Вопрос

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

Это было полезно?

Решение

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

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

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

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

Другие советы

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

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

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

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

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

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

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

Вероятно, это не рекомендуемая практика для этого:видишь http://msdn.microsoft.com/en-us/library/ms229017 (ПРОТИВ 85).aspx

Ссылочные типы размещаются в куче, а управление памятью осуществляется сборщиком мусора.

Типы значений размещаются в стеке или встроены и освобождаются когда они выходят за пределы области видимости.

Как правило, типы значений дешевле выделять и освобождать.Однако, если они используются в сценариях, требующих значительного объема упаковки и распаковки, они работают хуже по сравнению с ссылочными типами.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top