Господа, подскажите, пожалуйста, по коду. Вот ради эксперимента набросал код, но не пойму, почему метод 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();
Комментариев нет:
Отправить комментарий