注意:这似乎已在Roslyn中修复
写我的回答时,此问题出现了这一个,其中谈到了的关联性空合并运算符.
提醒一下,null-coalescing运算符的概念就是表单的表达式
x ?? y
Run Code Online (Sandbox Code Playgroud)
首先评估x,然后:
xnull,y则进行求值,这是表达式的最终结果x是非空,y则不评估,的值x是表达的最终结果,转换到编译时间类型的后y如果需要的话现在通常不需要转换,或者它只是从可空类型到非可空类型 - 通常类型相同,或者只是从(比如说)int?到int.但是,您可以创建自己的隐式转换运算符,并在必要时使用它们.
对于简单的情况x ?? y,我没有看到任何奇怪的行为.但是,(x ?? y) ?? z我看到一些令人困惑的行为.
这是一个简短但完整的测试程序 - 结果在评论中:
using System;
public struct A
{
public static implicit operator B(A input)
{
Console.WriteLine("A to B");
return new B();
}
public static implicit operator …Run Code Online (Sandbox Code Playgroud) null coalescing运算符是右关联的,表示表单的表达式
第一个?第二个 - 第三个
被评估为
第一个?(第二次 - 第三次)
基于上述规则,我认为以下翻译是不正确的.
从:
Address contact = user.ContactAddress;
if (contact == null)
{
contact = order.ShippingAddress;
if (contact == null)
{
contact = user.BillingAddress;
}
}
Run Code Online (Sandbox Code Playgroud)
至:
Address contact = user.ContactAddress ??
order.ShippingAddress ??
user.BillingAddress;
Run Code Online (Sandbox Code Playgroud)
相反,我认为以下是正确的(如果我错了请纠正我)
Address contact = (user.ContactAddress ?? order.ShippingAddress) ??
user.BillingAddress;
Run Code Online (Sandbox Code Playgroud) 我在下面展示的是一个理论问题.但我对新的C#7编译器如何工作并解析本地函数感兴趣.
在C#7中,我可以使用本地函数.例如(您可以在LinqPad beta中尝试这些示例):
示例1:嵌套Main()
void Main()
{
void Main()
{
Console.WriteLine("Hello!");
}
Main();
}
Run Code Online (Sandbox Code Playgroud)
而不Main()是以递归方式调用,本地函数Main()被调用一次,因此它的输出是:
你好!
编译器接受此操作时没有警告和错误.
示例2: 在这里,我更深入一级,如:
void Main()
{
void Main()
{
void MainL()
{
Console.WriteLine("Hello!");
}
MainL();
}
Main();
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下,我也期望相同的输出,因为最里面的本地函数被调用,然后一个级别,Main()只是另一个具有局部范围的本地函数,所以它应该与第一个示例没有太大的不同.
但令我惊讶的是,我收到了一个错误:
CS0136无法在此范围内声明名为"Main"的本地或参数,因为该名称用于封闭的本地范围以定义本地或参数
问题: 您能解释为什么在例2中发生此错误,但在示例1中没有?
我想,每个内部Main()都有一个局部范围,并隐藏在外面.
更新: 感谢所有到目前为止已经提出建议的人(无论是答案还是评论),你为了解C#编译器的行为而写的是非常值得的.
根据我的阅读,在考虑了可能性之后,我在你的帮助下发现它可能是编译器错误或设计行为.
回想一下,C#有一些设计目标,可以将它与C++等语言区分开来.
如果你对我所做的事情有兴趣进一步研究它:我已经将最里面的函数重命名为MainL:
例2b:
IL_0000: call UserQuery.<Main>g__Main0_0
IL_0005: ret
<Main>g__Main0_0:
IL_0000: call UserQuery.<Main>g__Main0_1
IL_0005: ret
<Main>g__Main0_1:
IL_0000: ldstr "Hello!"
IL_0005: call System.Console.WriteLine
IL_000A: …Run Code Online (Sandbox Code Playgroud) 在C#7中,你被允许这样做
if (int.TryParse("123", out int result))
Console.WriteLine($"Parsed: {result}");
Run Code Online (Sandbox Code Playgroud)
或者 - 如果您不使用结果并且只想检查解析是否成功,则丢弃out值:
if (int.TryParse("123", out _))
Console.WriteLine("Syntax OK");
Run Code Online (Sandbox Code Playgroud)
这通常很好,但在Visual Studio 2017中,out参数为空的第二个示例生成警告
警告AD0001:Analyzer'Microsoft.CodeAnalysis.CSharp.Diagnostics.SimplifyTypeNames.CSharpSimplifyTypeNamesDiagnosticAnalyzer'抛出了类型为'System.NullReferenceException'的异常,并显示消息'对象引用未设置为对象的实例.'.
我可以验证它发生的Visual Studio版本是
Visual Studio Enterprise 2017版本15.1(26403.7)发布
Visual Studio Enterprise 2017版本15.2(26430.4)发行版
这是一个错误,还是使用int.TryParse("123", out _)不正式支持?到目前为止我找不到任何暗示.
为了完整起见,这是显示问题的控制台应用程序的代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
if (int.TryParse("123", out _))
Console.WriteLine("Syntax OK");
}
}
}
Run Code Online (Sandbox Code Playgroud)