C#中是否可以使用具有类型类型的成员变量的Struct?如果是这样,信息将在何处存储,堆栈,堆或两者?
答案 0 :(得分:23)
是的,你可以。指向类成员变量的指针将存储在堆栈中,其中包含结构的其余值,类实例的数据存储在堆上。
结构也可以包含类定义作为成员(内部类)。
这是一些非常无用的代码,至少可以编译并运行以显示它是可能的:
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;
}
}
}
}
答案 1 :(得分:13)
类内容存储在堆上。
对类的引用(与指针几乎相同)与struct内容一起存储。存储结构内容的位置取决于它是局部变量,方法参数还是类的成员,以及它是否被闭包装箱或捕获。
答案 2 :(得分:3)
如果结构的某个字段是类类型,则该字段将保存类对象的标识,或者保留null引用。如果所讨论的类对象是不可变的(例如string
),则存储其标识也将有效地存储其内容。但是,如果所讨论的类对象是可变的,那么存储标识将是存储内容的有效方法当且仅当引用永远不会落入任何代码的手中时,一旦代码存储在其中,它可能会使其变异。该领域。
通常,应避免在结构中存储可变类类型,除非以下两种情况之一适用:
请注意,场景#1在泛型类型中非常常见;例如,有一个字典的“值”是可变对象的身份是很常见的;枚举该字典将返回其KeyValuePair
字段包含该可变类型的Value
个实例。
场景#2不太常见。没有办法告诉编译器除了属性设置器之外的结构方法将修改结构,因此在只读上下文中应禁止它们的使用;一个可以有一个行为类似于List<T>
的结构,但具有值语义,并包含一个Add
方法,但尝试在只读结构实例上调用Add
会产生伪造代码而不是编译器错误。此外,这种结构上的变异方法和属性设定器通常表现得相当差。当这些结构作为一个不可变的包装器存在于其他可变类中时,它们可能是有用的;如果这样的结构永远不会被装箱,那么性能往往比一个类好。如果只装箱一次(例如通过强制转换为接口类型),性能通常与类相当。如果重复加框,性能可能比一个类差很多。
答案 3 :(得分:2)
这可能不是建议的做法:请参阅http://msdn.microsoft.com/en-us/library/ms229017(VS.85).aspx
引用类型在堆上分配,内存管理是 由垃圾收集器处理。
值类型在堆栈或内联中分配并被释放 当他们超出范围。
通常,值类型分配和解除分配的成本更低。 但是,如果它们用于需要重要的场景 拳击和拆箱的数量,与...相比表现不佳 参考类型。