是否可以使用操作员?并抛出新的异常()?

时间:2009-11-19 11:50:37

标签: c# .net nullable null-coalescing-operator

我接下来有很多方法:

var result = command.ExecuteScalar() as Int32?;
if(result.HasValue)
{
   return result.Value;
}
else
{
   throw new Exception(); // just an example, in my code I throw my own exception
}

我希望我可以像这样使用运算符??

return command.ExecuteScalar() as Int32? ?? throw new Exception();

但它会产生编译错误。

是否可以重写我的代码,或者只有一种方法可以做到这一点?

5 个答案:

答案 0 :(得分:54)

对于C#7

在C#7中,throw成为表达式,因此可以完全使用问题中描述的代码。

对于C#6及更早版本

你不能在C#6及更早版本中直接直接 - 第二个操作数?需要是一个表达式,而不是一个抛出语句。

如果您真的只是想找到一个简洁的选项,那么有一些选择:

你可以写:

public static T ThrowException<T>()
{
    throw new Exception(); // Could pass this in
}

然后:

return command.ExecuteScalar() as int? ?? ThrowException<int?>();

真的不建议你这样做但是......这是非常可怕和单一的。

扩展方法怎么样:

public static T ThrowIfNull(this T value)
{
    if (value == null)
    {
        throw new Exception(); // Use a better exception of course
    }
    return value;
}

然后:

return (command.ExecuteScalar() as int?).ThrowIfNull();

另一种替代方案(同样是一种扩展方法):

public static T? CastOrThrow<T>(this object x) 
    where T : struct
{
    T? ret = x as T?;
    if (ret == null)
    {
        throw new Exception(); // Again, get a better exception
    }
    return ret;
}

致电:

return command.ExecuteScalar().CastOrThrow<int>();

这有点难看,因为你不能指定int?作为类型参数......

答案 1 :(得分:9)

如前所述,你不能用??操作员(好吧,不是没有一些看起来不符合你的目标的扭曲)。

当我看到这种模式出现时,我立即想到Enforcements。最初来自C ++世界,他们很好地转移到C#,虽然大多数时候可以说不那么重要。

这个想法是你采取的形式:

if( condition )
{
  throw Exception;
}

并将其转换为:

Enforce<Exception>( condition );

(您可以通过默认异常类型进一步简化)。

更进一步,您可以为不同的条件检查编写一组Nunit风格的方法,例如;

Enforce<Exception>.NotNull( obj );
Enforce<Exception>.Equal( actual, expected );
Enforce<Exception>.NotEqual( actual, expected );

或者,更好地通过提供期望lamba:

Enforce<Exception>( actual, expectation );

真正干净的是,一旦你完成了,你就可以返回实际的参数并强制执行内联

return Enforce( command.ExecuteScalar() as Int32?, (o) => o.HasValue ).Value;

......这似乎与你所追求的最接近。

我之前已经完成了这个实现。有一些小问题,比如你通常如何创建一个带参数的异常对象 - 那里有一些选择(我当时选择了反射,但是将工厂作为额外参数传递可能会更好)。但总的来说,这一切都非常简单,可以真正清理很多代码。

这是我要做的事情列表,可以用来打开开源实现。

答案 2 :(得分:4)

如果您只想在返回值不是Int32时发生异常,请执行以下操作:

return (int)command.ExecuteScalar();

如果你想抛出自己的自定义异常,那么我可能会做这样的事情:

int? result = command.ExecuteScalar() as int?;
if (result == null) throw new YourCustomException();
return result.Value;

答案 3 :(得分:2)

您无法在空合并运算符的右侧抛出异常。这背后的原因是运算符的右侧需要是表达式,而不是声明。

null合并运算符的工作原理如下:如果运算符的左值为null,则返回它;否则,返回操作员右侧的内容。 throw关键字不会返回值;因此,它不能在操作员的右侧使用。

答案 4 :(得分:1)

你无法做到的原因:

return command.ExecuteScalar() as Int32? ?? throw new Exception();

是因为抛出异常是一种陈述,而不是一种表达。

如果您只是想缩短代码,可能就是这样:

var result = command.ExecuteScalar() as Int32?;
if(result.HasValue) return result;
throw new Exception();

不需要别人。