2012-04-17 12 views
5

Por alguna razón que estoy luchando para implementar una propiedad de una interfaz genérica mediante el uso de una clase base genérica de la siguiente manera:genérico Clase base que hereda de la interfaz genérica

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

public interface IChild { } 

entonces tengo una clase 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 
} 

ahora tengo un objeto derivado y el niño nuevo padre de la siguiente manera:

public class MyChild : IChild { } 

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

I wan t instanciarlo y obtener el (tipo de interfaz) abstracta para pasar a los consumidores de la siguiente manera:

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

Pero por alguna razón no se puede poner en práctica el TChild correctamente, a pesar de que he definido la propiedad public TChild Child en el ParentBase, la el compilador dice que no está implementado, incluso si intento implementarlo explícitamente. Como puede ver, las restricciones llegan hasta la clase base.

+0

¿Qué versión de C# estás usando? – Oded

+0

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

Respuesta

4

Usted está derivando MyParent de ParentBase<MyChild> y IParent<IChild>. No hay una aplicación para

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

Adición de una implementación explícita le permitirá a su código original para compilar

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 
} 

Si usted también hace iParent covariante como esto:

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

entonces ahora puede hacer esto

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

o

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

y

IParent<IChild> parent3 = parent2; 

Y como se señala en la respuesta por @svick, la covarianza a continuación, puede simplificar al no deriva de IParent<IChild> y la eliminación de la implementación de interfaz explícita.

+0

Los consumidores necesitan usar IParent y no los tipos de concreto, así que necesito una instancia de esto. Y cuando acceden a la propiedad hija necesita ser IChild – Andre

+0

Necesita una implementación explícita nof IParent .Child – Phil

+0

Pero si convierte 'IParent' en una covariante y no especifica' IParent 'explícitamente como base para' MyParent ', entonces no tendrá que implementar' IParent .Child', la implementación en 'ParentBase' será suficiente. Ver mi respuesta – svick

0

Si los consumidores necesitan utilizar obtener un IChild y no un TChild, ¿no puede deshacerse de la interfaz genérica?

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

y luego su herencia funciona bien

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

y

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

Esto es exactamente donde la varianza genérica es útil.Si marcó su interafce IParent como covariante:

public interface IParent<out TChild> where TChild : IChild 

y se retira la derivación explícita de IParent<IChild> de MyParent:

public class MyParent : ParentBase<MyChild> 

continuación MyParent pueden ser tratados como si implementa IParent<IChild>. Entonces, por ejemplo, el siguiente código funcionaría:

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