If I define a struct in C# using automatic properties like this:
public struct Address
{
public Address(string line1, string line2, string city, string state
A property is nothing more than an encapsulation of a Get
method and/or a Set
method. The CLR has metadata which indicates that particular methods should be regarded as being a properties, meaning compilers should allow some constructs which it would not allow with methods. For example, if X
is a read-write property of Foo
, a compiler will translate Foo.X += 5
into Foo.SET_X_METHOD(Foo.GET_X_METHOD() + 5)
(though the methods are named differently, and are not generally accessible by name).
Although an autoproperty implements a pair of get/set methods which access a private field in such a way as to behave more or less like a field, from the point of view of any code outside the property, an autoproperty is a pair of get/set methods just like any other property. Consequently, a statement like Foo.X = 5;
is translated as Foo.SET_X_METHOD(5)
. Since the C# compiler just sees that as a method call, and since methods do not include any metadata to indicate what fields they read or write, the compiler will forbid the method call unless it knows every field of Foo
has been written.
Personally, my advice would be to avoid the use of autoproperties with structure types. Autoproperties make sense with classes, since it's possible for class properties to support features like update notifications. Even if early versions of a class do not support update notifications, having those versions use an autoproperty rather than a field will mean that future versions can add update-notification features without requiring consumers of the class to be reworked. Structures, however, cannot meaningfully support most of the types of features that one might wish to add to field-like properties.
Further, the performance differences between fields and properties is much greater with large structures than it is with class types. Indeed, much of the recommendation to avoid large structures is a consequence of this difference. Large structures can actually be very efficient, if one avoids copying them unnecessarily. Even if one had an enormous structure HexDecet<HexDecet<HexDecet<Integer>>>
, where HexDecet<T>
contained exposed fields F0
..F15
of type T
, a statement like Foo = MyThing.F3.F6.F9;
would simply require reading one integer from MyThing
and storing it to Foo
, even though MyThing
would by huge by struct standards (4096 integers occupying 16K). Additionally, one could update that element very easily, e.g. MyThing.F3.F6.F9 += 26;
. By contrast, if F0
..F15
were auto-properties, the statement Foo = MyThing.F3.F6.F9
would require copying 1K of data from MyThing.F3
to a temporary (call it temp1
, then 64 bytes of data from temp1.F6
to temp2
) before finally getting around to reading 4 bytes of data from temp2.F9
. Ick. Worse, trying to add 26 to the value in MyThing.F3.F6.F9
would require something like var t1 = MyThing.F3; var t2 = t1.F6; t2.F9 += 26; t1.F6 = f2; MyThing.F3 = t1;
.
Many of the long-standing complaints about "mutable structure types" are really complaints about structure types with read/write properties. Simply replace properties with fields and the problems go away.
PS: There are times it can be useful to have a structure whose properties access a class object to which it holds a reference. For example, it would be nice to have a version of an ArraySegment<T>
class which allowed one to say Var foo[] = new int[100]; Var MyArrSeg = New ArraySegment<int>(foo, 25, 25); MyArrSeg[6] += 9;
, and have the last statement add nine to element (25+6) of foo
. In older versions of C# one could do that. Unfortunately, the frequent use of autoproperties in the Framework where fields would have been more appropriate led to widespread complaints about the compiler allowing property setters to be called uselessly on read-only structures; consequently, calling any property setter on a read-only structure is now forbidden, whether or not the property setter would actually modify any fields of the struct. If people had simply refrained from making structs mutable via property setters (making fields directly accessible when mutability was appropriate) compilers would never have had to implement that restriction.
Note: as of C# 6, this isn't required - but you should be using read-only automatically-implemented properties with C# 6 anyway...
this()
makes sure that the fields are definitely assigned as far as the compiler is concerned - it sets all fields to their default values. You have to have a fully constructed struct before you can start accessing any properties.
It's annoying, but that's the way it is. Are you sure you really want this to be a struct though? And why use a protected setter on a struct (which can't be derived from)?