112

Here is a struct I am trying to write:

 public struct AttackTraits { public AttackTraits(double probability, int damage, float distance) { Probability = probability; Distance = distance; Damage = damage; } private double probability; public double Probability { get { return probability; } set { if (value > 1 || value < 0) { throw new ArgumentOutOfRangeException("Probability values must be in the range [0, 1]"); } probability = value; } } public int Damage { get; set; } public float Distance { get; set; } } 

This results in the following compilation errors:

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

Field 'AttackTraits.probability' must be fully assigned before control is returned to the caller

Backing field for automatically implemented property 'AttackTraits.Damage' must be fully assigned before control is returned to the caller. Consider calling the default constructor from a constructor initializer.

Backing field for automatically implemented property 'AttackTraits.Distance' must be fully assigned before control is returned to the caller. Consider calling the default constructor from a constructor initializer.

What am I doing wrong?

5 Answers 5

318

If you see this error on a struct that has an automatic property, just call the parameterless contructor from your parameterized one by doing : this() example below:

struct MyStruct { public int SomeProp { get; set; } public MyStruct(int someVal) : this() { this.SomeProp = someVal; } } 

By calling :this() from your constructor declaration you let the base ValueType class initialize all the backing fields for the automatic properties. We cannot do it manually on our constructor because we don't have access to the backing field of an automatic property. ValueType is the base class of all structs.

Sign up to request clarification or add additional context in comments.

12 Comments

@ChrisAmelinckx just where do you find all those stuff it looks like some kind of someones imagination though only it works for real (:
This worked, but I don't understand why. Can anyone explain? Why must the parameterless constructor be called first? I'm missing something...
@DarrenHale when the first line of the constructor is going to execute, for structs it is required that all fields be initialized already. SomeProp being an automatic property is equivalent to having an explicit 'someProp' field and the get/set methods. By calling the base parameterless : this() constructor you guarantee that before the first line of “your logic” in the constructor, all fields have been initialized.
Well its cool that we have a solution, but why on earth is this workaround needed?
@Peter, you raise a good point in that this seems like a workaround. My opinion is that this is not a workaround but a complete solution to the issue. Structs are meant to be lightweight representations of application state that get copied over the executing stack. (Every time a value type instance (a struct) is passed into a method a new copy of it is made within the context of that method, as opposed to passing a reference for a class defined object type).
|
51

try to access probability field not accessor. In this case auto-props should work as well.

There is no way for a struct to have parameterless constructor so consider change it to class instead.

Best practise is to use structs only if they are 16 bytes or less and are immutable. So if you are going to change object fields after creating, consider refactoring it to class.

Also, you can change constructor definition to:

construct(params) : this() 

this will remove error as well

8 Comments

Just FYI, your answer works, but some of your justification is incorrect. In fact, structs ALWAYS have a parameterless constructors. Unlike classes, a struct's parameterless constructor cannot be hidden by creating a constructor with parameters.
Not to belabor this point unnecessarily, but not only is it perfectly legal to call that constructor, but it'll pop up in intellisense like any other constructor. Can you provide a case where that's not true?
@joshua.ewer, @vittore - you are always allowed to call that constructor, what you aren't allowed to do is to give your own implementation, but must always go with the default given to you (which assigns default(AppropriateType) to all instance fields).
@kashif you can calculate it from fields sizes it has.
|
35

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

3 Comments

Tried this. didn't work for me - but I am using auto properties
The problem with this solution. You don't have the validation benefits of the Probability property. And it doesn't fix everything because you also need to change Distance and Damage to non-anonymous properties otherwise it will not work. I prefer @Chris-Amelinckx s answer as a better solution.
struggled with this to make c#7 code backwards compatible: it pops up when you remove existing auto property initializers (for the same reason as in OP code). note that in this case, the actual answer is @thomas comment above (while you cannot have an explicit default constructor on a struct, you can call it in the constructor chain) > could you edit that into your answer, as comments may be removed?
2

Change the line Probability = probability to this.probability = probability

In the future pick a different naming convention for fields as you do for parameters. For example, prefix all fields with an underscore, so you can simply call this:

_probability = probability; 

and see easily what's happening.

1 Comment

Yes, there simply is an ugly name conflict between a parameter and a field.
-3

try to change struct to class for AttackTraits

public class AttackTraits { ......... { 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.