C# 基本类型(double、int 等)和 Struct 差异
我对结构感到困惑。
class A
{
double a { get; set; }
MyStruct b { get; set; }
void Modify()
{
a = 1.0; // This compiles.
b.c = 2.0; // Assuming c is a double. This gives the known error.
}
}
现在为什么我能够设置结构体 a 的值,而不是结构体字段 b 的值? 我读到的答案是我有 b 的副本,而不是 b 的支持字段。按照同样的逻辑,我必须拥有 a 的副本,而不是 a,那么它如何解释 a 属性在允许的赋值之后发生更改
a = 1.0;
?谢谢。
编辑:
另外,为了仍然在 A 类中使用 b,通过 set 和 get 方法“过滤”,而不是直接使用支持字段 _b ,可能如下所示:
MyStruct _b;
MyStruct b { get { return _b; } set { _b=value; } }
然后使用 field
_b
,如答案中正确所述,我想到了一种愚蠢的方法,将属性“包装”在大小为 1 的一维数组中
MyStruct[] b { get; set; }
。类似于用类包装结构。我不知道这样做的计算成本,但我更喜欢直接在 A 类中使用该字段。
已回答:好吧,当您习惯于将属性解释为字段时,这个问题中的混乱就出现了。如果您以正确的方式解释属性(像 MsIL 那样),那么一切都会安定下来。下面的所有答案和评论都是相关的。 (抱歉英语不好。)
I am confused with structs.
class A
{
double a { get; set; }
MyStruct b { get; set; }
void Modify()
{
a = 1.0; // This compiles.
b.c = 2.0; // Assuming c is a double. This gives the known error.
}
}
Now why I am able to set the value of the structure a, and not of the structure's field b ?
The answer I read is that I have a copy of b and not b's backing field. By the same logic I must have a copy of a, not a, so how it explains that the a property is changed after the permitted assignement
a = 1.0;
? Thank you.
EDIT :
Also in order to still use b inside the A class, "filtered" by the set and get methods and not directly by using the backing field _b, something which could look like this:
MyStruct _b;
MyStruct b { get { return _b; } set { _b=value; } }
and then use the field
_b
, as correctly stated in the answers, I thinked of a silly method to "wrap" the property in an one dimensional array of size 1.
MyStruct[] b { get; set; }
kind of wrapping the struct with a class. I dont know the computational cost of this, but I preferred it from using the field directly inside the A class.
ANSWERED : Ok, the confusion in this question comes, when you are used to interpret properties as fields in your mind. If you interpret properties the correct way -as the MsIL does-, all things settle down. All the answers and comments below, are relevant.
(Sorry for the bad English.)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
你正在做两件不同的事情。下面是在两个地方执行相同操作的示例:
在这两种情况下,赋值运算符都调用属性的“setter”。您可以将其视为:
作为一个更复杂的示例,如果您编写:
则相当于:
You're doing two different things. Here's an example of doing the same thing in both places:
In both of these cases, the assignment operator is calling the "setter" of the property. You can think of it as:
As a more complicated example, if you wrote:
that's equivalent to:
假设您对以下形式的成员访问进行了赋值:
根据定义,结构体实例的值是其值。如果您尝试改变结构体的字段,那么您必须尝试改变存储值的存储位置。也就是说,您必须尝试改变变量。该字段是一个变量,它是另一个变量的一部分。
因此,如果 expr 是结构类型,那么 expr 必须是变量。
在您的示例中,expr 不是变量。它是一个属性,并且属性访问的结果是一个值,而不是一个变量。
这可能不太清楚。让我们尝试打个比方。
想象一下你有一张纸代表一个结构体的值。这张纸上有一个标有“c”的方框,其中包含一个数字。
当你说“bc = 2.0;”时它所做的就是找到与 b 相关的存储,并复印在那里找到的那张纸。然后,您删除收到的副本上的数字并将其替换为 2.0。这符合你的要求吗?当然不是。它根本不会改变b中存储的那张纸的值!值类型按值复制。因为这没有达到您想要的效果,所以在 C# 中这是非法的。
现在假设你有一张纸代表一个类的值。这张纸上有一个标有“y”的方框,其中包含一个数字。
当你说“xy = 2.0;”时它所做的就是找到与 x 相关的存储,然后递给您一根丝带的一端。丝带的另一端附着在与 x 相关的存储空间的纸上。您沿着功能区,找到另一端标有 y 的框,并将那里的数字替换为 2.0。
引用类型通过引用复制;您不会获得存储中值的副本,您会获得可以让您找到存储的东西。
这就是值类型和引用类型之间的区别;值类型按值复制,引用类型按引用复制。
现在清楚了吗?
Suppose you have an assignment to a member access of the form:
The value of a struct instance is, by definition, its value. If you are attempting to mutate the field of a struct then you must be attempting to mutate the storage location that stores the value. That is, you must be attempting to mutate the variable. The field is a variable which is a part of another variable.
Therefore, if expr is a struct type then expr must be a variable.
In your example, expr is not a variable. It's a property, and the result of a property access is a value, not a variable.
That might not be clear. Let's try an analogy.
Imagine you have a piece of paper that represents a value of a struct. The paper has a box on it labelled "c", which contains a number.
When you say "b.c = 2.0;" what that does is goes and finds the storage associated with b, and makes a photocopy of the piece of paper it finds there. You then erase the number on the copy you've been handed and replace it with 2.0. Does that do what you want? Of course not. It doesn't change the value of the piece of paper stored in b at all! Value types are copied by value. Because this doesn't do what you want, it is illegal in C#.
Now suppose you have a piece of paper that represents the value of a class. The paper has a box in it labelled "y" which contains a number.
When you say "x.y = 2.0;" what it does is goes and finds the storage associated with x, and hands you one end of a ribbon. The other end of the ribbon is attached to the piece of paper that is the storage associated with x. You follow the ribbon, find the box labelled y at the other end, and replace the number there with 2.0.
Reference types are copied by reference; you don't get a copy of the value in the storage, you get something that lets you find the storage.
That's the difference between value types and reference types; value types are copied by value, reference types are copied by reference.
Is that now clear?
当您尝试修改该值时会出现此错误。
当您编写
a = 1.0
时,您正在替换该值 - 您正在将整个值类型分配给一个新值。a = 1.0
相当于b = new MyStruct()
。这是可变结构是邪恶的的另一个原因。
This error occurs when you try to modify the value.
When you write
a = 1.0
, you're replacing the value - you're assigning the entire value type to a new value.a = 1.0
is equivalent tob = new MyStruct()
.This is yet another reason why mutable structs are evil.
你的逻辑有点不对劲。
在第一个示例中,您将用全新的双精度替换双精度。
在第二个示例中,您不会用另一个结构替换该结构。相反,您尝试修改结构的某些字段。
要执行类似的操作,您必须执行以下操作:
Your logic is a little off.
In your first example, you're replacing a double with a brand new double.
In the second example, you're not replacing the struct with another struct. Instead you're trying to modify some field of the struct.
To do similar things, you would have to do: