2013-09-11 6 views
2
interface I1 
{ 
} 
class ClassOfI1 : I1 
{ 
} 

interface I2 
{ 
    I1 ABC { get; set; } 
} 
class ClassOfI2 : I2 
{ 
    public ClassOfI1 ABC { get; set; } 
} 

Выдает следующую ошибку:класса вместо интерфейса неисправного

'ns.ClassOfI2' does not implement interface member 'ns.I2.ABC'. 'ns.ClassOfI2.ABC' cannot implement 'ns.I2.ABC' because it does not have the matching return type of 'ns.I1'.

Почему? (И есть ли способ обойти это? Я хочу ClassOfI1 там, а не только интерфейс.)

ответ

4

При реализации интерфейсов, то возвращаемые типы должны точно совпадать. C# не поддерживает ковариацию возвращаемого типа. Поэтому Ваша реализация должна быть:

class ClassOfI2 : I2 
{ 
    public I1 ABC { get; set; } 
} 

Даже если он, ваш код будет небезопасно, так как вы могли бы сделать:

public class Other : I1 { ... } 
I2 iface = new ClassOfI2(); 
iface.ABC = new Other(); 

Вы могли бы рассмотреть возможность использования дженериков:

interface I2<T> where T : I1 
{ 
    T ABC { get; set; } 
} 

class ClassOfI2 : I2<ClassOfI1> 
{ 
    public ClassOfI1 ABC { get; set; } 
} 
+0

Для любого, кто смотрит этот ответ, я принял его как ответ, но также отправил ответ с «обходным путем», чтобы получить желаемые результаты. – ispiro

+0

(@) Ли Спасибо за ваш ответ. Однако в вашем разделе о моем небезопасном коде есть опечатка - вы имели в виду '... Другое: I1 ...', правильно? – ispiro

+0

@ispiro - Да, это должно быть 'I1', извините. – Lee

1

Потому что ваш метод возвращает ClassOfI1 вместо I1! Он должен вернуть сам интерфейс. Позже вам разрешено возвращать конкретный класс (в данном случае ClassOfI1), но определение в реализации должно соответствовать таковому в интерфейсе! Так изменить код:

interface I1 
{ 
} 

class ClassOfI1 : I1 
{ 
} 

interface I2 
{ 
    I1 ABC { get; set; } 
} 

class ClassOfI2 : I2 
{ 
    public I1 ABC { get; set; } 
} 

и он должен работать.

Вы всегда можете использовать экземпляр ClassOfI1 в коде, как:

var c1 = new ClassOfI1(); 
var c2 = new ClassOfI2(); 
c2.ABC = c1; 
+0

Но это должно быть возможно заменить класс для интерфейса. Так же, как вы можете использовать 'List' вместо' IEnumerable'. – ispiro

+2

Не в этот момент - позже в какой-то момент кода да, вы coud do object.ABC = ClassOfI1Instance, но метод должен соответствовать определению интерфейса! – pasty

0

Вот способ для этого:

class ClassOfI2 : I2 
{ 
    ClassOfI1 _ABC; 
    public I1 ABC { get { return _ABC; } set { _ABC = (ClassOfI1)value; } } 
} 

Обратите внимание, что это приведет к исключению в случае, вызванном Ли в его ответе, но при использовании только с ClassOfI1 - он работает нормально.

0

Я только что видел this answer, и это похоже на правильный способ: общие интерфейсы.

Суть этого:

Марка ABC «s Type (в I2): Twhere T: I1

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