Struct with auto-implemented properties and constructor initializer - c#

Recently a compiler warning and (very useful) hint prompted me to write the code below.
I had no idea you could do this, but it is perfectly legal, and also convenient in that I can declare a managed struct with public properties similar to public fields of an unmanaged struct, and also initialize it with an object instead of having to pass all the fields as parameters.
What confuses me is that this appears to call the explicit parameterless constructor, which would of course be illegal for this struct.
What's going on here, and has this syntax always been supported?
internal struct IconEntry
{
public byte Width { get; set; }
public byte Height { get; set; }
public byte ColorCount { get; set; }
public byte Reserved { get; set; }
public short Planes { get; set; }
public short BitCount { get; set; }
public int BytesInRes { get; set; }
public int ImageOffset { get; set; }
public IconEntry(BinaryReader reader)
: this()
{
Width = reader.ReadByte();
Height = reader.ReadByte();
ColorCount = reader.ReadByte();
Reserved = reader.ReadByte();
Planes = reader.ReadInt16();
BitCount = reader.ReadInt16();
BytesInRes = reader.ReadInt32();
ImageOffset = reader.ReadInt32();
}
}

A struct always has a public parameterless constructor which can't be overriden: http://msdn.microsoft.com/en-us/library/aa288208%28v=vs.71%29.aspx
This means that a user still would be able to create an instance of this struct that is not initialized according to your logic but with default values for all properties:
var s = new IconEntry();

All structs have a parameterless constructor - it's just implicit (e.g. it always exists with a default routine - one that sets all values to 0) - you just can't have an explicit one (e.g. one that you define yourself in code).

Is there any reason you're exposing properties rather than fields for your struct? If the semantics of your data type imply that
The entire state of an instance will be fully defined by the values exposed by some public members, such that two instances for whom all those report or contain identical values will be considered identical.
Instances of the struct with any combination of values for the aforementioned members may be created easily, given the desired values in question.
that sounds like a perfect fit for a PODS (Plain Old Data Struct). Exposed fields are more efficient and less quirky than struct properties. Given that all struct types always expose all fields for mutation or capture by struct assignment, the encapsulation offered by struct properties is of extremely limited value.
The way you have your constructor written, your struct will have all fields set to all-bits-zero, and then be passed repeatedly to methods which will update one field at a time with the desired value. The fact that the struct is specified as initialized to all-bits-zero by the this will make the compiler happy, but using many individual properties to set up fields piecemeal is inefficient.
Incidentally, even better than a constructor in many cases would be a static method which simply takes your struct as a ref parameter. In many cases, using a constructor with a struct will result in an unnecessary copy operation which could be avoided by using a static method with a ref parameter.

Since structs are value types, it's data members should be initialized if you are explicitly invoke the constructor. And mention "this()" to intimate compiler to complete the assignment of auto implemented properties if anything you mentioned.
struct Student
{
string _sname;
public int ID
{
get; set;
}
internal Student(string sname):this()
{
_sname = sname;
}
internal void PrintDetails()
{
Console.WriteLine("ID : {0} Name: {1}", ID, _sname);
}
}
Main method:
class Program
{
static void Main()
{
Student st = new Student("John")
{
ID=101
};
st.PrintDetails();
}
}
Output:
ID : 101 Name: John
If you are not mention "this()", compiler forcefully ask you to complete the full assignment of ID property.
If you are not explicitly invoke the constructor, compiler implicitly set default values for the struct data members.

Related

Why do I need to call the default constructor for `struct` with auto properties [duplicate]

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.
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; }
}
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.
Add a call to the default constructor:
public T(int u) : this()
{
this.U = 10;
}
you have to use the default constructor here:
struct T
{
public int U { get; private set; }
public T(int u) : this()
{
U = 10;
}
}
From C# 6 this is not an issue anymore and it compiles correctly. Look here

Why is my C# struct is being reset when passed into a method

I am creating a simple text-game. My Character struct keeps resetting it Can value. What am I doing wrong and how do I fix it? Here is the code:
namespace MyNamespace
{
struct Character
{
public float Can;
//...
}
class MainClass
{
public static void Move (Character a)
{
bool cal = true;
while (cal)
{
Thread.Sleep(500);
if(a.Can <= 100)
{
a.Can += 1;
}
else
{
cal = false;
}
}
}
}
//...
}
A struct is a value type. When you pass it to a method or assign it to another variable, data are copied. You will then operate on a copy.
Consider your method call Dinlen (oyuncu);. It copies the Karakter oyuncu, and then changes the field Can of the copy.
Consider using reference types (class) instead. If you use a struct, consider making it an immutable type. Read the thread Why are mutable structs evil?
If you want to pass a struct to a method for the purpose of having that method modify it, the method must use a ref qualifier on the parameter. If you pass a struct to a method without a ref parameter, there is no way that the method can modify any fields of that struct.
Note that some people may suggest replacing the struct with a class so that one won't have to use the ref qualifier. That is a dangerous notion, since every method receiving a reference to a mutable class object will be free to cause the object to be mutated at any time thereafter. There's no clean way to pass a reference to a mutable class object without allowing the recipient to mutate it, nor is there any way to be certain that code which is given a class-object reference won't persist it and use it to modify the object at any arbitrary future time. Structures don't have either of these problems.
If an object holds a value-type field e.g. MyBounds of type Drawing.Rectangle, and I call Foo(MyBounds) I can be assured that there is no possibility that Foo will change MyBounds. Further, if I call Bar(ref MyBounds) I can expect that Bar might change MyBounds, but all changes will be complete before the method returns. If Rectangle had been a mutable class type, then without examining Foo and Bar I would have no way of knowing whether the properties of MyBounds might be changed at any arbitrary time in the future.
Someone who doesn't understand that structs are different from classes may be confused by the way structs behave, but all structs with exposed public fields behave the same way, so if one understands how one such struct works, one will understand them all. There is one evil aspect of structures, which is that instance methods and properties defined on a struct will receive this as a ref parameter, but if one attempts to do something like:
readonly System.Drawing.Rectangle myRect = whatever;
...
myRect.Offset(4,2);
the system will recognize that myRect cannot be passed as a ref parameter (since it's read-only) and will, without any diagnostic, change the code to:
readonly System.Drawing.Rectangle myRect = whatever;
...
System.Drawing.Rectangle temp = myRect;
temp.Offset(4,2);
What is evil there, however, is not the fact that Rectangle is mutable, but rather the fact that the compiler assumes the above code substitution is legitimate when calling any and all value-type methods. Unless or until Microsoft gets around to adding an attribute to indicate that calling a particular method on a read-only structure should result in an error rather than performing such substitution, the only safe way to code struct methods that operate on a structure "in-place" would be to use a format like: static void Offset(ref Rectangle it, int x, int y);, in which case Rectangle.Offset(ref myRect, 4, 2); would fail as it should.
I believe the problem is you are passing the struct as a variable into your first method, but struct's are value types - i.e. they are copied, not passed by reference.
Changing your struct to class will have the behaviour you require.
P.S. Is there a reason you chose a struct? They are normally used for more advanced scenarios, where the developer knows more about the benefits and flaws of using this type.
When you are passing struct instance into method, a copy of struct is created (it is passed by value). Any changes to struct inside method does not affect original struct which you passed.
Solutions? Use class instead of struct. Instances of classes passed by reference. Well you can pass structs by reference, but why would you trying to use structs like classes? Use classes instead.
class Karakter
{
public string Isim { get; set; }
public float Can { get; set; }
public int Seviye { get; set; }
public int Exp { get; set; }
public float Guc { get; set; }
public string Irk { get; set; }
public int vExp { get; set; }
public override string ToString()
{
return String.Format("Adınız:{0}\nIrkınız:{1}\nCan:{2}\nGuc:{3}",
Isim, Irk, Can, Guc);
}
}
BTW I think it will be useful for you to read about Value and Reference Types in .NET
You might want to consider using a class instead of a struct.
As said, a struct is a value type and passed by copy. You can pass it by ref like this:
public static void Move (ref Character a)
{
...
}
and call it like this:
var a = new Character();
MainClass.Move(ref a);

Automatically implemented property in struct can not be assigned

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.
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; }
}
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.
Add a call to the default constructor:
public T(int u) : this()
{
this.U = 10;
}
you have to use the default constructor here:
struct T
{
public int U { get; private set; }
public T(int u) : this()
{
U = 10;
}
}
From C# 6 this is not an issue anymore and it compiles correctly. Look here

Is this too much data that should be used in a Struct?

public struct Cache {
public int babyGangters { get; set; }
public int punks { get; set; }
public int ogs { get; set; }
public int mercs { get; set; }
public int hsPushers { get; set; }
public int collegeDealers { get; set; }
public int drugLords { get; set; }
public int streetHoes { get; set; }
public int webcamGrls { get; set; }
public int escort { get; set; }
public int turns { get; set; }
public int cash { get; set; }
public int bank { get; set; }
public int drugs { get; set; }
public int totalValue { get; set; }
public int attackIns { get; set; }
public int attackOuts { get; set; }
public int status { get; set; }
public int location { get; set; }
}
That's not only too big by most guidelines, but it's also mutable. That's a much bigger red flag in my view.
Mutable structs can cause unexpected behaviour in many situations. Just say "no".
Why do you want this to be a struct in the first place? And does it really need to be mutable?
The rule of thumb is that a struct should not be bigger than 16 bytes (according to the Framework Design Guidelines). Your struct is 76 bytes (= 19 * 4), so it is pretty big. However, you will have to measure the performance. Big structs can be beneficial for some applications.
The Framework Design Guidelines state:
Avoid defining a struct unless the
type [...] an instance size under 16
bytes.
One of the annotations from Jeffrey Richterto this guidlines state:
Value types can be more than 16
bytes if you don't intend to pass them
to other methods or copy them to and
from a collection class (like an
array).
There is no hard and fast rule as to what constitutes a struct that is too big. There several guidelines available. Most notably the .Net Design Guidelines which recomend a struct not exceed 16 bytes in size.
However these are just guidelines. Whether or not a struct is too big depends highly on the context in which it is used. For example if the struct is created once and only passed by ref / out to all functions then it's size is much less important than one which is frequently passed by value.
In .Net, use classes unless you have a good reason not to. "I want it on the stack" with no other qualifiers is not usually a good reason.
http://www.codeproject.com/KB/cs/structs_in_csharp.aspx
struct improve memory e speed performance, but must be small, in this case utilize a class.
If the item is a struct, any attempt to change a field will only change the field in that particular struct instance. In some circumstances, .net will create temporary struct instances, and if you're not careful your attempts to change a field will simply change the field in that temp instance, rather than in anything more persistent. That is the 'gotcha' that Jon Skeet is warning you about.
On the other hand, a struct variable does have the advantage that value types within it can only be changed if that variable itself is written. The risk that an attempt to change a temporary struct might fail (described above) should be weighed against the risk that an two class variables might get aliased to the same object when they should in reality point to two different objects which happen to have the same property values. If that happens, a change to one variable might accidentally change the other.
One way to think of a struct is like a class which gets cloned any time it gets passed around, but with a cloning operation that's cheaper than that of a class. If 10%-50% or more of the uses of a class would require that it be cloned, you're probably better off with a struct. If you would mostly be using it without cloning it, use a class.
BTW, I wouldn't bother with settable properties; if something is settable, just make the field public. Since structs can't be inherited, there's no loss of generality.
It's impossible to answer that because this depends on your application and usage.
However, yes, with this much data you should really think about creating a class instead of a struct.
You could also ask yourself if you can logically group some of those fields into structs or classes.
The decision as to whether or not to use a struct should be based more on how you want to use it than on how large it is. You should ask yourself if there's any compelling benefit to making this a struct instead of a class. Do you really need value type semantics? Do you need to allocate tens of millions of these things and can't pay the allocation overhead (12 or 24 bytes, depending on the platform) if they're classes? I suspect that the answer to both of those questions is "No", so it's likely that you want to make this thing a class rather than a struct.

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

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?
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.
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
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;
}
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.
try to change struct to class for AttackTraits
public class AttackTraits
{
.........
{

Categories

Resources