对于类中的值类型属性,我对堆栈和堆上发生的事情感到困惑。
到目前为止我的理解:
当你创建一个具有结构(值类型)的类时,如下所示:
class Foo
{
private Bar _BarStruct;
public Bar BarStruct
{
get {return _BarStruct; }
set {_BarStruct = value; }
}
}
private struct Bar
{
public int Number;
Bar()
{
Number = 1;
}
Bar(int i)
{
Number = i;
}
}
如果你像这样创建一个类实例:
Foo fooObj = new Foo();
堆栈和堆将如下所示:
... Bar结构嵌入堆中的Foo类。这对我来说很有意义,但是当我们考虑在Foo对象中修改BarStruct类中的Number整数时,我开始松开它。例如:
Foo fooObj = new Foo();
fooObj.BarStruct.Number = 1;
据我所知,这应该返回一个BarStruct的副本以存在于堆栈中,这意味着BarStruct成员的任何更改都不会传递给该对象,这就是上面最后一行给出错误的原因
到目前为止这是对的吗?
如果是这样,我的问题是,如何进行这样的任务:
fooObj.BarStruct = new Bar(2);
...有效并更改堆值?当然这只是改变堆栈上的值?此外,(by和by)我发现它很混乱,你可以在值类型上使用new。对我来说,new是在堆上进行分配(根据C ++),对堆栈中的项目执行此操作感觉不自然。
所以只是为了重新讨论这个问题,我是否正确地假设当调用包含结构的属性时会发生什么?为什么你可以为一个副本分配一个新结构但它仍然会更改堆上的引用?
真的希望这一切都有意义。
如果你需要澄清,请大喊大叫!
的Ta,
安迪。
答案 0 :(得分:10)
看看这个作业:
fooObj.BarStruct = new Bar(2);
赋值不会改变堆栈上的值 - 它正在为属性调用 setter 。
换句话说,你的第一个作业相当于:
fooObj.get_BarStruct().Number = 1; // Bad
第二个相当于:
fooObj.set_BarStruct(new Bar(2));
这有帮助吗?
请注意,如果您将值类型设置为不可变,则有问题的赋值将成为非问题 - 事实上,这通常有帮助。可变值类型在C#中是一个非常糟糕的主意;你可以忍受它们的麻烦。
就你对“新”的期望而言 - 基本上不要用C ++思考。 C#不是C ++,如果你试图在C#中有效地编写C ++,各种各样的事情(析构函数,泛型,构造期间的行为)会让你感到困惑。 “new”语句创建一个类型的新实例,无论是值类型还是引用类型。