2010-04-28 3 views
13

Определив этот интерфейс:Вопрос о C# 4.0-х дженериков ковариационной

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, являющемуся типом значения? Если да, то как я могу обойти эту ситуацию?

Благодаря

+0

Вы пробовали использовать Int32 – Strelok

+1

Нет, но от того, что мое понимание того, что это приведет к тому же ИНТ просто псевдоним?. Int32. –

ответ

14

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

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

EDIT: В спецификации C# 4.0 говорит, что это в разделе 13.1.3.2:

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

  • Си ковариантен и неявного ссылка или личность преобразования существует от Ai к Bi

  • Си контравариантны и неявное ссылки или идентичность преобразование существует с Bi к Ai

  • Сов инвариантны и преобразование идентичности существует от Ai к Bi

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

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

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

Это довольно неприятный, хотя :(

+0

Я думал, что это так, но я не могу найти ссылку. Знаете ли вы о какой-либо ссылке msdn, в которой упоминаются, что отклонения работают только со ссылочными типами? –

+0

Как насчет этого? Http: //blogs.msdn. com/csharpfaq/archive/2010/02/16/covariance-and-contravariance-faq.aspx - Используйте Ctrl + F, чтобы найти «Несколько важных правил для запоминания», и вы найдете запись. –

+0

Есть ли альтернатива ? Java определяет для всех примитивные типы ссылочных типов тоже, поэтому вместо того, чтобы что-то делать Я могу сделать что-то , что решит эту проблему. –