Подпишитесь на учетную запись как можно большего числа основных почтовых провайдеров (gmail / yahoo / hotmail / aol / etc). Если вы вносите изменения в свои электронные письма, либо переписываете, либо меняете код, отправляющий электронные письма, либо меняя свои почтовые серверы, и т.д., обязательно отправляйте тестовые сообщения всем своим учетным записям и убедитесь, что они не помечены как спам.
Вы задаете вопросы о деталях реализации , поэтому ответ будет зависеть от конкретной реализации. Давайте рассмотрим версию вашей программы, которая действительно компилируется:
class A { public int VarA; }
class X
{
static void Main(string[] args)
{
A a1 = new A();
a1.VarA = 5;
A a2 = a1;
a2.VarA = 10;
}
}
вот что происходит в Microsoft CLR 4.0, работающей под управлением C # 4.0, в режиме отладки.
На этом этапе указатель кадра стека был скопирован в регистр ebp:
Здесь мы выделяем динамическую память для нового объекта.
A a1 = new A();
mov ecx,382518h
call FFE6FD30
Это возвращает ссылку на объект кучи в eax. Мы сохраняем ссылку в слоте стека ebp-48, который является временным слотом, не связанным ни с каким именем. Помните, что a1 еще не инициализирован.
mov dword ptr [ebp-48h],eax
Теперь мы берем эту ссылку, которую мы только что сохранили в стеке, и копируем ее в ecx, который будет использоваться для указателя this на вызов ctor.
mov ecx,dword ptr [ebp-48h]
Теперь мы вызываем ctor.
call FFE8A518
Теперь мы снова копируем ссылку, хранящуюся во временном слоте стека, в регистр eax.
mov eax,dword ptr [ebp-48h]
А теперь мы копируем ссылку из eax в слот стека ebp-40, то есть a1.
mov dword ptr [ebp-40h],eax
Теперь мы должны загрузить a1 в eax:
a1.VarA = 5;
mov eax,dword ptr [ebp-40h]
Помните, что теперь eax - это адрес данных, выделенных в куче для объекта, на который ссылается a1. Поле VarA этого объекта занимает четыре байта в объекте, поэтому мы сохраняем в нем 5:
mov dword ptr [eax+4],5
Теперь мы делаем копию ссылки в слоте стека для a1 в eax, а затем копируем ее в слот стека для a2 , то есть EBP-44.
A a2 = a1;
mov eax,dword ptr [ebp-40h]
mov dword ptr [ebp-44h],eax
И теперь, как и следовало ожидать, мы снова получаем a2 в eax, а затем используем ссылку на четыре байта для записи 0x0A в VarA:
a2.VarA = 10;
mov eax,dword ptr [ebp-44h]
mov dword ptr [eax+4],0Ah
Итак, ответ на ваш вопрос заключается в том, что ссылки на объект хранятся в стек в трех местах: EBP-44, EBP-48 и EBP-40.Они хранятся в регистрах в eax и ecx. Память объекта, включая его поле, хранится в управляемой куче. Это все на x86 в отладочной сборке Microsoft CLR v4.0. Если вы хотите знать, как данные хранятся в стеке, куче и регистрах в какой-то другой конфигурации, это может быть совершенно иначе. Все ссылки могут храниться в куче или все в регистрах; стека может вообще не быть. Это полностью зависит от того, как авторы jit-компилятора решили реализовать семантику IL.
class X
{
A a1=new A(); // reference on the stack, object value on the heap
a1.VarA=5; // on the Heap- value type (Since it is inside a reference type)
A a2=a1; // reference on the stack, object value on the heap
a2.VarA=10; // on the Heap - value type (Since it is inside a reference type)
}
Строго говоря, это зависит от реализации. Обычно .NET-разработчик не должен заботиться об этом. Насколько мне известно, в реализации .NET от Microsoft переменные типов значений хранятся в стеке (когда они объявляются внутри метода), а данные объектов ссылочного типа размещаются в управляемой куче. Но помните, когда тип значения является полем класса, данные самого класса хранятся в куче (включая все поля типа значения). Следовательно, не смешивайте семантику (типы значений и ссылки типы) с правилами размещения. Эти вещи могут быть коррелированы, а могут и не быть.
Я думаю, у вас может быть небольшое недоразумение ...
Вообще говоря, ссылочные типы хранятся в куче, а типы значений / локальные переменные, как мне кажется (может ошибаться) пойти в стек. Однако ваши примеры A1.VarA и A2.VarA относятся к полю ссылочного типа, которое хранится вместе с объектом в куче ...
Для полного понимания этой темы прочитайте книгу Джеффа Рихтера CLR через C#
Вспомните чтение в C# in Depth :- Только локальные переменные (объявленные внутри метода) и параметр метода живут в стеке. Переменная экземпляра, как varA в вышеприведенном случае, живет в куче.
В этом случае a1.VarA будет в куче, поскольку пространство для него будет выделено, когда вы сделали A a1 = new A ()
.
Если вы просто выполните int i = 5;
в функции, которая будет помещена в стек, но, как вы явно указали, a1 должен был быть размещен в куче, тогда все типы значений, связанные с ним, будут помещены в куче
Я тоже новичок в C #. Ваш вопрос очень важный, я тоже об этом подумал. Во всей документации сказано, что значения складываются в стек, а ссылки идут в кучу, но, как сказали выше ребята, это только для кода внутри методов. На ступеньке обучения я понимаю, что весь программный код начинается внутри метода, который принадлежит экземпляру, принадлежащему куче. Таким образом, концептуально, стек не равен кучу, поскольку вся документация сбивает людей с толку. Механизм стека можно найти только в методе ...