2009-06-07 2 views
3

учитывая следующее:Могу ли я реализовать интерфейс, используя подкласс в C#?

class A : B {} 

interface I 
{ 
B TheObject {get;set;} 
} 

я могу сделать это так или иначе?

class C : I 
{ 
public A TheObject {get;set;} 
} 

Обратите внимание, что интерфейс имеет базовый класс, а реализация имеет подкласс.

+0

Если бы это было возможно, это наверняка смутило будущих сопровождающих вашего кода. Каковы ваши намерения? Вероятно, вам следует реорганизовать, если вы столкнулись с этой проблемой. –

ответ

11

Дайте это попробовать

class C : I 
{ 
public A TheObject {get;set;} 
B I.TheObject 
{ 
    get { return A; } 
    set { A = value as A; } 
} 
} 

Вы, возможно, потребуется изменить B сеттер, в зависимости от ваших потребностей. Внедрение интерфейса таким образом имеет следующие последствия. При работе с переменной, напечатанной как C, вы не сможете получить доступ к B-объекту. Если вам нужно, вам нужно будет объявить переменную I и присвоить ее вашей переменной C var. Реализация I таким образом известна как явная реализация.

например

C c = new C(); 
A a = c.TheObject; // TheObject is an A 
I i = c; 
B b = i.TheObject; 
+0

Да, явная реализация - это путь IMHO –

+0

Работал идеально для меня. Я немного не понимаю, почему C# не считает классы как реализацию интерфейса, если у них есть свойство, которое является подклассом свойства интерфейса. – frodo2975

1

Нет, вы не можете. По крайней мере, не из-за возможности Covariance/Contravariance C# 4.0.

1

Nope. Компилятор будет жаловаться на несоответствие типов.

Кроме того, я собираюсь не согласиться с Полом: я не думаю, что отклонение поможет в вашем случае. Посмотрите, что Скит должен сказать о дисперсии here.

2

Вы не можете этого сделать, потому что возвращаемый тип реализации интерфейса должен совпадать. Но мои рассуждения о том, почему вы не можете этого сделать, были неправильными (как указано в комментариях). Вы должны соответствовать подписи, но вы можете вернуть новый А из С ...

public class C : I 
{ 
    public B TheObject { get { return new A(); } set {} } 
} 
+1

Я не совсем понимаю ваш пример. Не должно быть: A есть-a B, но B не является A? Кроме того, B должен быть Vehicle и A a Boat, я был бы Мобильным. Тогда другой класс D, самолет, который был бы Автомобилем, не может быть отнесен к TheObject, потому что он ожидает Лодку вместо транспортного средства, как заявлено в мобильном интерфейсе. Я что-то упускаю? –

+0

@ Ionut: Да, вы правы, мне нужно исправить. –

1

Нет, предположим следующее:

class D : B {} 

C c = new C(); 
c.TheObject = new D(); // error. D is not A, A is not D 

С выше классом я все еще могу использовать D с объектами, реализующих интерфейс I, но давайте предположим, что я хочу, чтобы установить TheObject свойство экземпляр C к экземпляру D. Я не могу, потому что D и A являются братьями и сестрами. Они оба наследуются от одного и того же класса, и все будет в порядке, так как они находятся в интерфейсе, но объявляют, что вы ожидаете, что компилятор задает A. Экземпляр A не является экземпляром D, но экземпляры A и D являются экземплярами B.

Это правило следует за Liskov Substitution Principle.

P.S. Я хочу поблагодарить Troels Knak-Nielsen за открытие моего ума об этой тонкости.

0

Что вы думаете о ковариации/контравариантности, но даже с C# 4.0 это не сработает. Он по-прежнему должен использоваться, если у вас есть только ссылка на интерфейс.

Геттер будет работать, поскольку A также является B, но сеттер не будет работать, поскольку реализация ожидает A, тогда как интерфейс позволяет вам установить объект TheObject на B. Как правило, возвращаемые значения могут быть подтипами , а аргументы могут быть базовыми типами с ковариацией/контравариантностью. Но только в C# 4.0.

0

компилируется:

class B { } 

class A : B { } 

interface I<T> where T : B 
{ 
    T TheObject { get; set; } 
} 

class C : I<A> 
{ 
    public A TheObject { get; set; } 
} 

Но я полагаю, что это не то, что вы хотите?

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