使用表达式成员允许您将方法或属性的主体定义为没有return关键字的单个表达式(如果它返回了某些内容).
例如,它变成了这些
int Method1()
{
return 5;
}
void Method2()
{
Console.WriteLine();
}
Run Code Online (Sandbox Code Playgroud)
进入这些
int Method1() => 5;
void Method2() => Console.WriteLine();
Run Code Online (Sandbox Code Playgroud)
当您从正文中抛出异常时,会产生差异:
void Method3()
{
throw new Exception();
}
Run Code Online (Sandbox Code Playgroud)
但是,以下内容将无法编译:
void Method3() => throw new Exception();
Run Code Online (Sandbox Code Playgroud)
以下消息:
Warning The member 'Program.Exception()' does not hide an inherited member. The new keyword is not required.
Error 'Program.Exception()' must declare a body because it is not marked abstract, extern, or partial
Error ; expected
Error Invalid token 'throw' in class, struct, or interface member declaration
Error Method must have a return type
Error Invalid expression term 'throw'
Run Code Online (Sandbox Code Playgroud)
为什么?
Jer*_*vel 35
发生这种情况是因为前两个代码片段(5和Console.WriteLine)是表达式.更具体地说,这些分别是NumericLiteralExpression和InvocationExpression.
后一个(throw new Exception())是一个声明 - 在这种情况下:ThrowStatement.
如果您查看Roslyn SDK,您会注意到一个MethodDeclarationSyntax对象具有ExpressionBody类型的属性,ArrowExpressionClauseSyntax而该属性又具有类型的属性ExpressionSyntax.这应该很明显只有表达式身份成员才接受表达式.
如果你查看最后一个代码示例,你会注意到它由ThrowStatementSyntax一个ExpressionSyntax属性组成.在我们的例子中,我们用一个ObjectCreationExpressionSyntax对象填充它.
我只能在这里猜测,但我认为这是因为这会打开太多的副作用,只是为了能够抛出异常.我不相信表达式和语句在继承中有共同的祖先,所以会有很多代码重复.最后,我认为它归结为简直不值得麻烦,即使它在某种程度上是有道理的.
当你将一个简单的表达式写成一个方法体的一部分时,它实际上被包装在ExpressionStatementSyntax- 是的,两者结合在一起!这允许它与Body方法属性下的其他语句组合在一起.在引擎盖下,他们必须展开它并从中提取表达式.这反过来可以用于表达式身体成员,因为此时你只剩下一个表达式而不再是一个语句.
然而,一个重要的注意事项是,return语句是一个声明.更具体地说ReturnStatementSyntax.他们必须已经明确地处理了这个并且应用了编译器魔术,虽然这确实提出了一个问题:为什么不这样做ThrowStatementSyntax呢?
请考虑以下情形:突然,throw也接受语句.但是,由于表达式身体成员只能将表达式作为其主体(duh),这意味着您必须省略throw关键字而不是留下new Exception().您如何区分意图return声明和throw声明?
这两种方法的表达体变异之间没有区别:
public Exception MyMethod()
{
return new Exception();
}
public Exception MyMethod()
{
throw new Exception();
}
Run Code Online (Sandbox Code Playgroud)
a throw和a return语句都是有效的方法结束.但是当你省略它们时,没有什么可以区分两者 - ergo:你永远不会知道是返回还是抛出新创建的异常对象.
一个表达体的成员正如名字所说的那样:一个在其体内只有一个表达式的成员.这意味着您必须了解表达式的确切构成.仅仅因为它是一个"陈述"并不能使它成为一种表达.
Cur*_*ore 15
此功能将在C#7中出现.来自https://blogs.msdn.microsoft.com/dotnet/2016/08/24/whats-new-in-csharp-7-0/
在表达式中间抛出异常很容易:只需调用一个为您执行此操作的方法!但在C#7.0中,我们直接允许
throw在某些地方作为表达式:
class Person
{
public string Name { get; }
public Person(string name) => Name = name ?? throw new ArgumentNullException(name);
public string GetFirstName()
{
var parts = Name.Split(" ");
return (parts.Length > 0) ? parts[0] : throw new InvalidOperationException("No name!");
}
public string GetLastName() => throw new NotImplementedException();
}
Run Code Online (Sandbox Code Playgroud)
编辑:
更新此问题以添加指向更新信息的链接,throw现在可以将其用作表达式 - 身体成员,三元表达式和空合并表达式中的表达式,现在C#7已发布: