24
votes

I have a next code:

struct T 
{
    public T(int u) 
    { 
        this.U = 10; //Errors are here
    }

    public int U { get; private set;  }
}

C# compiler give me a pair of errors in stated line: 1) Backing field for automatically implemented property 'TestConsoleApp.Program.T.U' must be fully assigned before control is returned to the caller. Consider calling the default constructor from a constructor initializer. 2) The 'this' object cannot be used before all of its fields are assigned to

What I do wrong? Help me understand.

5

5 Answers

76
votes

From the C# Specification:

10.7.3 Automatically implemented properties

When a property is specified as an automatically implemented property, a hidden backing field is automatically available for the property, and the accessors are implemented to read from and write to that backing field.

[Deleted]

Because the backing field is inaccessible, it can be read and written only through the property accessors, even within the containing type.

[Deleted]

This restriction also means that definite assignment of struct types with auto-implemented properties can only be achieved using the standard constructor of the struct, since assigning to the property itself requires the struct to be definitely assigned. This means that user-defined constructors must call the default constructor.

So you need this:

struct T 
{
    public T(int u)
        : this()
    { 
        this.U = u;
    }

    public int U { get; private set; }
}
19
votes

Well, for a start you're creating a mutable struct - that's almost always a really bad idea. Mutable structs can sometimes behave in ways you don't expect. Okay, it's only privately mutable, but the fact that you've written code to mutate it is a bad sign.

The reason for the second error is that you can't use any properties or methods of the struct until all fields have been assigned, so you need to chain to the implicit parameterless constructor:

public T(int u) : this()
{ 
    this.U = 10;
}

The compiler requires that any constructor leaves all the fields definitely assigned (which is why you were getting the first error before; the compiler doesn't "know" that the property assigns the field a value) - by chaining to this(), you're making sure that by the time you get to your constructor body, all the fields are already definitely assigned, and you don't need to worry about it any more.

However, unless you actually want to allow mutation, I suggest you just make it a genuinely read-only property:

struct T 
{
    private readonly int u;

    public T(int u)
    { 
        this.u = 10;
    }

    public int U { get { return u; } }
}

Now it's more obvious that you don't want to mutate it even within the struct itself.

4
votes

Add a call to the default constructor:

public T(int u) : this() 
{
    this.U = 10;
}
2
votes

you have to use the default constructor here:

struct T
{
    public int U { get; private set; }

    public T(int u) : this()
    {
        U = 10;
    }


}
0
votes

From C# 6 this is not an issue anymore and it compiles correctly. Look here