Страницы

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

вторник, 14 мая 2019 г.

Обобщенный интерфейс, ковариантность

Господа, подскажите, пожалуйста, по коду. Вот ради эксперимента набросал код, но не пойму, почему метод GetNameObj возвращает объект типа a1, если ему как через конструктор, так и через параметр типа передают a2. Вот код: using System; interface a { T GetNameObj(); } class b : a { T t; public b(T o) { t = o; } public T GetNameObj() { Console.WriteLine(typeof(T).Name); return t; } } class a1 { } class a2 : a1 { } class c { static void Main() { a A = new b(new a2()); a2 A2 =(a2) A.GetNameObj(); //вот этот метод почему-то возвращает тип a1
} } Мне кажется, что единственным объяснением такого поведения является то, что методу без разницы, что я там передаю за тип данных в конструктор или параметр типа, ему главное, что в интерфейсной ссылке указан параметр типа a1. Но в таком случае приоритет выше у параметра типа интерфейса, чем у типа объекта? Или я что-то не правильно понял? Подскажите, пожалуйста.


Ответ

Вы встретились с различием между заявленным (compile-time) и реальным (run-time) типом. Объект, создаваемый конструктором new b(new a2()), имеет реальный тип b. Поскольку b является разновидностью (то есть, подтипом) a для любого T, то b есть разновидность a. Далее, a2 есть подтип a1, поэтому, вследствие ковариантности a<>, a есть подтип a. Поэтому возможно присвоить переменной A типа a ссылку на объект типа b Далее, рассмотрим объект, возвращаемый A.GetNameObj(). Поскольку A имеет заявленный тип a, возвращённый объект имеет заявленный тип a1. Реальный же тип этого объекта — a2, т. к. реальный тип A — b При компиляции для присвоения переменной A2 существенен лишь заявленный тип (компилятор в общем случае не знает, как будет реальный тип), поэтому код без приведения типов не скомпилируется. Тем не менее, приведение типов может привести объект к его реальному типу (но выяснится это лишь во время выполнения), поэтому код с приведением типов работает без выброса исключения. По вашему вопросу: ...методу без разницы что я там передаю за тип данных в конструктор или параметр типа, ему главное что в интерфейсной ссылке указан параметр типа a1. Но в таком случае приоритет выше у параметра типа интерфейса чем у типа объекта ? Для компилируемости кода важен лишь заявленный тип. В вашем случае важен заявленный тип переменной A, а не реальный тип объекта, который будет в эту переменную записан. Если бы вы заявили более сильный тип для переменной A, то приведение типов не понадобилось бы: a A = new b(new a2()); a2 A2 = A.GetNameObj();

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

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