Generics used in struct vs class

27,789

Solution 1

That is because a compiler rule enforces that all fields in a struct must be assigned before control leaves any constructor.

You can get your code working by doing this:

public Foo(T first)
{
    this.First = first;
    this.Second = default(T);
}

Also see Why Must I Initialize All Fields in my C# struct with a Non-Default Constructor?

Solution 2

That's a requirement of structs in general -- it has nothing to do with generics. Your constructor must assign a value to all fields.

Note the same error happens here:

struct Foo
{
    public int A;
    public int B;

    public Foo()
    {
        A = 1;
    }
}

Solution 3

Because it is a rule in C# that all fields must be assigned for structs (inline or in constructor). This is because of a struct nature. It has nothing about generic it or not generic.

Share:
27,789
Sleiman Jneidi
Author by

Sleiman Jneidi

I am lexically scoped. #SOreadytoHelp Read More, Recursively!!

Updated on November 21, 2021

Comments

  • Sleiman Jneidi
    Sleiman Jneidi over 2 years

    Assume that we have the following struct definition that uses generics:

    public struct Foo<T>
    {
        public T First; 
        public T Second;
    
        public Foo(T first)
        {
            this.First = first;
        }
    
    }
    

    The compiler says

    'Foo.Second' must be fully assigned before control is returned to the caller

    However, if Foo is a class, then it compiles successfully.

    public class Foo<T>
    {
        public T First; 
        public T Second;
    
        public Foo(T first)
        {
            this.First = first;
        }
    
    }
    

    Why? Why the compiler treats them differently? Moreover if no constructor is defined in the first Foo then it compiles. Why this behaviour?

  • Buh Buh
    Buh Buh over 11 years
    That's not right. In classes all fields are initialized to their default values, regardless of what you do. If you set a field to null then you are setting it twice.
  • Jeff
    Jeff over 11 years
    @BuhBuh Oh, right you are. Getting my languages mixed up terribly :(
  • supercat
    supercat over 11 years
    It's interesting to note that the C# rule is essentially unenforceable, since .net doesn't have real "out" parameters. C# may expect that any parameter with an Out() attribute will be written, but nothing in the CLS spec justifies any such assumption when calling external functions. If a virtual method with an out parameter is overridden in a language which doesn't know about the Out() attribute, that language will regard the parameter as a ref parameter which the override method may write or not as it sees fit. It's worth noting that var it = new StructType(params); does not...
  • supercat
    supercat over 11 years
    ...always get performed by creating a temp instance and then copying to it; the compiler may simply have the constructor mutate the fields of the existing it instance directly. It may assume that all fields will be written before being read, but in reality there's no guarantee that any of them will be written.
  • driis
    driis about 10 years
    @BillW why is that ? It succinctly show the OP what he could do to get his sample to compile.
  • ToolmakerSteve
    ToolmakerSteve over 2 years
    BTW: This would be an answer to the second part if the second part had been asking about a class. OP actually asked why a struct ("the first foo") is valid without any constructor definition. The correct answer for a struct is "a struct always has an implicit parameterless constructor." In c#, there is no way to "disallow" new MyStruct(). That always is valid. In fact, for a struct, you can't even declare your own parameterless constructor, to override the default behavior!
  • Jeff
    Jeff over 2 years
    @ToolmakerSteve thanks! I've updated the answer - if you get a moment it'd be great to get your eyes across to make sure I haven't loaded in any more misinformation - it's been a few years since I was an active coder!