15

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?

bluish
  • 26,356
  • 27
  • 122
  • 180
Sleiman Jneidi
  • 22,907
  • 14
  • 56
  • 77
  • If you use a struct, you should really consider making it _immutable_. See [mutable structs are evil](http://stackoverflow.com/questions/441309/). One way of making it immutable is to say `public readonly T First; public readonly T Second;`. Then it is natural to assign all instance fields in your instance constructor. If, on the other hand, you really don't want to assign to all the fields, chain the (implicit and magical) parameterless constructor, of course, like: `: this()` (but I guess you know that). – Jeppe Stig Nielsen Dec 17 '12 at 15:41

4 Answers4

22

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?

Community
  • 1
  • 1
driis
  • 161,458
  • 45
  • 265
  • 341
  • 1
    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 Dec 06 '12 at 23:22
  • ...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. – supercat Dec 06 '12 at 23:24
  • 6
    @BillW why is that ? It succinctly show the OP what he could do to get his sample to compile. – driis Apr 06 '14 at 12:51
15

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;
    }
}
Jon B
  • 51,025
  • 31
  • 133
  • 161
2

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.

SergeyS
  • 3,515
  • 18
  • 27
0

The other answers explain the behaviour correctly, but neglect to mention the second part of your question, so here it is for completion.

For classes, when you don't explicitly define a constructor, the compiler will produce a default constructor which assigns default values (e.g. null for objects, 0 for numbers etc.) to every field.

For structs, the struct always has an implicit parameterless constructor that assigns default values.

ToolmakerSteve
  • 18,547
  • 14
  • 94
  • 196
Jeff
  • 12,555
  • 5
  • 33
  • 60
  • 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. – Buh Buh Dec 05 '12 at 20:37
  • @BuhBuh Oh, right you are. Getting my languages mixed up terribly :( – Jeff Dec 05 '12 at 20:40
  • 1
    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! – ToolmakerSteve Nov 21 '21 at 02:49
  • 1
    @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! – Jeff Nov 21 '21 at 02:57