Struct Constructor: "Fields Must Be Fully Assigned Before Control Is Returned to the Caller."

Struct constructor: fields must be fully assigned before control is returned to the caller.

You're setting the probability field through the Probability property, but the compiler doesn't know that the property sets the field... so you need to explicitly initialize the probability field itself

public AttackTraits(double probability, int damage, float distance)
{
this.probability = 0;
Distance = distance;
Damage = damage;
}

Automatically implemented property in struct can not be assigned

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; }
}

Constructor must be fully assigned

Your struct field entry_R is not getting initialized. In a struct, every member has to be initialized in the constructor. If you don't want this behavior, you might want to use a simple class.

 public struct S_Matrix
{
public int size_C, size_R;
public List<entries_R> entry_R;

public S_Matrix(int c, int r, List<entries_R> en)
{
this.size_C = c;
this.size_R = r;
this.entry_R = en;
// If you don't want a constructor parameter:
// this.entry_R = null;
// or:
// this.entry_R = new List<entries_R>();
}
}

In most cases, a class is what you want. Structs should only be used if one knows what one is doing.

 public class S_Matrix
{
public int size_C, size_R;
public List<entries_R> entry_R;

public S_Matrix(int c, int r)
{
this.size_C = c;
this.size_R = r;
// entry_R keeps being uninitialised
}
}

The 'this' object cannot be used before all of its fields are assigned to. Why do not class constructors have such restriction?

First of all, try not to make an analogy between Class and Struct in C#. They are quite different.

Let's say I got the following code:

 class MyClass
{
private int a = 0;
}
struct MyStruct
{
//private int a = 0; => this is not allowed
}
class Program
{
static void Main(string[] args)
{
var aCls=new MyClass();
var aStruct=new MyStruct();
}
}

When you check the il code,
class MyClass{...} generated the following code:

.class private auto ansi beforefieldinit
Ctors.MyClass
extends [mscorlib]System.Object
{

.field private int32 a

.method public hidebysig specialname rtspecialname instance void
.ctor() cil managed
{
.maxstack 8

// [11 9 - 11 27]
IL_0000: ldarg.0 // this
IL_0001: ldc.i4.0
IL_0002: stfld int32 Ctors.MyClass::a
IL_0007: ldarg.0 // this
IL_0008: call instance void [mscorlib]System.Object::.ctor()
IL_000d: nop
IL_000e: ret

} // end of method MyClass::.ctor
} // end of class Ctors.MyClass

struct MyStruct{} generated the following code:

.class private sealed sequential ansi beforefieldinit
Ctors.MyStruct
extends [mscorlib]System.ValueType
{
} // end of class Ctors.MyStruct

Based on observatons above:

1. MyClass genenerated a parameterless constructor.

2. The a=0 assignment will be put in the parameterless constructor.

3. There is no auto generated parameterless constructor for MyStruct
4. The a=0 assignment can not be directly put in MyStruct. It won't compile.

Let's see what will happen when we new them:

    IL_0001: newobj       instance void Ctors.MyClass::.ctor()
IL_0006: stloc.0 // aCls

// [22 13 - 22 40]
IL_0007: ldloca.s aStruct
IL_0009: initobj Ctors.MyStruct

The MyClass will be ctored by newobj while the MyStruct will be ctored by initobj.

Why call this() solved? Actullay, it generated the following code:

    IL_0000: ldarg.0      // this
IL_0001: initobj Ctors.RequestLog

I think we should not consider it parameterless constructor. It works very different from what you would expect a parameterless constructor do. It is just syntax sugar to clear state for value type.

Why should I to explicitly initialize all fields for struct? Simply Safety.
More details can be found in the following quote:

Note Strictly speaking, value type fields are guaranteed to be 0/null when the value type
is a field nested within a reference type. However, stack-based value type fields are not
guaranteed to be 0/null . For verifiability, any stack-based value type field must be written
to prior to being read. If code could read a value type’s field prior to writing to the field,
a security breach is possible. C# and other compilers that produce verifiable code ensure
that all stack-based value types have their fields zeroed out or at least written to before
being read so that a verification exception won’t be thrown at run time. For the most part,
this means that you can assume that your value types have their fields initialized to 0 , and
you can completely ignore everything in this note.

by Jeffrey Richter CLR via C#.

Unable to compile a struct

With structs you have to call the default constructor in all other constructors:

public LimitfailureRecord(string sampleCode) : this()
{
SampleCode = sampleCode;
}

The 'this' object cannot be used before all of its fields are assigned to

It doesn't, the compiler is just stopping after the first error. If you comment out Day = day you'll see the same error on Month = month.

(Tested with dotnetfiddle/.NET 4.7.2, I suppose other compilers may be different.)

Explicit struct in C# requires double init of value

Look into below Microsoft link:

https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/compiler-messages/cs0843

It says,

To assign a value to an automatically-implemented property from a
constructor, you must first invoke the default constructor to create
the object.

Doing below change will resolve your issue. call default constructor.

 public Color(byte r, byte g, byte b, byte a = 0xff):this()
{
A = a;
R = r;
G = g;
B = b;
}

Compilation error. Using properties with struct

As the error message recommends, you can resolve this by calling the default constructor from a constructor initializer.

public DealImportRequest(DealRequestBase drb) : this()
{
DealReq = drb;
ImportRetryCounter = 0;
}

From the language 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. [...] Because the
backing field is inaccessible, it can
be read and written only through the
property accessors, even within the
containing type. [...] 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.

The other (more verbose) alternative, of course, is to manually implement the properties and set the backing fields yourself in the constructor.

Do note that the struct you have there is mutable. This is not recommended. I suggest you either make the type a class (your compilation problems should go away immediately) or make the type immutable. The easiest way to accomplish this, assuming the code you have presented is the entire struct, would be to make the setters private (get; private set;). Of course, you should also make sure that you don't add any mutating methods to the struct afterwards that rely on private access to modify the fields. Alternatively, you could back the properties with readonly backing fields and get rid of the setters altogether.



Related Topics



Leave a reply



Submit