Страницы

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

вторник, 25 февраля 2020 г.

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

#c_sharp #net


Господа, подскажите, пожалуйста, по коду. Вот ради эксперимента набросал код, но
не пойму, почему метод 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. Но в таком случае приоритет выше
у параметра типа интерфейса, чем у типа объекта? Или я что-то не правильно понял? Подскажите,
пожалуйста.    


Ответы

Ответ 1



Вы встретились с различием между заявленным (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();

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

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