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

aba*_*hev 28 .net c# 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
}
Run Code Online (Sandbox Code Playgroud)

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

return command.ExecuteScalar() as Int32? ?? throw new Exception();
Run Code Online (Sandbox Code Playgroud)

但它会生成编译错误.

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

Jon*_*eet 54

对于C#7

在C#7中,throw变成一个表达式,所以可以正确使用问题中描述的代码.

对于C#6及更早版本

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

如果你真的只想找到一个简洁的选项,有几种选择:

你可以写:

public static T ThrowException<T>()
{
    throw new Exception(); // Could pass this in
}
Run Code Online (Sandbox Code Playgroud)

然后:

return command.ExecuteScalar() as int? ?? ThrowException<int?>();
Run Code Online (Sandbox Code Playgroud)

真的不建议你这样做但是......它非常可怕而且非常不合时宜.

扩展方法怎么样:

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

然后:

return (command.ExecuteScalar() as int?).ThrowIfNull();
Run Code Online (Sandbox Code Playgroud)

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

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;
}
Run Code Online (Sandbox Code Playgroud)

致电:

return command.ExecuteScalar().CastOrThrow<int>();
Run Code Online (Sandbox Code Playgroud)

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


phi*_*red 9

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

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

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

if( condition )
{
  throw Exception;
}
Run Code Online (Sandbox Code Playgroud)

并将其转换为:

Enforce<Exception>( condition );
Run Code Online (Sandbox Code Playgroud)

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

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

Enforce<Exception>.NotNull( obj );
Enforce<Exception>.Equal( actual, expected );
Enforce<Exception>.NotEqual( actual, expected );
Run Code Online (Sandbox Code Playgroud)

等等

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

Enforce<Exception>( actual, expectation );
Run Code Online (Sandbox Code Playgroud)

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

return Enforce( command.ExecuteScalar() as Int32?, (o) => o.HasValue ).Value;
Run Code Online (Sandbox Code Playgroud)

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

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

这是我要做的事情列表,以打开开源实现.