Страницы

Поиск по вопросам

четверг, 11 октября 2018 г.

Анонимные типы в c# и их особенности?

Начал изучать анонимные типы в C#. Автор приводит пример синтаксиса анонимного типа var instance = new { Name = "Alex", Age = 27 }; и предлагает последовательно — шаг за шагом добавить на эту строку дополнительные элементы синтаксиса, чтобы данная строк стала более узнаваемая "читаемая" для нас (напоминаю: автор это делает т.к пример и весь курс — учебный) т.е. превратив выше приведенную строку в
var instance = new MyClass() { Name = "Alex", Age = 27 };
говоря, что мы добавили имя конструктора по умолчанию и круглые скобки для приема аргументов конструктора, и тут же демонстрируеь, что добавляя это — студия предлагает сгенерировать нам свойства для Age и для Name в классе MyClass(класс он создал сам — опять же для примера, но сказал, что в анонимных типах при генерации свойств класс также создаётся автоматически). В классе сгенерировались автореализуемые свойства
Но автор сказал, что они должны быть только для чтения, т.е. в (ну в данном случае посто нужно убрать set — ведь студия генерировала свойства как для обычных полей класса когда мы дописала имя конструктора по умолчаню после ключевого слова new). И это подводит меня к вопросу №3 (вопросы №1 и №2 представлены ниже). Если автогенерируемые, автореализуемые свойства в также автоматически созданном классе (назовем его MyClass) только для чтения, то каким образом в блоке инициализатора на строке var instance = new { Name = "Alex", Age = 27 }; мы вообще можем присваивать этим полям значения? Вот скриншот первого примера, в котором меня интересует комментарий, в котором у меня и возникают все эти вопросы.
Вопрос №1: т.е. компилятор каждый раз создает новое имя для анонимного типа, который в свою очередь является ссылочным типом?
Вопрос №2: т.е. приложение не может обращаться ссылке (т.к. тип ссылочный) к новому имени созданному компилятором.
Вопрос №3 представлен вначале.


Ответ

Да, так задумано. Компилятор создаёт имя наподобие <>f__AnonymousType0, которое невозможно использовать из C#. К нему невозможно получить доступ просто так, потому что такие имена нельзя использовать в C#. Но вы легко можете увидеть это имя при помощи рефлексии:
class Program { public static void Main() { var o = new { x = 5, y = 8 }; foreach (var t in Assembly.GetExecutingAssembly().GetTypes()) Console.WriteLine(t.Name); } }
выдаёт
<>f__AnonymousType0`2 Program Settings
(`2 означает, что класс на самом деле является generic-классом по причинам, указанным здесь) Программа вполне может обращаться по ссылке к значениям этого типа. Просто она не может получить имя типа, чтобы, например, объявить тип возвращаемого значения. Обращение на чтение работает:
var o = new { x = 5, y = 8 }; // var необходим, т. к. мы не можем назвать имя Console.WriteLine(o.x); // обращение по ссылке Нет, присваивать свойствам анонимного типа нельзя. Они создаются вовсе без сеттера. На самом деле вот такой код:
var o = new { x = 5, y = 8 };
порождает (примерно) следующий класс:
[DebuggerDisplay("{ x = {x}, y = {y} }", Type = "")] public sealed class Anonymous { private readonly TX field_x; private readonly TY field_y;
public TX x { get { return field_x; } } public TY y { get { return field_y; } }
[DebuggerHidden] public Anonymous(PX x, PY y) { field_x = x; field_y = y; }
public override bool Equals(object value) { /* тут имплементация */ } public override int GetHashCode() { /* тут имплементация */ } public override string ToString() { /* тут имплементация */ } }
а ваш вызов превращается компилятором в следующее:
Anomymous o = new Anonymous(5, 8);
Вы видите, что на самом деле присвоения свойствам нету, а есть просто вызов конструктора. Поэтому в дальнейшем запись в эти же свойства невозможна.

Комментариев нет:

Отправить комментарий