2011-05-09 19 views
7

Duplicar posibles:
Casting List<T> - covariance/contravariance problemdevolver una lista de clase abstracta

tengo clases definidos de la siguiente manera

public abstract class AbstractDType 
{ 
    protected abstract string Num1 { get; set; } 
    protected abstract string Num2 { get; set; } 
} 

public class AD1 : AbstractDType 
{ 
    public string Num1 { get; set; } 
    public string Num2 { get; set; } 
    public string Num3 { get; set; } 
} 

public class AD2 : AbstractDType 
{ 
    public string Num1 { get; set; } 
    public string Num2 { get; set; } 
    public string Num3 { get; set; } 
} 

public abstract class DTypeStrategy 
{ 
    protected virtual List<AbstractDType> GetData() 
    { 
      return new List<AD1>(); 
    }  
} 

me gustaría devolver una lista de PD1 (tipo concreto) en el método GetData(). Sin embargo, el código anterior arrojó un error de lanzamiento. List<AbstractDType> no se puede convertir a List<PD1>. ¿Cómo soluciono este error para poder devolver el hormigón en el método GetData?

Hay otras clases derivadas que heredaron de DTypeStrategy que serían de aplicación GetData(), como a continuación: (Estoy suponiendo que voy a conseguir el mismo error de fundición aquí también)

public class MyDraw : DTypeStrategy 
{ 
    public override List<AbstractDType> GetData() 
    { 
      return new List <AD2>(); 
    } 
} 

Respuesta

0

Sería parece del código que has publicado que para el momento en que heredes DTypeStrategy sabes qué clase concreta quieres devolver.

Por lo tanto se puede convertir en un DTypeStrategy clase genérica

public abstract class DTypeStrategy <T> where T:AbstractDType 
{ 
    protected abstract List<T> GetData(); 
} 

y entonces funciona:

public class MyDraw : DTypeStrategy <AD2> 
{ 
    public override List<AD2> GetData() 
    { 
      return new List <AD2>(); 
    } 
} 
1

¿Cuál es su objetivo real aquí? Si realmente desea devolver una lista de GetData que contiene AD1, se puede hacer eso:

protected virtual List<AbstractDType> GetData() 
{ 
     var stuff = new List<AbstractDType>(); 
     stuff.Add(new AD1()); 
     return stuff; 
} 

Pero si realmente desea devolver una lista de un tipo concreto, entonces, bueno, se puede' Hago eso, y apunta a un defecto en su diseño. Piense en el código de llamada si esto fuera posible:

public void Victim(DTypeStrategy strat) 
{ 
    List<AbstractDType> list = strat.GetData(); 
    //oops, the list is actually a list<AD1>, so this throws: 
    list.Add(new AD2()); 
} 

Pregúntese:

  • ¿Por qué quiero para devolver una lista especializada en lugar de uno de AbstractDType?
  • ¿Por qué debería ser una Lista y no un IEnumerable?

Si usted debe tener una lista especializada, por alguna razón, utilice un método genérico:

public class DTypeStrategy<T> where T: AbstractDType 
{ 
    //not sure a concrete here is a good idea, but you get the point... 
    public virtual List<T> GetData() 
    { 
     return new List<T>(); 
    } 
} 

public class MyDraw : DTypeStrategy<AD2> 
{ 
    public override List<AD2> GetData() 
    { 
     return new List<AD2>(); 
    } 
} 

Si no necesitan una List<T>, entonces es probable que se puede abusar de C# 's covariant generic interfaces para hacer esto - pero De nuevo, me gustaría ver su diseño primero.

+0

Estoy usando Strategy Pattern para crear objetos concretos basados ​​en typeID. El método GetData() de cada objeto concreto devolverá una lista específica como Lista de AD1, AD2 o AD3. AD1, AD2 y AD3 heredados de AbstractDType. DTypeStrategy tendría el método GetData() con comportamiento predeterminado. –

+0

@Alan B En un patrón de estrategia, el código que llama a sus estrategias no debería necesitar saber qué devuelve la lista concreta 'GetData', por lo que el fragmento superior sería el que desee: cree la lista a partir del resumen y agregue instancias de subclases a ella. –

Cuestiones relacionadas