Что происходит, когда Вы создаете экземпляр объекта, содержащего состояние в C#?

Я, я думаю хорошо при алгоритмическом программировании, если это - правильное слово? Я раньше играл с турбо Паскаля и 8 086 ассемблеров назад в 1980-х как хобби. Но только очень маленькие проекты и я действительно не выполнили ни в каком программировании 20ish годы с тех пор. Таким образом, я борюсь за понимание как тонущий пловец.

Таким образом, возможно, это очень niave вопрос, или я просто не имею никакого смысла вообще, но говорю, что у меня есть объект отчасти как это:

class Something : IDoer
{
    void Do(ISomethingElse x)
    {
         x.DoWhatEverYouWant(42);
    }
}

И затем я делаю

var Thing1 = new Something();
var Thing2 = new Something();

Thing1.Do(blah);
Thing2.Do(blah);

Thing1 = Thing2? "новый Что-то ()" создает что-нибудь? Или действительно ли это не очень отличающееся отличающийся от наличия статического класса, кроме я могу раздать его и выгрузить его и т.д.

"Делают" процедуру в том же месте в памяти и для Thing1 (вздор) и для Thing2 (вздор) объекты? Я имею в виду при выполнении его, делает это означает, что существует два Что-то. Процедуры или всего один?

8
задан liquorice 14 June 2010 в 12:19
поделиться

8 ответов

В памяти определенно есть два разных объекта. Каждый объект будет занимать 8 байтов в куче (по крайней мере, в 32-битных системах); 4 для синхроблока и 4 для дескриптора типа (который включает таблицу методов). Кроме данных о состоянии, определенных системой, в вашем случае нет других данных о состоянии, определяемых пользователем.

Есть единственный экземпляр кода для Something.Используйте метод . Указатель дескриптора типа, который содержит каждый объект, определяет местонахождение различных методов класса в среде CLR. Таким образом, хотя в памяти есть два разных объекта, они оба выполняют один и тот же код. Поскольку Something.Do был объявлен как метод экземпляра, ему будет передан указатель this , чтобы код мог изменять правильные члены экземпляра в зависимости от того, какой объект вызывал метод. . В вашем случае у класса Something нет членов экземпляра (и, следовательно, нет определяемого пользователем состояния), поэтому это не имеет значения, но все же происходит.

7
ответ дан 5 December 2019 в 05:44
поделиться

Концептуально Thing1 и Thing2 - это разные объекты, но существует только одна процедура Something.Do.

Среда выполнения .Net выделяет немного памяти каждому из создаваемых вами объектов - один блок для Thing1, а другой - для Thing2. Целью этого фрагмента памяти является хранение (1) состояния объекта и (2) адреса любых процедур, принадлежащих объекту. Я знаю, что у вас нет состояния, но среде выполнения все равно - она ​​по-прежнему хранит две отдельные ссылки на два отдельных фрагмента памяти.

Теперь ваш метод «Do» одинаков как для Thing1, так и для Thing2, только среда выполнения хранит в памяти только одну версию процедуры.

Выделенная память Thing1 включает адрес метода Do. Когда вы вызываете метод Do на Thing1, он ищет адрес своего метода Do для Thing1 и запускает метод. То же самое происходит с другим объектом Thing2. Хотя объекты разные, один и тот же метод Do вызывается как для Thing1, так и для Thing2.

Это сводится к тому, что Thing1 и Thing2 отличаются друг от друга тем, что имена «Thing1» и «Thing2» относятся к разным областям памяти. Содержимое этой памяти одинаково в обоих случаях - один адрес, указывающий на метод «Do».

Во всяком случае, это теория. Под капотом может происходить какая-то оптимизация (см. http://www.wrox.com/WileyCDA/Section/CLR-Method-Call-Internals.id-291453.html , если вы интересно), но для большинства практических целей я сказал, как все работает.

1
ответ дан 5 December 2019 в 05:44
поделиться

Вы должны создать 2 «пустых» объекта, для каждого объекта в куче будет выделено небольшое пространство.

Но метод «До» всегда в одном и том же месте, что не имеет ничего общего с отсутствием состояния. Код не хранится «в» классе / объекте. Есть только 1 фрагмент кода, соответствующий Do (), и у него есть «скрытый» параметр this , который указывает на экземпляр Something, на котором он был вызван.

4
ответ дан 5 December 2019 в 05:44
поделиться

Это два отдельных объекта; у них просто нет государства.

Рассмотрим этот код:

var obj1 = new object();
var obj2 = new object();

Console.WriteLine(object.ReferenceEquals(obj1, obj2));

Он выведет False .

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

В ответ на последнюю часть вашего вопроса: существует только один метод Do . Методы хранятся не для каждого экземпляра, а для каждого класса. Если подумать, было бы крайне расточительно хранить их по одному экземпляру. Каждый вызов метода Do для объекта Something на самом деле является одним и тем же набором инструкций; все, что отличается между вызовами от разных объектов, - это состояние базового объекта (если у класса Something изначально было какое-либо состояние).

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

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

// appears to be instance-specific, so you might think
// it would be stored for every instance
public void Do() {
    Do(this);
}

// is clearly static, so it is much clearer it only needs
// to be stored in one place
private static Do(Something instance) {
    // do whatever Do does
}

Интересное примечание: приведенный выше гипотетический «перевод» в значительной степени объясняет, как работают методы расширения: это статические методы, но, определяя свой первый параметр ключевым словом this , они внезапно выглядят как методы экземпляра.

12
ответ дан 5 December 2019 в 05:44
поделиться

Каждый ссылочный тип (Thing1, Thing2) указывает на другой физический адрес в основной памяти, поскольку они были созданы отдельно. В памяти указываются байты, используемые объектом, независимо от того, есть ли у него состояние или нет (у него всегда есть состояние, но есть ли у него объявленное / инициализированное состояние).

Если вы назначили ссылочный тип другому ссылочному типу (Thing2 = Thing1;), то это была бы та же часть памяти, которая использовалась бы двумя разными ссылочными типами, и не было бы никакого нового создания экземпляра.

0
ответ дан 5 December 2019 в 05:44
поделиться

Нет, это не одно и то же. Это два отдельных экземпляра класса Something . Они имеют идентичные экземпляры, вот и все.

5
ответ дан 5 December 2019 в 05:44
поделиться

Вещь1! = Вещь2
Это два разных объекта в памяти.

Код метода Do находится в одном месте для обоих объектов. Нет необходимости хранить две разные копии метода.

0
ответ дан 5 December 2019 в 05:44
поделиться

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

, так что теперь вы можете иметь несколько экземпляров одного и того же класса, работающих во время выполнения, обрабатывая всевозможные ситуации: D

что касается CLR, вы получаете фактически 2 отдельных экземпляра в памяти, каждый из которых содержит указатели на него, он очень похож на любой другой язык ООП, но нам не нужно на самом деле взаимодействовать с указателями, они переводятся так же, как не ссылочный тип, поэтому нам не нужно о них беспокоиться!

(в C # есть указатели, если вы хотите избавиться от ключевого слова [unsafe]!)

0
ответ дан 5 December 2019 в 05:44
поделиться
Другие вопросы по тегам:

Похожие вопросы: