33

接下来我有很多方法:

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();

但它会产生编译错误。

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

4

5 回答 5

62

对于 C# 7

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

对于 C# 6 及更早版本

您不能直接在 C# 6 及更早版本中执行此操作 - ?? 的第二个操作数 必须是表达式,而不是 throw 语句。

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

你可以写:

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?为类型参数...

于 2009-11-19T11:54:02.810 回答
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 );

真正巧妙的是,一旦你这样做了,你就可以返回实际的参数并强制执行inline

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

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

我以前敲过这个的实现。有几个小问题,比如你如何一般地创建一个接受参数的异常对象——那里有一些选择(我当时选择了反射,但将工厂作为额外参数传入可能会更好)。但总的来说,这一切都非常简单,并且可以真正清理大量代码。

在我的清单上,要完成一个开源实现。

于 2009-11-19T12:35:31.053 回答
4

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

return (int)command.ExecuteScalar();

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

int? result = command.ExecuteScalar() as int?;
if (result == null) throw new YourCustomException();
return result.Value;
于 2009-11-19T11:54:05.460 回答
2

您将无法在 null 合并运算符的右侧引发异常。这背后的原因是运算符的右侧需要是表达式,而不是语句。

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

于 2009-11-19T11:54:19.253 回答
1

你做不到的原因:

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

是因为抛出异常是一个语句,而不是一个表达式。

如果您只是想稍微缩短代码,也许是这样:

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

不需要其他的。

于 2009-11-19T11:56:08.123 回答