【问题标题】:Return a list of abstract class [duplicate]返回抽象类列表[重复]
【发布时间】:2011-05-09 11:37:14
【问题描述】:

可能重复:
Casting List<T> - covariance/contravariance problem

我有如下定义的类

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

我想在 GetData() 方法中返回一个 PD1(具体类型)的列表。但是上面的代码抛出了一个转换错误。 List&lt;AbstractDType&gt; 无法转换为 List&lt;PD1&gt;。如何修复此错误,以便可以在 GetData 方法中返回具体。

还有其他从 DTypeStrategy 继承的派生类将实现 GetData(),如下所示:(我假设我也会在这里得到相同的转换错误)

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

【问题讨论】:

    标签: c#


    【解决方案1】:

    您在这里的实际目标是什么?如果你真的只是想从 GetData 返回一个 包含 AD1 的列表,你可以这样做:

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

    但如果你真的想返回一个具体类型的列表,那么,你不能这样做——这表明你的设计存在缺陷。想想调用代码如果可能的话

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

    问问自己:

    • 为什么我要返回一个专门的列表而不是 AbstractDType 之一?
    • 为什么它应该是 List 而不是 IEnumerable?

    如果您出于某种原因必须有一个专门的列表,请使用通用方法:

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

    如果您不需要 List&lt;T&gt;,那么您可能会滥用 c# 的 covariant generic interfaces 来执行此操作 - 但同样,我会查看您的设计首先

    【讨论】:

    • 我正在使用策略模式来创建基于 typeID 的具体对象。每个具体对象的 GetData() 方法将返回一个特定列表,例如 AD1、AD2 或 AD3 的列表。 AD1、AD2 和 AD3 继承自 AbstractDType。 DTypeStrategy 将具有具有默认行为的 GetData() 方法。
    • @Alan B 在策略模式中,调用策略的代码不需要知道具体 List GetData 返回的内容,因此顶部的 sn-p 将是您想要的 - 创建抽象的列表并向其添加子类的实例。
    【解决方案2】:

    从您发布的代码看来,当您继承 DTypeStrategy 时,您就知道要返回哪个具体类。

    因此你可以将DTypeStrategy 变成一个泛型类

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

    然后就可以了:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-02-24
      • 1970-01-01
      • 1970-01-01
      • 2016-04-19
      • 2016-06-08
      • 1970-01-01
      • 2010-12-13
      相关资源
      最近更新 更多