Changing nested structures in C #

Can someone tell me why the commented line of code (one after the last) does not compile? Isn't that the same as the line following it?

public struct OtherStruct { public int PublicProperty { get; set; } public int PublicField; public OtherStruct(int propertyValue, int fieldValue) : this() { PublicProperty = propertyValue; PublicField = fieldValue; } public int GetProperty() { return PublicProperty; } public void SetProperty(int value) { PublicProperty = value; } } public struct SomeStruct { public OtherStruct OtherStruct { get; set; } } class Program { static void Main(string[] args) { SomeStruct a = new SomeStruct(); //a.OtherStruct.PublicProperty++; a.OtherStruct.SetProperty(a.OtherStruct.GetProperty() + 1); } } 
+4
source share
3 answers

SomeStruct.OtherStruct - a property that returns a value - this is not a variable. This line:

 a.OtherStruct.PublicProperty++; 

looks like a call:

 a.get_OtherStruct().PublicProperty++; 

Since the expression a.get_OtherStruct() is a value, not a variable, this looks a bit like this:

 OtherStruct tmp = a.get_OtherStruct(); tmp.PublicProperty++; 

Changing the PublicProperty value in the PublicProperty copy returned by this property will not change the original value at all. This is almost certainly not your intention. C # designers foresaw this problem and managed to ban it in many situations.

Note that if OtherStruct instead a reference type (class), then it would be the link that was copied, not the values ​​inside it ... so changing tmp.PublicProperty could make a difference. See the article for reference and type values for more information.

Btw, volatile structures like this are usually a very bad idea. They cause all kinds of problems and hard-to-predict code.

EDIT: in response to your “answer”, the two lines do not match: the expression of the a.OtherStruct property a.OtherStruct not an object of an assignment statement or a compound assignment statement.

You can say that you want C # to be defined in such a way that it allows (although I still disagree), but the compiler correctly executes the specification. See Section 10.7.2 of the C # 3.0 Specification for more details.

+9
source

I apologize for not using the comment, I don't think it will do. John, this is not a real implementation, I’m just trying to get a deeper understanding of the structures, so do not worry about the fact that I implement mutable structures :)

In any case, I'm not sure that you are right. Consider this code, almost the same as in the first example:

 public struct SomeStruct { public int PublicProperty { get; set; } public int PublicField; public SomeStruct(int propertyValue, int fieldValue) : this() { PublicProperty = propertyValue; PublicField = fieldValue; } public int GetProperty() { return PublicProperty; } public void SetProperty(int value) { PublicProperty = value; } } class Program { static void Main(string[] args) { SomeStruct a = new SomeStruct(1, 1); a.PublicProperty++; a.SetProperty(a.GetProperty()+1); } } 

Now, looking at msil using ildasm gives me the following for the Main method:

.method private hidebysig static void Main (string [] args) cil managed

{

 .entrypoint // Code size 45 (0x2d) .maxstack 3 .locals init ([0] valuetype ConsoleApplication1.SomeStruct a) IL_0000: nop IL_0001: ldloca.sa IL_0003: ldc.i4.1 IL_0004: ldc.i4.1 IL_0005: call instance void ConsoleApplication1.SomeStruct::.ctor(int32, int32) IL_000a: nop IL_000b: ldloca.sa IL_000d: dup IL_000e: call instance int32 

ConsoleApplication1.SomeStruct :: get_PublicProperty ()

 IL_0013: ldc.i4.1 IL_0014: add IL_0015: call instance void 

ConsoleApplication1.SomeStruct :: set_PublicProperty (int32)

 IL_001a: nop IL_001b: ldloca.sa IL_001d: ldloca.sa IL_001f: call instance int32 ConsoleApplication1.SomeStruct::GetProperty() IL_0024: ldc.i4.1 IL_0025: add IL_0026: call instance void ConsoleApplication1.SomeStruct::SetProperty(int32) IL_002b: nop IL_002c: ret 

}

Sorry for the awful formatting, I'm not sure how to make it normal. In any case, I hope you will see that the last 2 lines of code in the main method are actually identical.

Therefore, I would say that from the previous post this line:

 a.OtherStruct.PublicProperty++; 

In fact, it is identical to the line after it:

  a.OtherStruct.SetProperty(a.OtherStruct.GetProperty() + 1); 

And therefore, it seems to me that the first line is not compiled simply because the compiler does not support it, and not because it is not legal.

What do you think?

0
source

Structures should not expose fields like read and write properties; there is no good reason for this. Instead, they should simply open the fields directly. Most of the "problems" that are attributed to "mutable structures" are indeed problems with structures that reveal read and write properties. In your example, if you just made a member of OtherStruct type SomeStruct be a field, and not a valid one (that is, lose { get; set; } , then there would be no problem with nested access to the structure.

Note also that one “problematic” person with “mutable structures” who is not related to this mutation (something that does such fields) follows from the fact that in the following code:

  someStructType myThing = MyDataSupplier.GetSomeData ();
   myThing.someField = something;

a change to myThing will not leak back to MyDataSupplier if any code is missing:

  MyCollection [whatever] = myThing;

My reaction would be "Naturally. Knowing that someStructType is a structure with someField field, it is enough to know that myThing.someField can be changed without affecting anything else in the universe." In contrast, if you substitute myClassType , and myClassType has a mutable member (regardless of whether it is a field or a property), the above code "can" correctly modify data in MyDataSupplier , or maybe not, and such a modification may or may not can spoil other aspects of the state of the system. In fact, the complaint is that someone would have predictable behavior that would not always correspond to what needs to be done, and not to semantics that depend on many things, including in some cases other MyDataSupplier consumers. Note also that if someStructType opened the read-write property rather than a field, you would need to examine the code associated with this property to determine whether it can affect objects outside the structure instance that it is being called on.

0
source

Source: https://habr.com/ru/post/1306718/


All Articles