可以使用接线员吗?和抛出新的异常()?

时间:2022-09-24 20:35:33

I have a number of methods doing next:

接下来我有一些方法:

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
}

I wish I could use operator ?? like this:

我希望我能使用接线员?是这样的:

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

but it generates a compilation error.

但它会产生编译错误。

Is it possible to rewrite my code or there is only one way to do that?

有没有可能重写我的代码,或者只有一种方法?

5 个解决方案

#1


48  

For C# 7

对于C # 7

In C# 7, throw becomes an expression, so it's fine to use exactly the code described in the question.

在c# 7中,throw变成了一个表达式,因此可以使用问题中描述的代码。

For C# 6 and earlier

对于c# 6和更早的

You can't do that directly in C# 6 and earlier - the second operand of ?? needs to be an expression, not a throw statement.

您不能在c# 6和更早的时候直接这样做——第二个操作数?需要是一个表达式,而不是一个抛出语句。

There are a few alternatives if you're really just trying to find an option which is concise:

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

You could write:

你可以写:

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

And then:

然后:

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

I really don't recommend that you do that though... it's pretty horrible and unidiomatic.

我真的不建议你这么做……这是非常可怕的,单变量的。

How about an extension method:

扩展方法呢?

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

Then:

然后:

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

Yet another alternative (again an extension method):

另一种选择(同样是扩展方法):

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;
}

Call with:

电话:

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

It's somewhat ugly because you can't specify int? as the type argument...

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

#2


9  

As has been said, you can't do this with the ?? operator (well, not without some contortions that don't seem to fit with your aim of making this cleaner).

如前所述,你不能用?操作人员(嗯,不是没有一些扭曲,似乎不符合你的目标,使这个更干净)。

When I see this pattern emerging I immediately think of Enforcements. Originally from the C++ world they transfer to C# pretty well, although are arguably less important most of the time.

当我看到这种模式出现时,我立刻想到了强制执行。它们最初是从c++世界移植到c#的,非常好,尽管在大多数情况下可能不那么重要。

The idea is that you take something of the form:

这个想法是你取一些形式

if( condition )
{
  throw Exception;
}

and converts it to:

并将其转换为:

Enforce<Exception>( condition );

(you can further simplify by defaulting the exception type).

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

Taking it further you can write a set of Nunit-style methods for different condition checks, e.g.;

进一步说,您可以为不同的条件检查编写一组nunit样式的方法,例如;

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

etc.

等。

Or, better still by providing an expectation lamba:

或者,更好的方法是提供一个期望lamba:

Enforce<Exception>( actual, expectation );

What's really neat is that, once you've done that, you can return the the actual param and enforce inline:

真正整洁的是,一旦你这样做了,你就可以返回实际的param并强制执行内联:

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

... and this seems to be the closest to what you're after.

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

I've knocked up an implementation of this before. There's a couple of little niggles, like how you generically create an exception object that takes arguments - some choices there (I chose reflection at the time, but passing a factory in as an extra parameter may be even better). But in general it's all pretty straightforward and can really clean up a lot of code.

我之前已经把这个实现了。这里有几个小细节,比如如何创建一个接受参数的异常对象——这里有一些选择(当时我选择了反射,但将工厂作为一个额外的参数传入可能更好)。但总的来说,它非常简单,可以清理很多代码。

It's on my list of things to do to knock up an open source implementation.

在我的清单上列出了创建开放源码实现要做的事情。

#3


4  

If you just want an exception when the returned value isn't an Int32 then do this:

如果您只是想在返回值不是Int32时发生异常,那么就这样做:

return (int)command.ExecuteScalar();

If you want to throw your own custom exception then I'd probably do something like this instead:

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

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

#4


2  

You're not going to be able to throw an exception on the right side of the null coalescing operator. The reason behind this is that that the right side of the operator needs to be an expression, not a statement.

你不能在空合并运算符的右边抛出一个异常。这背后的原因是运算符的右边需要是表达式,而不是语句。

The null coalescing operator works like so: if the left value of the operator is null, return it; otherwise, return what's on the right of the operator. The throw keyword doesn't return a value; hence, it can't be used on the right side of the operator.

null合并运算符的工作方式如下:如果运算符的左值为null,返回;否则,返回运算符右边的内容。抛出关键字不返回值;因此,它不能用于操作符的右边。

#5


1  

The reason you can't do:

你做不到的原因:

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

Is because throwing an exception is a statement, not an expression.

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

If you're just looking to shorten the code a little bit, perhaps this:

如果你只是想把代码缩短一点,也许是这样:

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

No need for the else.

不需要其他的。

#1


48  

For C# 7

对于C # 7

In C# 7, throw becomes an expression, so it's fine to use exactly the code described in the question.

在c# 7中,throw变成了一个表达式,因此可以使用问题中描述的代码。

For C# 6 and earlier

对于c# 6和更早的

You can't do that directly in C# 6 and earlier - the second operand of ?? needs to be an expression, not a throw statement.

您不能在c# 6和更早的时候直接这样做——第二个操作数?需要是一个表达式,而不是一个抛出语句。

There are a few alternatives if you're really just trying to find an option which is concise:

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

You could write:

你可以写:

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

And then:

然后:

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

I really don't recommend that you do that though... it's pretty horrible and unidiomatic.

我真的不建议你这么做……这是非常可怕的,单变量的。

How about an extension method:

扩展方法呢?

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

Then:

然后:

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

Yet another alternative (again an extension method):

另一种选择(同样是扩展方法):

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;
}

Call with:

电话:

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

It's somewhat ugly because you can't specify int? as the type argument...

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

#2


9  

As has been said, you can't do this with the ?? operator (well, not without some contortions that don't seem to fit with your aim of making this cleaner).

如前所述,你不能用?操作人员(嗯,不是没有一些扭曲,似乎不符合你的目标,使这个更干净)。

When I see this pattern emerging I immediately think of Enforcements. Originally from the C++ world they transfer to C# pretty well, although are arguably less important most of the time.

当我看到这种模式出现时,我立刻想到了强制执行。它们最初是从c++世界移植到c#的,非常好,尽管在大多数情况下可能不那么重要。

The idea is that you take something of the form:

这个想法是你取一些形式

if( condition )
{
  throw Exception;
}

and converts it to:

并将其转换为:

Enforce<Exception>( condition );

(you can further simplify by defaulting the exception type).

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

Taking it further you can write a set of Nunit-style methods for different condition checks, e.g.;

进一步说,您可以为不同的条件检查编写一组nunit样式的方法,例如;

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

etc.

等。

Or, better still by providing an expectation lamba:

或者,更好的方法是提供一个期望lamba:

Enforce<Exception>( actual, expectation );

What's really neat is that, once you've done that, you can return the the actual param and enforce inline:

真正整洁的是,一旦你这样做了,你就可以返回实际的param并强制执行内联:

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

... and this seems to be the closest to what you're after.

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

I've knocked up an implementation of this before. There's a couple of little niggles, like how you generically create an exception object that takes arguments - some choices there (I chose reflection at the time, but passing a factory in as an extra parameter may be even better). But in general it's all pretty straightforward and can really clean up a lot of code.

我之前已经把这个实现了。这里有几个小细节,比如如何创建一个接受参数的异常对象——这里有一些选择(当时我选择了反射,但将工厂作为一个额外的参数传入可能更好)。但总的来说,它非常简单,可以清理很多代码。

It's on my list of things to do to knock up an open source implementation.

在我的清单上列出了创建开放源码实现要做的事情。

#3


4  

If you just want an exception when the returned value isn't an Int32 then do this:

如果您只是想在返回值不是Int32时发生异常,那么就这样做:

return (int)command.ExecuteScalar();

If you want to throw your own custom exception then I'd probably do something like this instead:

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

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

#4


2  

You're not going to be able to throw an exception on the right side of the null coalescing operator. The reason behind this is that that the right side of the operator needs to be an expression, not a statement.

你不能在空合并运算符的右边抛出一个异常。这背后的原因是运算符的右边需要是表达式,而不是语句。

The null coalescing operator works like so: if the left value of the operator is null, return it; otherwise, return what's on the right of the operator. The throw keyword doesn't return a value; hence, it can't be used on the right side of the operator.

null合并运算符的工作方式如下:如果运算符的左值为null,返回;否则,返回运算符右边的内容。抛出关键字不返回值;因此,它不能用于操作符的右边。

#5


1  

The reason you can't do:

你做不到的原因:

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

Is because throwing an exception is a statement, not an expression.

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

If you're just looking to shorten the code a little bit, perhaps this:

如果你只是想把代码缩短一点,也许是这样:

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

No need for the else.

不需要其他的。