2012-04-17 5 views
5

По некоторым причинам я сражаю реализовать свойство из общего интерфейса с помощью общего базового класса следующим образом:Generic Базового класс наследует от общего интерфейса

public interface IParent<TChild> where TChild : IChild 
{ 
    TChild Child { get; } 
} 

public interface IChild { } 

Тогда у меня есть базовый класс:

public class ParentBase<TChild> : IParent<TChild> where TChild : IChild 
{ 
    private TChild _child; 
    public ParentBase(TChild child) 
    { 
     this._child = child; 
    } 
    #region IParent<TChild> Members 

    public TChild Child 
    { 
     get { return _child; } 
    } 

    #endregion 
} 

Теперь у меня есть новый родительский Производная и дочерний объект следующим образом:

public class MyChild : IChild { } 

public class MyParent : ParentBase<MyChild>, IParent<IChild> 
{ 
    public MyParent(MyChild child) 
     : base(child) 
    { 
    } 
} 

Я тусклый т к его экземпляр и получить абстрактную (тип интерфейса), чтобы перейти к потребителям следующим образом:

IParent<IChild> parent = new MyParent(new MyChild()); 

Но по какой-то причине я не могу реализовать TChild правильно, даже если я определил свойство public TChild Child на ParentBase, то компилятор говорит, что он не реализован, даже если я пытаюсь реализовать явно. Как вы можете видеть, ограничения доходят до базового класса.

+0

Какую версию C# вы используете? – Oded

+0

Я использую C# 4 (.NET 4) – Andre

ответ

4

Вывод MyParent от ParentBase<MyChild> и IParent<IChild>. Там нет реализации для

IParent<IChild> { IChild Child{get; } } 

Добавление явной реализации позволит исходный код для компиляции

public class MyParent : ParentBase<MyChild>, IParent<IChild> 
{ 
    public MyParent(MyChild child) 
     : base(child) 
    { 
    } 

    #region Implementation of IParent<IChild> 

    IChild IParent<IChild>.Child 
    { 
     get { return base.Child; } 
    } 

    #endregion 
} 

Если вы также сделать IParent коварианты так:

public interface IParent<out TChild> where TChild : IChild 
{ 
    TChild Child { get; } 
} 

, то вы можете прямо сейчас сделать это

IParent<IChild> parent = new MyParent(new MyChild()); 

или

ParentBase<MyChild> parent2 = new MyParent(new MyChild()); 

и

IParent<IChild> parent3 = parent2; 

И как было указано в ответе по @svick с ковариации вы можете упростить, не вытекающие из IParent<IChild> и удаления явной реализации интерфейса.

+0

Потребители должны использовать IParent , а не конкретные типы, поэтому мне нужен экземпляр этого. И когда они обращаются к дочернему свойству, ему нужно просто быть IChild – Andre

+0

Вам нужна явная реализация nof IParent .Child – Phil

+0

Но если вы сделаете ковариацию 'IParent' и не укажете' IParent 'явно в качестве базы для' MyParent ' ', тогда вам не придется реализовывать' IParent .Child', реализации в ParentBase будет достаточно. См. Мой ответ. – svick

0

Если потребители должны использовать получение IChild, а не TChild, не можете ли вы избавиться от универсального интерфейса?

public interface IParent 
{ 
    public IChild Child { get; } 
} 

, а затем ваше наследство работает просто отлично

public class ParentBase<TChild> : IParent where TChild : IChild 
{ 
    public IChild Child { get { return myChild; } } 
} 

и

public class MyParent : ParentBase<MyChild> // already implements IParent by the base doing so. 
{ 
} 
3

Это точно, где общая дисперсия является полезным.Если вы отметили свой IParent interafce как коварианта:

public interface IParent<out TChild> where TChild : IChild 

и удаляется явный вывод IParent<IChild> из MyParent:

public class MyParent : ParentBase<MyChild> 

затем MyParent можно рассматривать, как если бы оно реализовано IParent<IChild>. Так, например, следующий код будет работать:

MyParent parent = new MyParent(new MyChild()); 
IParent<IChild> iParent = parent;