【发布时间】:2010-09-09 06:41:12
【问题描述】:
在 C# 中是否可以有一个带有类类型成员变量的 Struct?如果是这样,信息存储在哪里,在堆栈、堆或两者上?
【问题讨论】:
标签: c# class struct value-type reference-type
在 C# 中是否可以有一个带有类类型成员变量的 Struct?如果是这样,信息存储在哪里,在堆栈、堆或两者上?
【问题讨论】:
标签: c# class struct value-type reference-type
是的,你可以。指向类成员变量的指针与结构的其余值一起存储在堆栈上,而类实例的数据存储在堆上。
结构也可以包含类定义作为成员(内部类)。
这里有一些非常无用的代码,至少可以编译并运行以表明它是可能的:
using System;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
MyStr m = new MyStr();
m.Foo();
MyStr.MyStrInner mi = new MyStr.MyStrInner();
mi.Bar();
Console.ReadLine();
}
}
public class Myclass
{
public int a;
}
struct MyStr
{
Myclass mc;
public void Foo()
{
mc = new Myclass();
mc.a = 1;
}
public class MyStrInner
{
string x = "abc";
public string Bar()
{
return x;
}
}
}
}
【讨论】:
类内容存储在堆中。
对类的引用(几乎与指针相同)与结构内容一起存储。 struct 内容的存储位置取决于它是局部变量、方法参数还是类的成员,以及它是被装箱还是被闭包捕获。
【讨论】:
string 存储在 0x1000”的任何其他对象。字符串数组在无法访问时会消失,即使其中引用的某些对象将继续存在。 struct 数组实际上包含它的元素,不涉及引用(指针),因此当数组不可达时,根据定义,元素也是不可达的,不需要在运行时进行分析来检查。
如果结构的字段之一是类类型,则该字段将保存类对象的 identity 或空引用。如果所讨论的类对象是不可变的(例如string),则存储其身份也将有效地存储其内容。但是,如果所讨论的类对象是可变的,则存储标识将是存储内容的有效方法当且仅当引用永远不会落入任何代码的手中,一旦它存储在字段.
一般来说,除非出现以下两种情况之一,否则应避免在结构中存储可变类类型:
请注意,场景 #1 在泛型类型中很常见;例如,有一个字典,其“值”是可变对象的身份是很常见的;枚举该字典将返回 KeyValuePair 的实例,其 Value 字段包含该可变类型。
场景 #2 不太常见。唉,没有办法告诉编译器除了属性设置器之外的结构方法会修改结构,因此应该禁止在只读上下文中使用它们;可以有一个行为类似于List<T> 的结构,但具有值语义,并包含Add 方法,但尝试在只读结构实例上调用Add 会生成虚假代码而不是编译器错误.此外,这种结构上的变异方法和属性设置器通常会表现得很差。当此类结构作为不可变包装存在于其他可变类上时,它们可能很有用;如果这样的结构从不装箱,性能通常会比类好。如果只装箱一次(例如,通过转换为接口类型),性能通常与类相当。如果反复装箱,性能可能会比一个类差很多。
【讨论】:
可能不建议这样做:请参阅http://msdn.microsoft.com/en-us/library/ms229017(VS.85).aspx
引用类型在堆上分配,内存管理是 由垃圾收集器处理。
值类型在堆栈或内联上分配并被释放 当他们超出范围时。
一般来说,值类型的分配和解除分配成本更低。 但是,如果它们用于需要显着 装箱和拆箱的数量,与 引用类型。
【讨论】: