c# - 从属性返回值类型

标签 c# properties heap-memory stack-memory value-type

我对类中值类型属性在堆栈和堆上发生的情况感到困惑。

目前我的理解:

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

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++),对堆栈上的项目执行此操作感觉不自然。

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

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

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

他,

安迪。

最佳答案

查看此作业:

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/

相关文章:

java - 在这种情况下自签名证书更好吗?

c# - 如何在 WPF 中制作右键单击按钮上下文菜单?

java - 批处理 JDBC

java - java中字符串的字体设置

C# 大对象和堆

java - InputStream读取部分文件并输出

c# - 跨程序集使用应用程序设置

c# - c# 中的 vbNullChar 等价物是什么?

c++ - 在 C++ 中对类属性使用字符串数据类型的问题

redis - 就内存使用而言,将其所有数据存储为字符串不是一种开销吗?