Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/256.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 为什么可以';我不能从表达式体成员抛出异常吗?_C#_Roslyn_C# 6.0 - Fatal编程技术网

C# 为什么可以';我不能从表达式体成员抛出异常吗?

C# 为什么可以';我不能从表达式体成员抛出异常吗?,c#,roslyn,c#-6.0,C#,Roslyn,C# 6.0,使用表达式体成员可以将方法体或属性体定义为不带返回关键字的单个表达式(如果它返回某些内容) 例如,它将这些 int Method1() { return 5; } void Method2() { Console.WriteLine(); } 进入这些 int Method1() => 5; void Method2() => Console.WriteLine(); 当您从主体中抛出异常时,会产生一种差异: void Method3() { thro

使用表达式体成员可以将方法体或属性体定义为不带返回关键字的单个表达式(如果它返回某些内容)

例如,它将这些

int Method1()
{
    return 5;
}

void Method2()
{
    Console.WriteLine();
}
进入这些

int Method1() => 5;

void Method2() => Console.WriteLine();
当您从主体中抛出异常时,会产生一种差异:

void Method3()
{
    throw new Exception();
}
但是,以下内容将不会编译:

void Method3() => throw new Exception();
发送以下信息:

警告成员“Program.Exception()”不会隐藏继承的成员。新关键字不是必需的。
错误“Program.Exception()”必须声明一个主体,因为它没有标记为抽象、外部或部分
错误;预期
错误:类、结构或接口成员声明中的无效标记“throw”
错误方法必须具有返回类型
错误无效的表达式项“throw”


为什么?

发生这种情况是因为前两个代码段(
5
Console.WriteLine
)是表达式。更具体地说,它们分别是
NumericLiteralExpression
InvocationExpression

后一个(
thrownewexception()
)是一条语句——在本例中是:
ThrowStatement

如果查看Roslyn SDK,您会注意到
MethodDeclarationSyntax
对象有一个
ExpressionBody
类型为
ArrowExpressionClauseSyntax
的属性,该属性又有一个
ExpressionSyntax
类型的属性。这应该清楚地表明,在一个表达式体成员中只接受表达式

如果查看上一个代码示例,您会注意到它由一个
ThrowStatementSyntax
组成,该语法又有一个
ExpressionSyntax
属性。在我们的例子中,我们用
对象creationexpressionsyntax
对象填充它


表达式和语句之间有什么区别?
  • [堆栈溢出]
  • [MSDN]
为什么它不接受声明呢? 我只能在这里猜测,但我会假设这是因为这会带来太多的副作用,只是为了能够抛出一个异常。我不相信一个表达式和一个语句在继承中有一个共同的祖先,所以会有很多代码重复。最后,我认为这归结为根本不值得成为麻烦,尽管这在某种程度上是有道理的

当您将一个简单表达式作为方法体的一部分编写时,它实际上被包装在一个
ExpressionStatementSyntax
下——是的,两者结合在一起!这允许它与方法的
Body
属性下的其他语句一起分组。在引擎盖下,他们必须展开此文件并从中提取表达式。这反过来可以用于表达式体成员,因为此时只剩下一个表达式,而不再是语句

然而,这里一个重要的注意事项是返回语句是。。一个声明。更具体地说是
ReturnStatementSyntax
。他们肯定已经明确地处理了这个问题,并应用了编译器的魔力,尽管这确实提出了一个问题:为什么不对
ThrowStatementSyntax
执行同样的操作呢

考虑以下场景:突然,
throw
语句也被接受。但是,由于表达式主体成员只能将表达式作为其主体(duh),这意味着您必须省略
throw
关键字,而保留
new Exception()
。如何区分打算使用的
return
语句和
throw
语句

这两种方法的表达体变异没有区别:

public Exception MyMethod()
{
    return new Exception();
}

public Exception MyMethod()
{
    throw new Exception();
}
throw
return
语句都是有效的方法结尾。然而,当您省略它们时,就没有什么区别了——因此:您永远不知道是返回还是抛出新创建的异常对象

我应该从中得到什么?
表达式主体成员与名称完全相同:在其主体中只有一个表达式的成员。这意味着您必须了解表达式的确切构成。仅仅因为它是一个“陈述”,并不意味着它是一个表达式。

不是关于为什么的答案,而是一个解决方法:

void Method3() => ThrowNotImplemented();

int Method4() => ThrowNotImplemented<int>();

private static void ThrowNotImplemented()
{
    throw new NotImplementedException();
}

private static T ThrowNotImplemented<T>()
{
    throw new NotImplementedException();
}
void Method3()=>ThrowNotImplemented();
int Method4()=>ThrowNotImplemented();
私有静态void ThrowNotImplemented()
{
抛出新的NotImplementedException();
}
私有静态T ThrowNotImplemented()
{
抛出新的NotImplementedException();
}

此功能将采用C#7。从

很容易在表达式的中间抛出一个异常:只需调用一个方法来完成它!但在C#7.0中,我们直接允许在某些地方将

throw
作为表达式:


编辑:

var firstName = name ?? throw new ArgumentException ();
public string GetPhoneNumber () => throw new NotImplementedException();
更新此问题以添加链接到更新的信息,这些信息涉及
throw
现在如何在表达式体成员、三元表达式和空合并表达式中用作表达式,现在C#7已经发布:


.

正如杰伦·瓦内维尔(Jeroen Vannevel)所解释的,我们只能对有表情的成员使用表情。 我不建议这样做,但您可以通过编写lambda表达式将(复杂的)代码转换为适当的类型并调用它,将其封装在表达式中

public void Method3() => ((Action)(() => { throw new Exception(); })).Invoke();
这样,您仍然可以在表达式体成员的一行中抛出异常

也许有充分的理由不这样做。
但我认为这是一个设计缺陷,即表达式体成员仅限于这样的表达式,并且可以像本例中那样进行处理。

虽然这是一个旧线程,但C#现在支持在C#7中添加的抛出表达式

以前,

var colorString = "green,red,blue".Split(',');
var colors = (colorString.Length > 0) ? colorString : null
if(colors == null){throw new Exception("There are no colors");}
没有了。现在,作为Null合并运算符:

var firstName = name ?? throw new ArgumentException ();
public string GetPhoneNumber () => throw new NotImplementedException();
As条件运算符:

var firstName = name ?? throw new ArgumentException ();
public string GetPhoneNumber () => throw new NotImplementedException();
在这种情况下也是可能的