Roslyn: Warning when there is a struct constructor with default parameters

Created on 28 Aug 2019  路  4Comments  路  Source: dotnet/roslyn

The following code compiles without any warnings or errors. The compiler correctly generates IL and uses initobj to initialize a struct, but there is a constructor with a default parameter. So it seems like it should be invoked:

public class Program {
    public static void Main() => new TestStruct().Value.ToString();
}

public struct TestStruct
{
    public TestStruct(string value = "default") => Value = value;
    public string Value { get; }
}
    .method public hidebysig static 
        void Main () cil managed 
    {
        // Method begins at RVA 0x2050
        // Code size 21 (0x15)
        .maxstack 2
        .locals init (
            [0] valuetype TestStruct
        )

        IL_0000: ldloca.s 0
        IL_0002: dup
        IL_0003: initobj TestStruct
        IL_0009: call instance string TestStruct::get_Value()
        IL_000e: callvirt instance string [mscorlib]System.Object::ToString()
        IL_0013: pop
        IL_0014: ret
    } // end of method Program::Main

If the type is changed to be a class, then the constructor with the default parameter is invoked:

public class TestStruct
{
    public TestStruct(string value = "default") => Value = value;
    public string Value { get; }
}
    .method public hidebysig static 
        void Main () cil managed 
    {
        // Method begins at RVA 0x2050
        // Code size 22 (0x16)
        .maxstack 8

        IL_0000: ldstr "default"
        IL_0005: newobj instance void TestStruct::.ctor(string)
        IL_000a: call instance string TestStruct::get_Value()
        IL_000f: callvirt instance string [mscorlib]System.Object::ToString()
        IL_0014: pop
        IL_0015: ret
    } // end of method Program::Main

Makes sense to generate a warning or even an error to remove inconsistency between class and structure instantiations.

Area-Compilers untriaged

Most helpful comment

The struct has two constructors:

public struct TestStruct
{
    public TestStruct() { } // this one defined by the compiler (or runtime)
    public TestStruct(string value = "default") => Value = value;
    public string Value { get; }
}

A class with the same two constructors will be constructed in the same way as the structure.

All 4 comments

See also dotnet/csharplang#146.

The struct has two constructors:

public struct TestStruct
{
    public TestStruct() { } // this one defined by the compiler (or runtime)
    public TestStruct(string value = "default") => Value = value;
    public string Value { get; }
}

A class with the same two constructors will be constructed in the same way as the structure.

I suppose it might make sense to raise a warning if:

  1. There is an (explicit or implicit) parameteress constructor, and
  2. There's another constructor, which has a single parameter, which has a default value

In this case, I think the default value is pointless and might indicate user error.

I suppose the same could be said about two method overloads: if there's a parameterless method, and another method which takes a single parameter with a default value, that default value is pointless as Method() will always invoke the parameterless method. I suppose you might want to be careful if that method is part of an interface implementation though.

Closing as the compiler is operating as the language design intends here and that this seems like an unlikely candidate for a warning wave.

Was this page helpful?
0 / 5 - 0 ratings