Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save eterekhin/f1dd601568355a8b9b381d423b640463 to your computer and use it in GitHub Desktop.
Save eterekhin/f1dd601568355a8b9b381d423b640463 to your computer and use it in GitHub Desktop.

Упаковка это процесс помещения объекта из стека (значимого типа) в кучу, если поэтапно:

  1. Для объекта выделяется место в куче, это место для указателя на типовой объект и индекса синхронизации + длина значимого типа
  2. Происходит копирование объекта в выделенное место
  3. Возвращается ссылка на этот объект При распаковке выполняется меньше действий, только взятие адресов у полей структуры, чтобы в даньшей скопировать их в стек. Распаковкой называется именно взятие адресов, а не копирование, поэтому распаковка это более легкая операция.

Только при касте к интерфейсу можно изменить упакованный объект значимого типа

Альтернатива только распаковать его, изменить и снова упаковать но тогда старый объект останется в куче и будет собран сборщиком мусора, т.е память будет выделена дважды:

            var myStruct = new MyStruct {Name = "name"};
            var obj = (object) myStruct; // box
            var unBoxMyStruct = (MyStruct) obj; // unbox
            unBoxMyStruct.Name = "noname";
            var newobj = (object) unBoxMyStruct; //box
            Console.WriteLine(((MyStruct) obj).Name == "name"); //true
            Console.WriteLine(((MyStruct) newobj).Name == "noname"); //true

Но если структура реализует интерфейс IHasName можно сделать так:

            var myStruct = new MyStruct {Name = "name"};
            var obj = (object) myStruct; // box
            ((IHasName) obj).Name = "noname";
            Console.WriteLine(((MyStruct)obj).Name == "noname"); //true

При касте к интерфейсу упакованного объекта не происходит распаковки. Если же кастить значимый тип к интерфейсу происходит упаковка Таким образом только выполняя каст к интерфейсу можно изменить объект значимого типа

Когда у структуры вызывается базовый метод класса ValueType или Object - она упаковывается(почему?), но если она переопределяет виртуальный метод ValueType или Object, то упаковки не происходит, потому что компилятор понимает, что этот метод никто не может переопределелить (т.к нельзя унаследоватьс от структуры). Также если при переопределении вызывается метод базового класса ValueType или Object, происходит упаковка?

У структур хранящихся в стеке нет ссылки на базовый тип, но тем не менее они могут вызывать методы ValueType'а или Object'a (но при их вызове происходит упаковка). Упаковка происходит из-за того, что методы базовых классов ожидают, что this - это ссылка на объект, т.e ссылочный тип, т.е для того, чтобы методы базовых классов работали, необходимо, скастить упаковать вызываемые объекты, тем не менее если структура переопределяет эти методы и при этом не вызывает базовые - упаковка не происходит, потому что компилятор запечатывает эти методы, так , как будто это методы принадлежат типу в котором переопределены, это логично, потому что структура не может наследовать кому-либо. Таким образом при любом вызове базового метода классов ValueType или Object будет упаковка, при их переопределении и вызове - упаковки не будет Причем в IL коде вызова этих

Когда структура приводится к типу интерфейса она также упаковывается

Да, и дает возможность менять значения упакованного объекта, однако Рихтер непоощряет такой подход, поскольку считает, что структура должна служить только для хранения информации(быть неизменяемой), тогда проблем с упаковкой/распаковкой не возникнет

В чем разница между вызовом виртуального и обычного методов, если описать детально?

При вызове виртуального метода компилятору приходится смотреть на реальный тип объекта, т.е приходится подниматься к созданию объекта, и после этого по иерархии и искать самый "нижний"(в плане иерархии,метод). При вызове обычного метода компилятор просто смотрит на текущий тип объекта и вызывает его метод(Вернуться и дописать после прочтения 195 страниц)

Когда происходит упаковка и распаковка значимого типа?

Она может происходить тогда, когда объект приводится структура приводится к типу Object или ValueType или любому своему интерфейсу. Либо примитивный тип приводится к Object. Это может быть неожиданно, например:

          int t = 12;
          Console.WriteLine(t + "end");

В этом случае происходит упаковка типа int в тип object, а потом вызов метода Console.WriteLine(object o1,object o2);

Почему значимые переменные не могут использоваться из разных потоков?

Только у объектов в куче есть блок синхронизации, с которым взаимодействует инструкция lock, а значимые типы хранятся в стеке, который для каждого потока свой, и происходит просто заталкивание этой переменной в стек

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment