Comments 62
Любому двоичному коду .NET может быть сопоставлен внешний конфигурационный файл XML. Этот файл располагается в том же каталоге, и имеет такое же имя с добавленным в конце словом .CONFIG;
Что вы хотели этим сказать?
+1
8 пункт — неправда. Запрос выполняется, если он возвращает скаляр(Count, Sum, First...). Даже если на нем вызвать foreach (то есть, выполнить GetEnumerator()) он будет выполнен так лениво, как только можно. То есть, такое выражение не выполнится сразу:
var s = from f in Foo()
group f by f%2;
+5
Если быть точным, то выполнено оно будет лениво, однако для получения второй группы нужно будет проитерировать всю исходную последовательность.
0
Максимальная ленивость никак не поможет, если мы упорядочиваем бесконечную коллекцию.
0
Многое в статье — просто цитаты из Рихтера.
И про пункт 20 — можно поставить бряк на автосвойство. В 2015 студии это можно даже сделать мышкой.
И про пункт 20 — можно поставить бряк на автосвойство. В 2015 студии это можно даже сделать мышкой.
+5
Как быстро в рантайме найти петли потоков (dead-locks)?
— !dlk
Не очень понятно, что вы имели в виду.
+1
Мне статья понравилась, но есть замечание по терминологии в 1 пункте
Также мне интересно, есть ли у разработчиков понимание, почему один и тот же метод у разных экземпляров класса в разных потоках не пересекается с другими и не меняет их значения, ведь по сути инструкции метода не дублируются?
Объекты содержат в себе статические поля и все методы. Экземпляры содержат только не статические поля. Это значит, что методы не дублируются в каждом экземпляре, и здесь применяется паттерн Flyweight.Есть понятие («класс») и есть понятие («экземпляр класса», что по сути == «объект»). Используя такие термины, никогда не возникнет путаницы при изучении нового языка.
Также мне интересно, есть ли у разработчиков понимание, почему один и тот же метод у разных экземпляров класса в разных потоках не пересекается с другими и не меняет их значения, ведь по сути инструкции метода не дублируются?
0
Также мне интересно, есть ли у разработчиков понимание, почему один и тот же метод у разных экземпляров класса в разных потоках не пересекается с другими и не меняет их значения, ведь по сути инструкции метода не дублируются?
Я думаю не у всех =) Это уже относится к более фундаментальным знаниям (многопоточность в ОС, стек, регистры процессора, контекст потока и т.д.), а не напрямую к C#.
А в MSIL у методов экземляра есть неявный параметр this, что и позволяет работать с конкретным объектом.
Когда this == null: невыдуманная история из мира CLR
0
В целом статься получилась довольно сумбурной и содержит довольно много ошибок. Возможно автор злоупотреблял переводчиком или недостаточно понимает описываемые механизмы, но в любом случае статью нужно серьезно переработать.
Из ошибок которые сразу бросились в глаза это п.35 — VolatileWrite, VolatileRead — это не атомарные операции, по пункту Б — я даже не знаю как это написать, но в целом весь пункт сплошная ошибка. В англоязычной литературе взаимным запиранием называется мьютекс (Mutual Exclusion). Interlocked — класс предоставляет набор атомарных операций и не имеет ничего общего с мьютексом.
п.30 — написано не имеет отношения к ковариации и контравариации msdn.microsoft.com/ru-ru/library/dd799517(v=vs.110).aspx
Из ошибок которые сразу бросились в глаза это п.35 — VolatileWrite, VolatileRead — это не атомарные операции, по пункту Б — я даже не знаю как это написать, но в целом весь пункт сплошная ошибка. В англоязычной литературе взаимным запиранием называется мьютекс (Mutual Exclusion). Interlocked — класс предоставляет набор атомарных операций и не имеет ничего общего с мьютексом.
п.30 — написано не имеет отношения к ковариации и контравариации msdn.microsoft.com/ru-ru/library/dd799517(v=vs.110).aspx
+8
Не использовал переводчик при прочтении книги написанной на Русском языке.
п. 30 дополнил примерами, он правильный.
п. 30 дополнил примерами, он правильный.
0
По умолчанию обобщенные типы инвариантны. Еще обобщенные классы называют открытыми, в рантайме они закрываются конкретными типами «int», «string», например. И это разные типы, статические поля в них будут тоже разными.Какое отношение выделенное предложение имеет к ковариантности, контрвариантности или инвариантности?
0
все еще не правильный, возможность использования наследника вместо указанного типа не есть «преобразование в одну сторону». Преобразование типов возможно вообще без наследования например.
Возможно у вас проблемы с терминологией, но в нашем деле это очень важный аспект и нужно очень тщательно подбирать слова для описания процессов, особенно на русском.
Возможно у вас проблемы с терминологией, но в нашем деле это очень важный аспект и нужно очень тщательно подбирать слова для описания процессов, особенно на русском.
+1
Местами бред полный.
У структурных типов и примитивных (byte,int,long...) нет блока синхронизации
Исключения медленно работают, т.к. происходит переход в режим ядра.
в) !DEBUG == RELEASE (на всякий случай).
31) Методы расширения
…
А это реализация паттерна Visitor в .Net.
+3
Местами бред полный.
У структурных типов и примитивных (byte,int,long...) нет блока синхронизации
Я конечно не специалист, но разве у неупакованных ссылочных типов есть индекс блока синхронизации? По-моему как раз у них его и нет.
Safe Thread Synchronization
Правда тут ссылка на того же Рихтера, из чьей книги автор и взял половину «заметок».
0
Я конечно не специалист, но разве у неупакованных ссылочных типов есть индекс блока синхронизации? По-моему как раз у них его и нет.
Вы скорее всего опечатались, механизм упаковки/распаковки существует только для value type.
У структурных типов и примитивных (byte,int,long...) нет блока синхронизации
У value type нет слова заголовка объекта, у reference type (в том числе упакованных value type) он есть — это основа основ, которую, я думал, знают все.
Исключения медленно работают, т.к. происходит переход в режим ядра.
Формально да, это так. Хотя определение «медленно» для разных задач разное, так что нужно просто сказать что происходит переключение контекста потока.
0
При обработке исключения происходит серия переходов managed-unmanaged. Но сами такие переходы не страшны. К примеру, по два таких перехода происходит на каждый вызов делегата, если верить отладчику студии. Означает ли это, что делегатов надо избегать?Исключения медленно работают, т.к. происходит переход в режим ядра.
Формально да, это так. Хотя определение «медленно» для разных задач разное, так что нужно просто сказать что происходит переключение контекста потока.
Исключения работают медленно, главным образом, из-за сбора StackTrace. Чтобы не потерять информацию, стек надо собрать еще перед переходом в блок catch — то есть в тот момент, когда не ясно, понадобится ли он вообще.
Но при чем тут вообще режим ядра?
+3
Но при чем тут вообще режим ядра?
На сколько я знаю механизм обработки исключений в windows, требует перевода процессора в режим ядра (kernel mode), т.к. диспетчер исключений обращается системной памяти.
А по поводу делегатов я к сожалению не могу ничего сказать, я не знаю как они работаю внутри, но на сколько я понимаю делегаты не требуют обращения за пределы виртуальной памяти процесса, поэтому для их работы перевод процессора в режим ядра врятли происходит.
0
Э… зачем? Какая секретная информация хранится в системной памяти?
0
Некоторые исключения система обрабатывает сама, собственно обработчик хранится в системной памяти.
Например используемый при отладке breakpoint вызывает исключение, которое ОС обрабатывает вызывая отладчик.
Например используемый при отладке breakpoint вызывает исключение, которое ОС обрабатывает вызывая отладчик.
0
Вы сейчас путаете аппаратные исключения, то есть прерывания, сгенерированные самим процессором — и исключения языков программирования, которые обрабатываются целиком в пользовательском режиме.
0
Я их не путаю, у аппаратных исключений в отличие от программных просто другой источник, но механизм обработки в общем-то такой же.
Я не большой специалист в этих вопросах и видимо моих знаний недостаточно чтобы объяснить этот механизм. За более подробной информацией могу посоветовать посмотреть книгу Windows Internals глава Диспечеризация исключений.
Я не большой специалист в этих вопросах и видимо моих знаний недостаточно чтобы объяснить этот механизм. За более подробной информацией могу посоветовать посмотреть книгу Windows Internals глава Диспечеризация исключений.
0
Не знаю, что в этой книге понимается под программными исключениями — но в этой главе пишется про исключительные ситуации, генерируемые железом. Про исключения, генерируемые вот так:
throw new Exception()
— там нет ни слова.0
>>Я не большой специалист в этих вопросах
Это видно. Эксепшны в дотнете сугубо user-mode. И да, в процессоре нет kernel mode. Там ring0.
Это видно. Эксепшны в дотнете сугубо user-mode. И да, в процессоре нет kernel mode. Там ring0.
0
Прочитал ваше сообщение, даже засомневался, отыскал в книге этот пункт, нашел в статью в msdn, как еще одно подтверждение перехода в режим ядра.
1) "Я говорил об ущербе производительности, потому что, несмотря на свободу исключений в .NET, внутри они реализуются через SEH. Если хотите это проверить, отладьте приложение .NET, используя отладку в неуправляемом режиме (native mode–only debugging), — вы увидите те же первые случаи исключения при инициации вашего исключения. Это подразумевает переход в режим ядра при каждом исключении. Идея, повторяю, в том, чтобы инициировать исключения при ошибках, а не в нормальном ходе выполнения программы."
2) «Actually, .NET exceptions are implemented in terms of SEH exceptions, which means that they do go on a trip through kernel mode. See blogs.msdn.com/cbrumme/archive/2003/10/01/51524.aspx3 for Chris Brumme's explanation.»
С такими отзывами, я раз 10 перечитаю эти заметки, спасибо!
1) "Я говорил об ущербе производительности, потому что, несмотря на свободу исключений в .NET, внутри они реализуются через SEH. Если хотите это проверить, отладьте приложение .NET, используя отладку в неуправляемом режиме (native mode–only debugging), — вы увидите те же первые случаи исключения при инициации вашего исключения. Это подразумевает переход в режим ядра при каждом исключении. Идея, повторяю, в том, чтобы инициировать исключения при ошибках, а не в нормальном ходе выполнения программы."
2) «Actually, .NET exceptions are implemented in terms of SEH exceptions, which means that they do go on a trip through kernel mode. See blogs.msdn.com/cbrumme/archive/2003/10/01/51524.aspx3 for Chris Brumme's explanation.»
С такими отзывами, я раз 10 перечитаю эти заметки, спасибо!
0
Нашел эту статью в открытом доступе (hint: надо стереть тройку в конце ссылки). Сделал поиск по ключевому слову «kernel». Не нашел утверждений о том, что любое исключение SEH безусловно проходит через ядро.
Вот самое близкое из найденного:
Откуда вообще пошло гулять по инету утверждение о том, что любое исключение SEH проходит через ядро ОС?
Вот самое близкое из найденного:
Probably take a trip through the OS kernel. Often take a hardware exception.Но тут говорится о возможном проходе через ядро — в случае использования отладчиков, профайлеров и прочих инструментов, которые при нормальной работе приложения отключены.
Откуда вообще пошло гулять по инету утверждение о том, что любое исключение SEH проходит через ядро ОС?
0
В книге могла быть ошибка перевода. Спорные моменты требуют нескольких независимых источников.
Блог надо прочитать целиком, не Испанский ведь.
Блог надо прочитать целиком, не Испанский ведь.
0
Лично мне достаточно других источников. Не помню название, но была какая-то переведенная книга именно про SEH. Стоит сейчас где-то в шкафу у бабушки.
Если кто-нибудь найдет в первоисточниках информацию, опровергающую мои утверждения — буду благодарен. Пока что доказательств я не вижу (приведенная в пункте 2 цитата — не первоисточник, потому что сама ссылается на другой источник).
Если кто-нибудь найдет в первоисточниках информацию, опровергающую мои утверждения — буду благодарен. Пока что доказательств я не вижу (приведенная в пункте 2 цитата — не первоисточник, потому что сама ссылается на другой источник).
0
Самое смешное в этом диалоге то что мы в поисках ответа не подумали о том что бы запустить отладчик поддерживающий ring 0 и проверить это собственными руками, а не ссылаться вслепую на авторитетов.
0
Достаточно отладчика, поддерживающего перехват системных вызовов: не требуется отлаживать ядро, достаточно зафиксировать факт обращения к нему (ну и, конечно же, надо потом как-то проверить, что это обращение не было вызвано самим фактом отладки).
К сожалению, я не знаю ни одного отладчика, кроме отладчика Студии. И даже в отладчике Студии не знаю кнопки, позволяющей хотя бы переключиться в режим дизассемблера (обычно у меня стоит обратная задача — выключить этот чертов режим, так так, чтобы он не включался автоматически). Но это не означает, что я не подумал о проверке! Просто результатом этих дум был вывод о том, что для меня такой повод сейчас непосилен :)
К сожалению, я не знаю ни одного отладчика, кроме отладчика Студии. И даже в отладчике Студии не знаю кнопки, позволяющей хотя бы переключиться в режим дизассемблера (обычно у меня стоит обратная задача — выключить этот чертов режим, так так, чтобы он не включался автоматически). Но это не означает, что я не подумал о проверке! Просто результатом этих дум был вывод о том, что для меня такой повод сейчас непосилен :)
0
Вот еще ссылка в тему blog.codinghorror.com/understanding-user-and-kernel-mode.
написал простой тест — в бесконечном цикле создаем исключение/пробрасываем/ловим — в ProcessExplorer-е
Kernel Time стабильно растет. Если в тесте оставить только создание класса исключения — Kernel Time не изменяется (win7, x64).
написал простой тест — в бесконечном цикле создаем исключение/пробрасываем/ловим — в ProcessExplorer-е
Kernel Time стабильно растет. Если в тесте оставить только создание класса исключения — Kernel Time не изменяется (win7, x64).
0
Здорово.
0
еще немного поиcследовал вопрос:
1. в предыдущем эксперименте у меня стояла галочка Prefer32Bit, т.е. процесс из под wow64 был запущен. Если ее убрать, то время в ядре становится меньше гораздо, но все равно с работой программы продолжает расти
2. по стекам ProcessExplorer-а видно, что throw замыкается на RaiseException — стандартную
API функцию для генерации SEH-вских эксепшнов.
3. обработка SEH-вских фреймов (как и описано в вышеприведенных статьях) происходит в два
этапа — вначале RtlDispatchException ищет обработчик выше по стеку, затем этот обработчик вызывает RtlUnwind для снятия со стека всего лишнего (EXCEPTION_REGISTRATION-ов/активаций функций).
4. судя по частично доступным в сети сорцам винды 2000, единственное место, которое обращается
в ядро в этой схеме — это переход из RtlUnwind на найденный фрейм через системный сервис ZwContinue.
1. в предыдущем эксперименте у меня стояла галочка Prefer32Bit, т.е. процесс из под wow64 был запущен. Если ее убрать, то время в ядре становится меньше гораздо, но все равно с работой программы продолжает расти
2. по стекам ProcessExplorer-а видно, что throw замыкается на RaiseException — стандартную
API функцию для генерации SEH-вских эксепшнов.
3. обработка SEH-вских фреймов (как и описано в вышеприведенных статьях) происходит в два
этапа — вначале RtlDispatchException ищет обработчик выше по стеку, затем этот обработчик вызывает RtlUnwind для снятия со стека всего лишнего (EXCEPTION_REGISTRATION-ов/активаций функций).
4. судя по частично доступным в сети сорцам винды 2000, единственное место, которое обращается
в ядро в этой схеме — это переход из RtlUnwind на найденный фрейм через системный сервис ZwContinue.
0
Есть WRK v1.2 (официально доступный исходник)
The Windows Research Kernel v1.2 contains the sources for the core of
the Windows (NTOS) kernel and a build environment for a kernel that will run on
x86 (Windows Server 2003 Service Pack 1) and
amd64 (Windows XP x64 Professional)
A future version may also support booting WRK kernels on Windows XP x86 systems,
but the current kernels will fail to boot due to differences in some shared
structures.
The NTOS kernel implements the basic OS functions
for processes, threads, virtual memory and cache managers, I/O management,
the registry, executive functions such as the kernel heap and synchronization,
the object manager, the local procedure call mechanism, the security reference
monitor, low-level CPU management (thread scheduling, Asynchronous and Deferred
Procedure calls, interrupt/trap handling, exceptions), etc.
Смотрел по курсу Intuit.ru «Введение во внутреннее устройство Windows».
Очень интересно, правда забыл уже почти все.
The Windows Research Kernel v1.2 contains the sources for the core of
the Windows (NTOS) kernel and a build environment for a kernel that will run on
x86 (Windows Server 2003 Service Pack 1) and
amd64 (Windows XP x64 Professional)
A future version may also support booting WRK kernels on Windows XP x86 systems,
but the current kernels will fail to boot due to differences in some shared
structures.
The NTOS kernel implements the basic OS functions
for processes, threads, virtual memory and cache managers, I/O management,
the registry, executive functions such as the kernel heap and synchronization,
the object manager, the local procedure call mechanism, the security reference
monitor, low-level CPU management (thread scheduling, Asynchronous and Deferred
Procedure calls, interrupt/trap handling, exceptions), etc.
Смотрел по курсу Intuit.ru «Введение во внутреннее устройство Windows».
Очень интересно, правда забыл уже почти все.
0
Кто такие «неупакованные ссылочные типы»? :) Наверное, речь шла о неупакованных значимых типах. Разумеется, у них такого индекса нет. Но такой индекс есть, к примеру, у упакованных значимых типов!
Но вообще-то, когда я писал свой комментарий, я думал совсем о другом. Дело в том, что
Но вообще-то, когда я писал свой комментарий, я думал совсем о другом. Дело в том, что
string
— это тоже примитивный тип! Но будет ли кто-то спорить с тем, что у него есть все необходимое для синхронизации?+1
mayorovp, a_mastrakov
Да. Я очепятался. Правда очень грубый косяк. К вечеру на работе уже голова болит. Я и тот комментарий не с первого раза смог сформулировать. Несколько раз переписывал.
Да. Я очепятался. Правда очень грубый косяк. К вечеру на работе уже голова болит. Я и тот комментарий не с первого раза смог сформулировать. Несколько раз переписывал.
0
Дело в том, что string — это тоже примитивный тип!
Я может быть чего-то не знаю — но всегда считал string — указательный неизменяемый тип. Так по крайней мере говорится в MSDN: https://msdn.microsoft.com/en-us/library/system.type.isprimitive(v=vs.100).aspx.
0
1) У структурных типов и примитивных (byte,int,long...) нет блока синхронизации, который присутствует у объектов в управляемой куче на ряду с ссылкой.
Если не читать то что после запятой, то да, такое допущение будет ошибочным.
2) Методы расширения — прочитайте паттерн Visitor в бесплатной книге itvdn.com/ru/patterns (которая идет как дополнение к первоисточнику GOF).
Я не сам это придумал, это ведь заметки а не мои домыслы.
Если не читать то что после запятой, то да, такое допущение будет ошибочным.
2) Методы расширения — прочитайте паттерн Visitor в бесплатной книге itvdn.com/ru/patterns (которая идет как дополнение к первоисточнику GOF).
Я не сам это придумал, это ведь заметки а не мои домыслы.
0
1) У структурных типов и примитивных (byte,int,long...) нет блока синхронизации, который присутствует у объектов в управляемой куче на ряду с ссылкой.Не вижу разницы, если честно.
Если не читать то что после запятой, то да, такое допущение будет ошибочным.
2) Методы расширения — прочитайте паттерн Visitor в бесплатной книге itvdn.com/ru/patterns (которая идет как дополнение к первоисточнику GOF).Спасибо, я знаю что такое паттерн Visitor. Не вижу, как в его реализации могут помочь методы расширения, которые являются всего лишь обычными статическими методами.
Я не сам это придумал, это ведь заметки а не мои домыслы.
+1
1) Enum структурный тип, но не примитивный. Согласен что предложение не самое удачное (спасибо что указали), но это не делает его не правильным.
2) Цитата из бесплатной книги (ссылка на нее выше):
«Паттерн Visitor – позволяет единообразно обойти набор элементов с разнородными интерфейсами (т.е. набор объектов разных классов не приводя их к общему базовому типу), а также позволяет добавить новый метод (функцию) в класс объекта, при этом не изменяя сам класс этого объекта.»
Я не имею такой же квалификации как автор этих слов, но согласен с ним.
2) Цитата из бесплатной книги (ссылка на нее выше):
«Паттерн Visitor – позволяет единообразно обойти набор элементов с разнородными интерфейсами (т.е. набор объектов разных классов не приводя их к общему базовому типу), а также позволяет добавить новый метод (функцию) в класс объекта, при этом не изменяя сам класс этого объекта.»
Я не имею такой же квалификации как автор этих слов, но согласен с ним.
0
Тот факт, что метод расширения иногда решает ту же самую задачу, которую можно было бы решить паттерном Visitor, не делает из него реализацию этого паттерна.
0
> Паттерн Visitor… позволяет добавить новый метод (функцию) в класс объекта, при этом не изменяя сам класс этого объекта.
Добавить новый _полимофный_ метод в класс объекта. Extension-методы — это просто синтаксический сахар (языковой, не CLR) для _вызова_ функций. Языки, где нет этого сахара, просто используют другой синтаксис вызова. Паттерн Visitor к синтаксису того или иного языка не имеет никакого отношения. К объекту какого класса будет применён extension-метод — это определяется во время компиляции. К объекту какого класса будет применятся навешенный с помощью Visitor'а «метод» — это определяется во время исполнения, так как в compile time этой информации в общем случае нет.
Добавить новый _полимофный_ метод в класс объекта. Extension-методы — это просто синтаксический сахар (языковой, не CLR) для _вызова_ функций. Языки, где нет этого сахара, просто используют другой синтаксис вызова. Паттерн Visitor к синтаксису того или иного языка не имеет никакого отношения. К объекту какого класса будет применён extension-метод — это определяется во время компиляции. К объекту какого класса будет применятся навешенный с помощью Visitor'а «метод» — это определяется во время исполнения, так как в compile time этой информации в общем случае нет.
0
Структура передает свою копию в метод, Класс передает копию своей ссылки. А вот когда мы используем ключевое слово REF — структура передает указатель на себя, а класс передает свою исходную ссылку.
А я всегда считал что ref для ссылочных типов передает указатель на ссылку на объект.
+1
> В то же время, объявляя тип возвращаемого методом объекта, желательно выбирать самый сильный из доступных вариантов (пытаясь не ограничиваться конкретным типом). Например, лучше объявлять метод, возвращающий объект FileStream, а не Stream.
Да, с точки зрения сигнатуры функции, входные и выходные значения имеют разное направление вариантности. Но с точки зрения API библиотеки — это просто торчащие наружу типы. Если вы выберете конкретный тип для результата метода, то не сможете в новой версии библиотеки перейти при необходимости к более общему, это может сломать неподконтрольный клиентский код. Изменение в другую сторону от общего к частному не является ломающим изменением.
Например, пользователь вызывает ваш код:
`FileStream hisObject = MyApi.GetStream();`
Вы решили, что ваша реализация GetStream может возвращать не только FileStream, но и MemoryStream, так что вы изменили возвращаемое значение на Stream — и у пользователя сломается код. Этого не было бы проблемой, если бы вы изначально не обещали большего, чем Stream.
Наоборот, если вы начинали с сигнатуры `MyApi.GetStream(): Stream`, а потом решили специфицировать более конкретным типом (и заморозить его в API) и дать больший контроль пользователю, то изменение сигнатуры не сломает уже существующий клиентский код.
Да, с точки зрения сигнатуры функции, входные и выходные значения имеют разное направление вариантности. Но с точки зрения API библиотеки — это просто торчащие наружу типы. Если вы выберете конкретный тип для результата метода, то не сможете в новой версии библиотеки перейти при необходимости к более общему, это может сломать неподконтрольный клиентский код. Изменение в другую сторону от общего к частному не является ломающим изменением.
Например, пользователь вызывает ваш код:
`FileStream hisObject = MyApi.GetStream();`
Вы решили, что ваша реализация GetStream может возвращать не только FileStream, но и MemoryStream, так что вы изменили возвращаемое значение на Stream — и у пользователя сломается код. Этого не было бы проблемой, если бы вы изначально не обещали большего, чем Stream.
Наоборот, если вы начинали с сигнатуры `MyApi.GetStream(): Stream`, а потом решили специфицировать более конкретным типом (и заморозить его в API) и дать больший контроль пользователю, то изменение сигнатуры не сломает уже существующий клиентский код.
+2
В C# внутри типов, помеченных атрибутом [Serializable], не стоит определять автоматически реализуемые свойства. Дело в том, что имена полей, генерируемые компилятором, могут меняться после каждой следующей компиляции, что сделает невозможной десериализацию экземпляров типа.
Нашел эту цитату у Рихтера. Но не пойму, насколько и в каких случаях это может быть проблемой? За сколько-то лет работы ни разу с такой ошибкой не сталкивался. Куча сериализуемых классов.
Нашел эту цитату у Рихтера. Но не пойму, насколько и в каких случаях это может быть проблемой? За сколько-то лет работы ни разу с такой ошибкой не сталкивался. Куча сериализуемых классов.
0
Результат тестов.
Класс:
Имена остались прежними, но возможно Джеффри Рихтер встречал другие ситуации (иначе зачем он обратил на это внимание) или в компиляторе были изменения. У меня VS 2013, летом на 2015 :)
Класс:
[Serializable]
class Person
{
string FirstName { get; set; }
string SecondName { get; set; }
int Age { get; set; }
}
ILDASM.exe
Debug (first compile):
.field private int32 '<Age>k__BackingField'
.field private string '<FirstName>k__BackingField'
.field private string '<SecondName>k__BackingField'
Debug (second compile):
.field private int32 '<Age>k__BackingField'
.field private string '<FirstName>k__BackingField'
.field private string '<SecondName>k__BackingField'
Release (third compile):
.field private int32 '<Age>k__BackingField'
.field private string '<FirstName>k__BackingField'
.field private string '<SecondName>k__BackingField'
Имена остались прежними, но возможно Джеффри Рихтер встречал другие ситуации (иначе зачем он обратил на это внимание) или в компиляторе были изменения. У меня VS 2013, летом на 2015 :)
0
Да это-то понятно. Один и тот же компилятор генерирует одни и те же имена… Интереснее было бы сравнить разные компиляторы.
0
Проверил пункт «36) Поля класса».
1) Неправильно.
2) Правильно.
А так если у кого есть желание и VS не 2013, пусть выложат свои результаты по автосвойствам.
1) Неправильно.
class Car
{
private string _name = "car";
private int _speed = 15;
private int _sits = 5;
public Car()
{
}
public Car(string name)
{
this._name = name;
}
public Car(int speed)
{
this._speed = speed;
}
public Car(int speed ,int sits)
{
this._speed = speed;
this._sits = sits;
}
}
// Code size 43 (0x2b)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldstr "car"
IL_0006: stfld string ConsoleApplication1.Car::_name
IL_000b: ldarg.0
IL_000c: ldc.i4.s 15
IL_000e: stfld int32 ConsoleApplication1.Car::_speed
IL_0013: ldarg.0
IL_0014: ldc.i4.5
IL_0015: stfld int32 ConsoleApplication1.Car::_sits
IL_001a: ldarg.0
IL_001b: call instance void [mscorlib]System.Object::.ctor()
IL_0020: nop
IL_0021: nop
IL_0022: ldarg.0
IL_0023: ldarg.1
IL_0024: stfld string ConsoleApplication1.Car::_name
IL_0029: nop
IL_002a: ret
} // end of method Car::.ctor
// Code size 43 (0x2b)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldstr "car"
IL_0006: stfld string ConsoleApplication1.Car::_name
IL_000b: ldarg.0
IL_000c: ldc.i4.s 15
IL_000e: stfld int32 ConsoleApplication1.Car::_speed
IL_0013: ldarg.0
IL_0014: ldc.i4.5
IL_0015: stfld int32 ConsoleApplication1.Car::_sits
IL_001a: ldarg.0
IL_001b: call instance void [mscorlib]System.Object::.ctor()
IL_0020: nop
IL_0021: nop
IL_0022: ldarg.0
IL_0023: ldarg.1
IL_0024: stfld int32 ConsoleApplication1.Car::_speed
IL_0029: nop
IL_002a: ret
} // end of method Car::.ctor
// Code size 50 (0x32)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldstr "car"
IL_0006: stfld string ConsoleApplication1.Car::_name
IL_000b: ldarg.0
IL_000c: ldc.i4.s 15
IL_000e: stfld int32 ConsoleApplication1.Car::_speed
IL_0013: ldarg.0
IL_0014: ldc.i4.5
IL_0015: stfld int32 ConsoleApplication1.Car::_sits
IL_001a: ldarg.0
IL_001b: call instance void [mscorlib]System.Object::.ctor()
IL_0020: nop
IL_0021: nop
IL_0022: ldarg.0
IL_0023: ldarg.1
IL_0024: stfld int32 ConsoleApplication1.Car::_speed
IL_0029: ldarg.0
IL_002a: ldarg.2
IL_002b: stfld int32 ConsoleApplication1.Car::_sits
IL_0030: nop
IL_0031: ret
} // end of method Car::.ctor
2) Правильно.
class Car
{
private string _name;
private int _speed;
private int _sits;
public Car()
{
this._name = "car";
this._speed = 15;
this._sits = 5;
}
public Car(string name) : this()
{
this._name = name;
}
public Car(int speed) : this()
{
this._speed = speed;
}
public Car(int speed ,int sits) : this()
{
this._speed = speed;
this._sits = sits;
}
}
// Code size 17 (0x11)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void ConsoleApplication1.Car::.ctor()
IL_0006: nop
IL_0007: nop
IL_0008: ldarg.0
IL_0009: ldarg.1
IL_000a: stfld string ConsoleApplication1.Car::_name
IL_000f: nop
IL_0010: ret
} // end of method Car::.ctor
// Code size 17 (0x11)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void ConsoleApplication1.Car::.ctor()
IL_0006: nop
IL_0007: nop
IL_0008: ldarg.0
IL_0009: ldarg.1
IL_000a: stfld int32 ConsoleApplication1.Car::_speed
IL_000f: nop
IL_0010: ret
} // end of method Car::.ctor
// Code size 24 (0x18)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void ConsoleApplication1.Car::.ctor()
IL_0006: nop
IL_0007: nop
IL_0008: ldarg.0
IL_0009: ldarg.1
IL_000a: stfld int32 ConsoleApplication1.Car::_speed
IL_000f: ldarg.0
IL_0010: ldarg.2
IL_0011: stfld int32 ConsoleApplication1.Car::_sits
IL_0016: nop
IL_0017: ret
} // end of method Car::.ctor
А так если у кого есть желание и VS не 2013, пусть выложат свои результаты по автосвойствам.
0
Sign up to leave a comment.
Интересные заметки по C# и CLR