来自http://csharpindepth.com/Articles/Chapter8/PropertiesMatter.aspx
using System;
struct MutableStruct
{
public int Value { get; set; }
public void SetValue(int newValue)
{
Value = newValue;
}
}
class MutableStructHolder
{
public MutableStruct Field;
public MutableStruct Property { get; set; }
}
class Test
{
static void Main(string[] args)
{
MutableStructHolder holder = new MutableStructHolder();
// Affects the value of holder.Field
holder.Field.SetValue(10);
// Retrieves holder.Property as a copy and changes the copy
holder.Property.SetValue(10);
Console.WriteLine(holder.Field.Value);
Console.WriteLine(holder.Property.Value);
}
}
1)为什么要制作(属性?)的副本?
2)将代码更改为holder.Field.Value
和holder.Property.Value = 10
时,我会收到以下错误消息。这让我大吃一惊。
无法修改'MutableStructHolder.Property'的返回值,因为它不是变量
为什么我不允许在属性中分配值!?!这两个属性都是get
/ set
!
最后为什么你想要在1和2中提到的行为? (它从来没有出现过,我总是只使用获得属性)。
请解释一下,我无法想象第二次会比第一次少得多。这对我来说太奇怪了。
答案 0 :(得分:3)
1)正在制作Property
的副本,因为它是struct
,struct
是值类型(与class
不同)并且由价值,而不是参考。
2)您看到的“无法修改返回值”错误源于结构的“按值复制”性质。如果您修改了结构(在Value
上设置MutableStruct
到[{1}}上的Property
),则您的更改将不会反映在其上,因为您将修改复制结构,而不是属性中保存的结构。由于您永远不会想要这种行为,因此C#编译器会阻止您这样做。
现在,如果MutableStructHolder
是MutableStruct
,那么通过属性修改它绝对没有问题(并且C#编译器允许你这样做),因为你将使用实际的实例,而不是副本。
答案 1 :(得分:2)
问题1:您应该阅读结构和类,因为这些结构解释了您所描述的所有“症状”。结构不是通过引用传递的,但实际上是通过复制传递的对象 - 副本作为关键字。因此,当属性返回一个结构时,它实际上是一个副本,而不是你正在改变其值的“真实”对象。
关于问题2: C#编译器意识到直接在通过属性检索的struct-object上设置变量是没有意义的,因此会向您提供错误告诉您。通过属性检索的对象是否具有setter不会改变此行为,您将以任何方式接收错误。
我建议您阅读Lasse Karlsen对“The difference between structs and classes”问题的回答
,而不是对类和结构进行写作。答案 2 :(得分:2)
回答#1:考虑没有自动生成属性的情况。你有Property { get { return xxx; } }
这就是复制的地方。看起来像是指一个属性,实际上是在调用getter方法。如果您有以下内容,您是否期望进行就地编辑:
private MutableStruct v;
public MutableStruct f()
{
return v;
}
f() = new MutableStruct();
当然不是,我们都依赖于返回来制作结构的副本,以便保护私有变量免受外部修改。这就是为什么它按照它的方式工作的原因。
现在,如果您认为应该自动使用结果值调用属性设置器,请让我指出在编译时无法知道非常困难到struct的一个方法进行更改(考虑结构是否在不同的程序集中定义)。将价值写回来不仅效率低下而且无害,可能会破坏正确性。考虑一个多线程场景,其中只在ReaderWriterLock保护下从属性读取的线程突然写回来。会发生各种各样的痛苦和痛苦。因此,C#编译器自动将属性设置为计算结果不是一种选择。
struct Mutable
{
public static int Sum = 0;
public int x;
public Mutable(int x) { this.x = x; }
public void Total() { Sum += x; }
}
class Container
{
public Mutable Field;
public Mutable Property { get; set; }
}
class Program
{
static void Main(string[] args)
{
Container c = new Container();
c.Field = new Mutable(1);
c.Property = new Mutable(2);
c.Field.Total();
c.Property.Total();
Console.Out.WriteLine(Mutable.Sum);
}
}
答案 3 :(得分:0)
结构按值传递,所以你所拥有的只是副本。也:
public int Value { get; set; }
是
的简写private int _Value;
public int Value {
get { return _Value; }
set { _Value = value; }
}
正如您所看到的,正在进行大量复制,因此需要投诉。如果您改为使用class
作为参考类型,则不会出现此问题。