我对类中值类型属性在堆栈和堆上发生的情况感到困惑。
目前我的理解:
当您创建一个具有如下结构(值类型)的类时:
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);
...有效并更改堆值?当然这只是在改变堆栈上的值??此外,(渐渐地)我发现它非常令人困惑,以至于您可以在值类型上使用 new。对我来说,new 用于在堆上进行分配(根据 C++),对堆栈上的项目执行此操作感觉不自然。
所以只是重复这个问题,我对调用包含结构的属性时会发生什么的假设是否正确,以及为什么可以将新结构分配给副本,但它仍然会更改堆上的引用?
真的希望这一切都有意义。
如果您需要澄清,请大声喊叫!
他,
安迪。
最佳答案
查看此作业:
fooObj.BarStruct = new Bar(2);
赋值不会更改堆栈上的值 - 它会调用属性的 setter。
换句话说,您的第一个作业相当于:
fooObj.get_BarStruct().Number = 1; // Bad
第二个相当于:
fooObj.set_BarStruct(new Bar(2));
这有帮助吗?
请注意,如果您一开始就让您的值类型不可变,那么有问题的赋值就不会成为问题 - 事实上,这通常会有所帮助。可变值类型在 C# 中是一个非常糟糕的主意;你可以和他们一起惹上无穷无尽的麻烦。
就您对"new"的期望而言——基本上尽量不要用 C++ 思考。 C# 不是 C++,如果您尝试在 C# 中有效地编写 C++,那么各种东西(析构函数、泛型、构造期间的行为)会让您感到困惑。 “new”语句创建一个类型的新实例,无论是值类型还是引用类型。
关于c# - 从属性返回值类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1999514/