Вопрос о C# 4.0's ковариантность дженериков

Определив этот интерфейс:

public interface IInputBoxService<out T> {
    bool ShowDialog();
    T Result { get; }
}

Почему делает следующую работу кода:

public class StringInputBoxService : IInputBoxService<string> {
    ...
}

...

IInputBoxService<object> service = new StringInputBoxService();

и это не делает?:

public class IntegerInputBoxService : IInputBoxService<int> {
    ...
}

...

IInputBoxService<object> service = new IntegerInputBoxService();

Это имеет какое-либо отношение к интервалу, являющемуся типом значения? Если да, как я могу обойти эту ситуацию?

Спасибо

13
задан devoured elysium 28 April 2010 в 06:25
поделиться

1 ответ

Да, это абсолютно связано с int является типом значения. Универсальная дисперсия в C # 4 работает только со ссылочными типами. Это в первую очередь потому, что ссылки всегда имеют одно и то же представление: ссылка - это просто ссылка, поэтому CLR может использовать те же биты для чего-то, что, как она знает, является ссылкой на строку, что и для ссылки на объект. CLR может гарантировать безопасность кода и использовать собственный код, который знает только о IInputBoxService при передаче IInputBoxService - значение, возвращаемое из ] Результат будет репрезентативно совместимым (если такой термин существует!).

С int => объект должен быть бокс и т. Д., Поэтому вы не получите тот же код - это в основном приводит к искажению дисперсии.

РЕДАКТИРОВАТЬ: В спецификации C # 4.0 об этом говорится в разделе 13.1.3.2:

Назначение аннотаций дисперсии - обеспечить более мягкие (но все же безопасные по типу) преобразования в интерфейс. и типы делегатов. С этой целью определения неявных (§6.1) и явных преобразований (§6.2) использовать понятие конвертируемости по дисперсии, которое определяется следующим образом: Тип T преобразуется по дисперсии в тип T, если T - это либо интерфейс , либо тип делегата, объявленный с параметрами типа варианта T, и для каждого параметра типа варианта выполняется одно из следующих значений :

  • Xi является ковариантным и существует преобразование неявной ссылки или идентификатора из Ai в Bi

  • Xi является контравариантным и является неявной ссылкой или идентификатором преобразование существует из Bi в Ai

  • Xi инвариантно , и существует преобразование идентичности из Ai в Bi

Это не делает это ужасно очевидным, но в основном ссылочные преобразования существуют только между ссылочными типами, что оставляет только преобразования идентичности (т. е. от типа к самому себе).

Что касается обходных путей: я думаю, вам, по сути, придется создать свой собственный класс-оболочку. Это может быть очень просто:

public class Wrapper<T>
{
    public T Value { get; private set; }
    public Wrapper(T value)
    {
        Value = value;
    }
}

Это довольно неприятно: (

14
ответ дан 2 December 2019 в 00:31
поделиться
Другие вопросы по тегам:

Похожие вопросы: