Подтвердить что ты не робот

Можете ли вы иметь класс в структуре?

Возможно ли, что в С# есть Struct с переменной-членом, которая является типом класса? Если да, то где хранится информация, в стеке, куче или в обоих?

4b9b3361

Ответ 1

Да, вы можете. Указатель на переменную-член класса хранится в стеке с остальными значениями структуры, а данные экземпляра класса хранятся в куче.

Структуры могут также содержать определения классов как члены (внутренние классы).

Вот какой-то действительно бесполезный код, который, по крайней мере, компилируется и запускается, чтобы показать, что это возможно:

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;
            }
        }
    }
}

Ответ 2

Содержимое класса сохраняется в куче.

Ссылка на класс (который почти такой же, как указатель) сохраняется с содержимым структуры. Если содержимое структуры хранится, зависит от того, является ли она локальной переменной, параметром метода или членом класса, и была ли она помещена в ящик или захвачена закрытием.

Ответ 3

Если одно из полей структуры является типом класса, это поле будет либо содержать identity объекта класса, либо нулевое рефери. Если рассматриваемый объект класса является неизменным (например, string), сохранение его идентификатора также эффективно сохраняет его содержимое. Однако если объект класса является изменчивым, сохранение идентификатора будет эффективным средством хранения содержимого тогда и только тогда, когда ссылка никогда не попадет в руки какого-либо кода, который мог бы изменить его после его сохранения в поле.

Как правило, следует избегать сохранения изменяемых типов классов в структуре, если не применяется одна из двух ситуаций:

  • Что интересно, это, по сути, идентичность объекта класса, а не его содержимого. Например, можно определить структуру `FormerControlBounds`, которая содержит поля типа` Control` и `Rectangle`, и представляет "границы", которые элемент управления имел в какой-то момент времени, с тем чтобы иметь возможность позже восстановить контроль к его более ранней позиции. Целью поля "Контроль" было бы не сохранение копии состояния управления, а скорее идентификация элемента управления, положение которого должно быть восстановлено. Как правило, структура должна избегать доступа к любым изменяемым членам объекта, к которым она содержит ссылку, за исключением случаев, когда ясно, что такой доступ относится к текущему изменяемому состоянию рассматриваемого объекта (например, в `CaptureControlPosition` или` RestoreControlToCapturedPosition` или свойство ControlHasMoved.
  • Поле является `private`, единственные методы, которые его читают, для изучения его свойств, не подвергая объект самому внешнему коду, и единственные методы, которые его пишут, будут создавать новый объект, выполнять все из мутаций, которые когда-либо произойдут с ним, а затем сохранит ссылку на этот объект. Например, можно построить конструкцию `struct`, которая вела себя подобно массиву, но с семантикой значений, имея структуру, удерживающую массив в частном поле, и, всякая попытка написать массив, создает новый массив с данными из старого, изменить новый массив и сохранить измененный массив в это поле. Обратите внимание: несмотря на то, что сам массив будет изменяемым типом, каждый экземпляр массива, который когда-либо будет храниться в поле, будет эффективно неизменным, поскольку он никогда не будет доступен никаким кодом, который может его изменить.

Обратите внимание, что сценарий # 1 довольно распространен в общих типах; например, очень часто имеет словарь, чьи "значения" являются идентификаторами изменяемых объектов; перечисляя, что словарь вернет экземпляры KeyValuePair, чье поле Value содержит этот изменяемый тип.

Сценарий № 2 встречается реже. Нет никакого способа сообщить компилятору, что методы struct, отличные от свойств, будут модифицировать структуру, и их использование должно быть запрещено в контексте только для чтения; можно было бы иметь структуру, которая вела себя как List<T>, но с семантикой значений и включала метод Add, но попытка вызвать Add в экземпляре struct только для чтения создавала бы фиктивный код, а не ошибку компилятора, Кроме того, мутирующие методы и средства определения свойств на таких структурах, как правило, будут выполняться довольно плохо. Такие структуры могут быть полезны, когда они существуют как неизменяемая оболочка в классе, изменяемом иначе; если такая структура никогда не бывает в коробке, производительность часто будет лучше, чем класс. Если вставить только один раз (например, при нажатии на тип интерфейса), производительность в целом будет сопоставима с классом. Если вставить несколько раз, производительность может быть намного хуже, чем класс.