Why call: this () in a structure to use automatic properties in C #?

If I define a structure in C # using automatic properties like this:

public struct Address { public Address(string line1, string line2, string city, string state, string zip) { Line1 = line1; Line2 = line2; City = city; State = state; Zip = zip; } public string Line1 { get; protected set; } public string Line2 { get; protected set; } public string City { get; protected set; } public string State { get; protected set; } public string Zip { get; protected set; } } 

When I try to create a file, I get a compilation error saying The 'this' object cannot be used before all of its fields are assigned to . This can be resolved by changing the constructor to make a related call to the default constructor as follows:

 public Address(string line1, string line2, string city, string state, string zip): this() { Line1 = line1; Line2 = line2; City = city; State = state; Zip = zip; } 

My question is: why does this work and what happens? I have an assumption, and I tried to prove it by looking at IL, but I'm only joking if I think I can break IL. But I assume that auto properties work when the compiler generates fields for your properties backstage. These fields cannot be accessed through code; all settings and retrieval must be done through properties. When creating a structure, the default constructor cannot be explicitly defined. Therefore, behind the scenes, the compiler must generate a default constructor that sets the values โ€‹โ€‹of the fields that the developer cannot see.

Any and all IL masters can confirm or refute my theory.

+52
c # struct cil
Nov 07 '08 at 14:06
source share
2 answers

Note: this is not required with C # 6 - but you should use automatically implemented properties with C # 6 anyway ...

this() ensures that the fields are definitely assigned to the compiler - it sets all the fields to their default values. Before you start accessing any properties, you must have a completely built structure.

It is annoying, but it is. Do you really want this to be a structure? And why use a secure setter in a structure (from which it cannot be obtained)?

+51
Nov 07 '08 at 14:10
source share

A property is nothing more than an encapsulation of the Get method and / or the Set method. The CLR has metadata that indicates that specific methods should be considered properties, that is, compilers should allow some constructs that it does not allow using methods. For example, if X is the read-write property of Foo , the compiler will translate Foo.X += 5 to Foo.SET_X_METHOD(Foo.GET_X_METHOD() + 5) (although the methods are named differently and are usually not accessible by name).

Although autoproperty implements a pair of get / set methods that access the 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, the autoprocessor is a pair of get / set methods, like any other property. Therefore, a statement of the type Foo.X = 5; translates as Foo.SET_X_METHOD(5) . Since the C # compiler simply sees this as a method call, and since the methods do not contain metadata to indicate which fields they read or write, the compiler forbids calling the method if it does not know that the entire Foo field has been written.

Personally, I advise you to avoid using auto-processors with structures. Autoproperties make sense with classes because it is possible for class properties to support features such as update notifications. Even if earlier versions of a class do not support update notifications, if these versions use autoproperty rather than a field, this means that future versions can add update notification functions without requiring consumers of this class to be redesigned. However, structures cannot significantly support most types of functions that could be added to field-like properties.

In addition, performance differences between fields and properties are much larger with larger structures than with class types. Indeed, most of the recommendations for preventing large structures are a consequence of this difference. Large structures can be very effective if you avoid copying them unnecessarily. Even if one had a huge structure HexDecet<HexDecet<HexDecet<Integer>>> , where HexDecet<T> contained open fields F0 .. F15 type T , a statement like Foo = MyThing.F3.F6.F9; it would just require reading a single integer from MyThing and saving to Foo , although MyThing would have huge structural standards (4096 integers occupying 16K). In addition, you can very easily update this item, for example. MyThing.F3.F6.F9 += 26; . In contrast, if F0 .. F15 were auto-properties, the operator Foo = MyThing.F3.F6.F9 would require you to copy 1K data from MyThing.F3 to temporary (let's call it temp1 and then 64 bytes of data from temp1.F6 to temp2 ) before moving on to reading 4 bytes of data from temp2.F9 . Hk. Even worse, trying to add 26 to a 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; 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. Just replace the properties with fields and the problems will disappear.

PS: Sometimes it is useful to have a structure whose properties access the object of the class to which it contains a link. For example, it would be nice to have a version of the ArraySegment<T> class that would allow Var foo[] = new int[100]; Var MyArrSeg = New ArraySegment<int>(foo, 25, 25); MyArrSeg[6] += 9; Var foo[] = new int[100]; Var MyArrSeg = New ArraySegment<int>(foo, 25, 25); MyArrSeg[6] += 9; , and the last expression will add nine to the element (25 + 6) from Foo . In older versions of C #, this could be done. Unfortunately, the frequent use of auto-processes within the framework, where the fields would be more appropriate, led to widespread complaints about the compiler, allowing real estate developers to uselessly call structures read-only; therefore, calling any means of defining properties in a read-only structure is now prohibited, regardless of whether this property element changes any fields in the structure. If people simply refrained from creating structures that could be modified using property setters (making fields available directly when suitability was suitable), compilers would never have to fulfill this limitation.

0
Oct 01
source share



All Articles