Unintuitive behaviour with struct initialization and default arguments

后端 未结 5 2309
小鲜肉
小鲜肉 2021-02-12 17:52
public struct Test 
{
    public double Val;
    public Test(double val = double.NaN) { Val = val; }
    public bool IsValid { get { return !double.IsNaN(Val); } }
}

Te         


        
5条回答
  •  自闭症患者
    2021-02-12 18:43

    In C# (at least until C# 6 - see blog post), invoking new Test() is equivalent to writing default(Test) - no constructor is actually called, the default value is provided.

    The default arg serves no purpose, what happens is that it is likely the result of an oversight in the implementation of the compiler, due to the fact that optional arguments were only added in C# 4:

    • The code that checks that optional arguments do not conflict with already existing overloads is unaware of a possible conflict with the initializer in the case of structs;
    • The code that translates what new Test() means is probably unaware of the existence of optional arguments;

      • After digging into comments, I noticed the following gem by Mads Torgersen:

        It is true that the compiler implementation has so far "optimized" 'new T()' to mean essentially default(T) when T is a struct. That was actually a bug - it was always supposed to call an actual parameterless constructor if there is one - which there could have been all along, since it is allowed in IL.

        For your example, it means that new Test() is effectively replaced by the compiler to default(Test) - so that is a bug, which will be fixed in the next version of Visual Studio.

    In other words, you have a corner case. That would probably be a good time to look at how that behaves in the next version of Visual Studio, as that behavior is changing.

提交回复
热议问题