【问题标题】:Trying to understand classes and struct试图理解类和结构
【发布时间】:2012-08-05 17:23:14
【问题描述】:

我今天早上一直在阅读 MSDN“C# 类和结构”,试图更好地理解这两个概念。

类是引用类型。当创建该类的对象时,分配给该对象的变量只保存对该内存的引用。当对象引用分配给新变量时,新变量引用原始对象。通过一个变量所做的更改会反映在另一个变量中,因为它们都引用相同的数据。

结构是一个值类型。创建结构时,分配给结构的变量保存结构的实际数据。当结构被分配给一个新变量时,它被复制。因此,新变量和原始变量包含相同数据的两个单独副本。对一个副本所做的更改不会影响另一个副本。”--MSDN

有人可以写几行示例代码来说明这个概念,因为我是一个试图掌握 OOP 概念并向我解释的年轻高中女生吗??

参考和价值(场景):一本书中,有一页有一个难懂的术语,不是每个人都能理解的,所以作者决定将术语的定义放在括号中(对于不熟悉的人)术语)。是不是像传值一样?

如果作者将页码引用放在术语后面的括号中,不熟悉该术语的读者可以浏览找到该术语的含义,那么这是否是引用传递?

【问题讨论】:

  • 你有什么不明白的?
  • 值类型和引用类型的概念是.NET概念,不是一般的OOP概念。

标签: c# class reference struct value-type


【解决方案1】:

尽量简单地说,区别主要在于实例是如何存储和使用的。

引用类型——顾名思义——总是通过引用来寻址。这意味着变量不保存对象本身,而只是有关信息在内存中有效存储位置的信息。现在,如果您将此变量分配给另一个值,则不会复制实例,而只会复制引用,这意味着现在两个变量都引用了同一个实例。

另一方面,值类型直接存储在它们所在的位置(例如变量)中。因此,当您对另一个变量进行赋值时,它将复制该实例,并且两者都将保持独立。

假设我们有实例 a 和 b,它们有一个字段 x:

a = new MyReferenceType();
a.x = 5;
b = a;
a.x = 10;
// b.x is now also 10, because both a and b reference the same instance

a = new MyValueType();
a.x = 5;
b = a;
a.x = 10;
// b.x is still 5, because both a and b are distinct instances

现在作为参考可以提供更大的灵活性;引用的大小是恒定的,但它引用的对象实例的大小可能会有所不同,这可以实现典型的 OO 原则,尤其是多态性。此外,与值类型相比,引用可以引用“无”,在这种情况下,它们是 null

注意:这主要是 .NET Framework 的实现细节。值类型(结构)有其用途,它们与原始类型的概念非常吻合,它们与值类型共享相同的语义。但是,它们在支持的 OOP 概念方面受到严格限制。

【讨论】:

  • 另外值得注意的是,几乎不应该使用可变值类型——它们会造成太多混乱。
  • Joey,这是正确的,关于该主题可以写很多东西(例如在可变结构上使用属性而不是字段 - 这让事情变得更糟)。但是,我试图专注于提出的问题。不变性等概念可能不是 Sarika 应该考虑太多的事情。
  • 重要提示:在 C# 中,值类型需要用new MyValueType() 初始化。声明变量的那一刻,内存已经分配,​​但未初始化(即它包含随机字节)。因此,结构通常用于性能关键场景(XNA 框架),因为可以省略new 关键字的开销(Vector2 myvec; myvec.X = ...; myvec.Y = ...; 明显快于Vector2 myvec = new Vector2(..., ...))。此外,结构存储信息的方式是可预测的,因此结构在将非托管数据编组到 C# 方面发挥着重要作用。
  • @dialer,我认为您在这里有一些误解。首先,C# 要求您在要使用变量时对其进行初始化。此外,结构总是有一个不能被覆盖的默认构造函数,这就是为什么调用new MyStruct()(不是带参数的)没有任何性能影响(看看生成的IL)。此外,在 .NET Framework 中分配的所有托管内存都将 AFAIK 清零,它从不包含随机字节。
  • @Lucero 生成的Vector2 myvec; myvec.X = 5.0f; myvec.Y = 4.0f; 的ILVector2 myvec = new Vector2(); myvec.X = 5.0f; myvec.Y = 4.0f; 相同。 new Vector2() 明确添加了 initobj 操作码,但是这两种变体之间的区别与:Vector2 myvec(5.0f, 4.0f); 相比没有什么不同(这个比较是我评论的重点)。然而,当我查看生成的 ASM 时,我惊讶地发现这些字段确实初始化为 0 (xor edx,edx; mov ...),我认为这是不必要的,因为 C# 不允许您使用带有未初始化字段的结构。
【解决方案2】:

假设我们有一个类 Foo 和一个结构体 Bar

class Foo
{
  public string Name;
}

struct Bar
{
  public string Name;
}

Foo f = new Foo();
Foo g = f;
f.Name = "Larry";
//Since g and f point to the same object both have a name of "Larry"
//changes to one, change all instances that point (refer) to the same object (memory location)
Bar b = new Bar();
Bar c = b;
b.Name = "Paul";
//Since Bar is a value type, when we set the name of b, c is not altered because 
//b and c do not refer to the same object, they are independent variables
//each allocated their own memory
//and can vary separately after the initial assignment. 

【讨论】:

  • 所以它们本质上都是数据结构,只是它们的实例对象如何引用它们的每个成员变量和方法不同?对于struct,实例化对象的状态值将直接分配内存,而对于类实例化对象,它的状态值不直接存储在内存中,而是在内存中的引用..
  • @SarikaThapaliya - 不。这是关于类型如何存储在内存中的。引用类型指向的内存位置保存对实际对象的引用(内存位置)。对于值类型,引用直接指向对象。
  • @Oded,我发现您的评论“对于值类型,引用直接指向对象。”由于对“参考”作品的含糊使用,有点误导。
  • @Lucero - 很公平,虽然我很难找到更好的表达方式。
  • @Oded,是的,这就是我在回答中选择“变量”一词的原因,这在技术上并不完全准确,但可能直观地理解了正确的方式。
猜你喜欢
  • 1970-01-01
  • 2017-12-30
  • 1970-01-01
  • 1970-01-01
  • 2013-09-05
  • 1970-01-01
  • 2011-09-10
  • 2016-07-18
  • 1970-01-01
相关资源
最近更新 更多