2013-03-22 16 views
1

Итак, у меня есть некоторый Java-код, который широко использует обобщения, которые компилируются просто отлично. Я портировали его на C# следующим образом: Дженерики, ковариация/контравариантность и т. Д.

interface IFoo1 { } 
interface IFoo2 { } 

interface IBar<T, K> 
    where T : IFoo1 
    where K : IFoo2 { 
    List<T> GetFoo1s(); 
    void AddAFoo1(T foo1); 

    List<K> GetFoo2s(); 
    void AddAFoo2(K foo2); 
} 

interface IBlip<T> 
    where T : IBar<IFoo1, IFoo2> { 
    T DoBlip(string input); 
    void DoBlip2(T input); 
} 

interface IConverter<T, K> 
    where T : IBar<IFoo1, IFoo2> 
    where K : IBar<IFoo1, IFoo2> { 
    K Convert(T input); 
} 

class FooA1 : IFoo1 { } 
class FooB1 : IFoo1 { } 

class FooA2 : IFoo2 { } 
class FooB2 : IFoo2 { } 

class BarA : IBar<FooA1, FooA2> { 
    public List<FooA1> GetFoo1s() { return null; } 
    public void AddAFoo1(FooA1 foo1) { } 
    public List<FooA2> GetFoo2s() { return null; } 
    public void AddAFoo2(FooA2 foo2) { } 
} 

class BarB : IBar<FooB1, FooB2> { 
    public List<FooB1> GetFoo1s() { return null; } 
    public void AddAFoo1(FooB1 foo1) { } 
    public List<FooB2> GetFoo2s() { return null; } 
    public void AddAFoo2(FooB2 foo2) { } 
} 

class BlipA : IBlip<BarA> { 
    public BarA DoBlip(string input) { return null; } 
    public void DoBlip2(BarA input) { } 
} 

class BlipB : IBlip<BarB> { 
    public BarB DoBlip(string input) { return null; } 
    public void DoBlip2(BarB input) { } 
} 

class ConverterImplementation : IConverter<BarA, BarB> { 
    public BarB Convert(BarA input) { 
     return null; 
    } 
} 

Когда я компилирую это, он жалуется, что, например, с ConverterImplementation, что Бара не может быть неявно преобразован в IBar. Наверное, есть кое-что, что я здесь принципиально не хватает. Может ли кто-то пролить свет на него? Благодарю.

+4

Сделайте поиск на C#, тигры и жирафы. Поверь мне в этом. –

+0

Для записи (и связанных страниц): http://stackoverflow.com/questions/4669858/simple-examples-of-co-and-contravariance и http://stackoverflow.com/questions/5881677/why-cant -i-cast-from-a-listmyclass-to-listobject – arcain

+0

Извините, если вопрос аналогичен другим. Этот пример казался немного более привлекательным, чем некоторые из других примеров, которые я видел там, поэтому было просто видно, есть ли у кого-нибудь какие-либо подсказки или трюки. Я думаю, что в конечном итоге мне просто придется перепроектировать мой API. –

ответ

4

Параметры типового типа по умолчанию не являются контравариантными или ковариантными, но могут быть сделаны одним или другим с помощью ключевых слов «in» и «out».

В случае IBar < T, K> оба параметра используются как входы и выходы, поэтому вы не можете сделать их контравариантными или ковариантными. Если вы реорганизовали его на два интерфейса, один из которых T используется только для ввода и K только для вывода, а тот, в котором T используется только для вывода, и K только для ввода, тогда вы можете сделать каждый тип параметра ковариантным или контравариантным по его использованию.

+0

Это то, чего я боялся. Я пропускаю стирание типа Java. –

2

IBar не является интерфейсом только для чтения, поэтому вы не можете достичь конвариантности на C#. Вам необходимо реорганизовать и извлечь только интерфейс для чтения, например. ReadOnlyBar, и сделать конвариантность на этом интерфейсе. (Отказ от ответственности - не эксперт по C#)

С другой стороны, подстановочный Java может превратить интерфейс только для чтения и convariant интерфейса, так что IBar<? extends Animal> только для чтения convariant и IBar<? extends Tiger> является подтипом этого. Это круто и все, пока ваш код не завален множеством подстановочных знаков.

+0

Хороший ответ Java-esque, спасибо. –

Смежные вопросы