Определив этот интерфейс:
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();
Это имеет какое-либо отношение к интервалу, являющемуся типом значения? Если да, как я могу обойти эту ситуацию?
Спасибо
Да, это абсолютно связано с 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;
}
}
Это довольно неприятно: (