Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Return a list of abstract class [duplicate]

Tags:

c#

Possible Duplicate:
Casting List<T> - covariance/contravariance problem

I have classes defined as below

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>();  
   }    
}

I would like to return a list of PD1 (concrete type) in GetData() method. However the above code threw a casting error . List<AbstractDType> cannot be converted to List<PD1>. How do I fix this error so that I could return concrete in GetData method.

There are other derived classes that inherited from DTypeStrategy which would be implementing GetData() such as below : ( I am assuming that I'll get the same casting error here as well )

public class MyDraw : DTypeStrategy  
{  
   public override List<AbstractDType> GetData()  
   {  
          return new List <AD2>();  
   } 
}
like image 839
Alan B Avatar asked May 09 '11 11:05

Alan B


1 Answers

What is your actual goal here? If you really just want to return a list from GetData that contains AD1, you can do that:

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

But if you really want to return a list of a concrete type, then, well, you can't do that - and it points to a flaw in your design. Think of the calling code if this were possible:

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() );
}

Ask yourself:

  • Why do I want to return a specialized list rather than one of AbstractDType?
  • Why should it be a List at all, and not an IEnumerable?

If you MUST have a specialized List for some reason, use a generic method:

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>();
   }
}

If you don't need a List<T>, then you can probably abuse c#'s covariant generic interfaces to do this - but again, I'd look at your design first.

like image 96
Philip Rieck Avatar answered Oct 10 '22 20:10

Philip Rieck