结构初始化和默认参数的不直观行为

Ric*_*bob 18 .net c# struct default-constructor default-arguments

public struct Test 
{
    public double Val;
    public Test(double val = double.NaN) { Val = val; }
    public bool IsValid { get { return !double.IsNaN(Val); } }
}

Test myTest = new Test();
bool valid = myTest.IsValid;
Run Code Online (Sandbox Code Playgroud)

上面给出了valid==true因为没有调用默认arg的构造函数,并且使用标准默认值val = 0.0创建了对象.
如果结构是一个类,那么行为就是valid==false我所期望的.

我发现这种行为上的差异,特别是结构案例中的行为令人惊讶和不直观 - 发生了什么?stuct构造的默认arg服务是什么? 如果它无用为什么要让这个编译?

更新:澄清这里的重点不在于行为是什么 - 而是为什么在没有警告的情况下进行编译并且行为不直观.即如果没有应用默认的arg,因为在新的Test()情况下没有调用构造函数,那么为什么要让它编译?

Jea*_*nal 9

在C#中(至少在C#6之前 - 参见博客文章),调用new Test()等同于写入default(Test)- 实际上没有调用构造函数,提供了默认值.

默认的arg没有任何意义,发生的事情是它很可能是编译器实现中疏忽的结果,因为可选参数只在C#4中添加:

  • 检查可选参数与现有重载不冲突的代码不知道在结构化的情况下可能与初始化程序冲突;
  • 翻译new Test()含义的代码可能不知道可选参数的存在;

    • 在深入评论之后,我注意到Mads Torgersen的以下宝石:

      确实,当T是结构时,编译器实现到目前为止已经"优化"了"新T()"以表示基本上默认(T).这实际上是一个错误 - 它总是应该调用一个实际的无参数构造函数(如果有的话) - 它可能一直存在,因为它在IL中是允许的.

      对于您的示例,这意味着new Test()编译器有效地将其替换为default(Test)- 因此这是一个错误,将在下一版本的Visual Studio中修复.

换句话说,你有一个角落案例.这可能是查看下一版Visual Studio中的行为方式的好时机,因为这种行为正在发生变化.