2012-04-17 19 views
5

Per qualche motivo sto combattendo per implementare una proprietà da un'interfaccia generica utilizzando una classe base generica come segue:classe generica di base che eredita da un'interfaccia generica

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

public interface IChild { } 

poi ho una classe di base:

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 
} 

ora ho un derivato e figlio oggetto nuovo genitore come segue:

public class MyChild : IChild { } 

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

I wan t creare un'istanza di esso e ottenere il (tipo di interfaccia) abstract di passare ai consumatori come segue:

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

Ma per qualche motivo non può implementare correttamente il TChild, anche se ho definito la proprietà public TChild Child sul ParentBase, il il compilatore dice che non è implementato, anche se provo a implementarlo esplicitamente. Come puoi vedere, i vincoli arrivano fino alla classe base.

+0

Quale versione di C# stai usando? – Oded

+0

Sto usando C# 4 (.NET 4) – Andre

risposta

4

Si sta derivando MyParent da ParentBase<MyChild> e IParent<IChild>. Non v'è alcuna implementazione per

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

Aggiunta un'implementazione esplicita permetterà il vostro codice originale per compilare

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 
} 

Se anche voi fate IParent covariante come questo:

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

allora si può ora fai questo

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

o

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

e

IParent<IChild> parent3 = parent2; 

E come sottolineato nella risposta da @svick, con covarianza è possibile semplificare da non derivanti da IParent<IChild> e rimuovendo l'implementazione dell'interfaccia esplicita.

+0

I consumatori devono utilizzare IParent e non i tipi di calcestruzzo, quindi ho bisogno di un'istanza di questo. E quando accedono alla proprietà child, deve semplicemente essere IChild – Andre

+0

È necessaria un'implementazione esplicita nof IParent .Campo – Phil

+0

Ma se si effettua covariante 'IParent' e non si specifica' IParent 'come base per' MyParent ', quindi non sarà necessario implementare' IParent .Child', l'implementazione in 'ParentBase' sarà sufficiente. Vedi la mia risposta. – svick

0

Se i consumatori devono utilizzare un IChild e non un TChild, non è possibile eliminare l'interfaccia generica?

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

e poi la tua eredità funziona bene

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

e

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

Questo è esattamente dove la varianza generici è utile.Se hai segnato il tuo IParent interafce come covariante:

public interface IParent<out TChild> where TChild : IChild 

e rimosso la derivazione esplicita di IParent<IChild> da MyParent:

public class MyParent : ParentBase<MyChild> 

poi MyParent può essere trattata come se fosse implementato IParent<IChild>. Ad esempio, il seguente codice funzionerebbe:

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