8

关于类中的值类型属性,我对堆栈和堆上发生的事情感到困惑。

到目前为止我的理解:

当您创建具有如下结构(值类型)的类时:

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();

堆栈和堆将如下所示:

https://i962.photobucket.com/albums/ae105/acardy/stackheap-1.jpg(https://i962.photobucket.com/albums/ae105/acardy/stackheap-1.jpg)

...其中 Bar 结构嵌入在堆中的 Foo 类中。这对我来说很有意义,但是当我们考虑在 Foo 对象中修改 BarStruct 类中的 Number 整数时,我开始失去它。例如:

Foo fooObj = new Foo();
fooObj.BarStruct.Number = 1;

据我了解,这应该是返回 BarStruct 的副本以存在于堆栈中,这意味着 BarStruct 成员的任何更改都不会传递到对象,这就是上面最后一行给出错误的原因。

到目前为止这是正确的吗?

如果是这样,我的问题是,怎么会有这样的任务:

fooObj.BarStruct = new Bar(2);

...有效并更改堆值?当然这只是改变堆栈上的值?此外,(渐渐地)我发现它非常令人困惑,以至于您可以在值类型上使用 new 。对我来说,new 用于在堆上分配(根据 C++),并且感觉不自然地为堆栈上的项目执行此操作。

因此,只是为了重申这个问题,我是否正确假设调用包含结构的属性时会发生什么,为什么可以将新结构分配给副本,但它仍然会更改堆上的引用?

真的希望这一切都有意义。

如果您需要澄清,请大喊大叫!

塔,

安迪。

4

1 回答 1

10

看这个作业:

fooObj.BarStruct = new Bar(2);

赋值不会更改堆栈上的值 - 它正在调用属性的设置器

换句话说,而您的第一个任务相当于:

fooObj.get_BarStruct().Number = 1; // Bad

第二个相当于:

fooObj.set_BarStruct(new Bar(2));

这有帮助吗?

请注意,如果您从一开始就使值类型不可变,那么有问题的分配就不会成为问题 - 事实上,这通常会有所帮助。可变值类型在 C# 中是一个非常糟糕的主意;你可能会遇到无穷无尽的麻烦。

就您对“新”的期望而言 - 基本上不要用 C++ 思考。C# 不是 C++,如果您尝试在 C# 中有效地编写 C++,那么各种事物(析构函数、泛型、构造期间的行为)都会让您感到困惑。“new”语句创建一个类型的新实例,无论是值类型还是引用类型。

于 2010-01-04T13:28:39.103 回答