Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
249 views
in Technique[技术] by (71.8m points)

c# - Why can struct change their own fields?

Consider the Foo struct as follows:

struct Foo
{
  public float X;
  public float Y;

  public Foo(float x, float y)
  {
    this.X = x;
    this.Y = y;
  }

  public void Change(float x)
  {
    this.X = x;
  }
}

I understand modifying the field in the constructor, that's perfectly logical to me and my understanding of structs as value, number-like immutable types.

However, since one can't do:

Foo bar = new Foo(1, 2);
bar.X = 5;

Why can one use:

Foo bar = new Foo(1, 2);
bar.Change(5);

EDIT: If structs are mutable, then why can't they be modified when in a list or returned from a property?

Cannot modify expression because it is not a variable

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Since one cannot do

Foo bar = new Foo(1, 2); 
bar.X = 5; 

Why can one use:

Foo bar = new Foo(1, 2); 
bar.Change(5); 

Your original question actually cannot be answered because it is predicated on a completely false assumption. Both code samples are perfectly legal, and so the question about why one is illegal is nonsensical. Let's move on to your follow-up question:

If structs are mutable, then why can't they be modified when in a list or returned from a property?

Because variables are mutable and values are immutable.

That's why they're called "variables", after all, because they can change.

When you say "bar.X = 5", "bar" is a local variable. Variables are allowed to change.

When you say "bar.Change(5)", "bar" is a local variable. Variables are allowed to change.

When you say "myArray[123].X = 5", "myArray[123]" is an array element and an array element is a variable. Variables are allowed to change.

When you say "myDictionary[123].X = 5", "myDictionary[123]" is not a variable. The value is returned from the dictionary, not a reference to the storage location. Since that is a value, not a variable, there is nothing there that can change, so the compiler does not allow it to change.

A subtle point is that when you attempt to change a field, the receiver must be a variable. If it is not a variable, it makes no sense; you are clearly attempting to mutate a variable and there's nothing there to mutate. When you call a method, the receiver must be a variable but what if you have a value? The method might not attempt to mutate anything, and so should be allowed to succeed. What the compiler actually does if the receiver of a method call on a struct is not a variable, then it makes a new temporary local variable and calls the method with that variable. So if you say: "myDictionary[123].Change(5);" that is the same as saying

var temp = myDictionary[123];
temp.Change(5);

Here "temp" is a variable, and the mutating method is allowed to change the temporary copy.

Is that now clear? The key takeaway here is variables can change.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...