繁体   English   中英

你能在一个结构中有一个类吗?

[英]Can you have a class in a struct?

在C#中是否可以使用具有类型类型的成员变量的Struct? 如果是这样,信息存储在哪里,堆栈,堆,或两者?

是的你可以。 指向类成员变量 的指针 与结构的其余值一起存储 在堆栈中 ,类实例的数据存储在堆上。

结构也可以包含类定义作为成员(内部类)。

这是一些真正无用的代码,至少编译并运行以显示它是可能的:

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内容一起存储。 存储结构内容的位置取决于它是局部变量,方法参数还是类的成员,以及它是否被闭包装箱或捕获。

of a class object or else a null referece. 如果结构的某个字段是类类型,则该字段将保留类对象的 ,或者保留null引用。 如果所讨论的类对象是不可变的(例如string ),则存储其标识也将有效地存储其内容。 . 但是,如果所讨论的类对象是可变的,那么存储该标识将是一种有效的存储内容的方法,

通常,应避免在结构中存储可变类类型,除非以下两种情况之一适用:

  1. 事实上,人们感兴趣的是类对象的身份而不是其内容。 例如,可以定义一个`FormerControlBounds`结构,它保存“Control”和“Rectangle”类型的字段,并表示某个时刻控件具有的“Bounds”,以便以后能够恢复控件到它早先的位置。 “Control”字段的目的不是保存控件状态的副本,而是识别应该恢复其位置的控件。 通常,struct应该避免访问它拥有引用的对象的任何可变成员,除非很明显这样的访问是指有关对象的当前可变状态(例如在`CaptureControlPosition`或` RestoreControlToCapturedPosition`方法,或`ControlHasMoved`属性)。
  2. 该字段是`private`,唯一读取它的方法是为了检查其属性而不将对象本身暴露给外部代码,并且编写它的唯一方法将创建一个新对象,执行所有突变它将永远发生在它上面,然后存储对该对象的引用。 例如,人们可以设计一个`struct`,它的行为很像一个数组,但具有值语义,通过让struct在私有字段中保存一个数组,并且每次尝试编写数组都会创建一个包含数据的新数组从旧的数组中,修改新数组,并将修改后的数组存储到该字段。 请注意,即使数组本身是一个可变类型,每个存储在字段中的数组实例都是有效的不可变的,因为任何可能会使其变异的代码都无法访问它。

请注意,场景#1在泛型类型中非常常见; 例如,有一个字典的“值”是可变对象的身份是很常见的; 枚举该字典将返回KeyValuePair的实例,其Value字段包含该可变类型。

场景#2不太常见。 没有办法告诉编译器除了属性设置器之外的结构方法将修改结构,因此在只读上下文中应禁止它们的使用; 一个可以有一个行为类似于List<T> ,但是具有值语义,并且包含一个Add方法,但是尝试在只读结构实例上调用Add会产生伪代码而不是编译器错误。 此外,这种结构上的变异方法和属性设定器通常表现得相当差。 当这些结构作为一个不可变的包装器存在于其他可变类中时,它们可能是有用的; 如果这样的结构永远不会被装箱,那么性能往往比一个类好。 如果只装箱一次(例如通过铸造到接口类型),性能通常可以与一个类别相比。 如果重复加框,性能可能比一类差。

这可能不是推荐的做法:请参阅http://msdn.microsoft.com/en-us/library/ms229017(VS.85).aspx

引用类型在堆上分配,内存管理由垃圾收集器处理。

值类型在堆栈或内联中分配,并在超出范围时释放。

通常,值类型分配和释放更便宜。 但是,如果它们用于需要大量装箱和拆箱的场景,则与参考类型相比,它们的性能很差。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2025 STACKOOM.COM