【问题标题】:Specify type of generic list based on other parameter根据其他参数指定泛型列表的类型
【发布时间】:2015-03-17 17:18:10
【问题描述】:

我有一个问题,我无法用简单的语言来解释,所以我会用一个例子来说明我的想法。

我有牛、马、羊三个班。和类动物。现在我希望 clas Animal 存储动物列表,但只有一个指定的物种(用户在构造函数中选择类型)。现在我不想使用模板,也不想在一个类中创建三个不同的列表。所以我想知道是否有其他方法可以做到这一点。我认为可以这样做:

public class Animal
{

}
public class Cow : Animal
{

}
public class Horse : Animal
{

}
public class Sheep : Animal
{

}
public class Animals
{
    public String Type { get; protected set; }
    public List<Animal> List { get; set;}
    public Animals(String type)
    {
        this.Type = type;
        switch (type)
        {
            case "Cow":
                List = new List<Cow>();
                break;
            case "Horse":
                List = new List<Horse>();
                break;
            case "Sheep":
                List = new List<Sheep>();
                break;
        }
    }
}

当然,该代码只是示例,它不起作用,但我认为它说明了我遇到的问题。我确定我过去看到过类似的东西,但我不知道它是 C# 还是 Java。如果我记得它看起来像这样:

Animal animal = new Cow();

告诉我有没有办法做到这一点。

【问题讨论】:

  • 您需要阅读有关装箱和拆箱的信息 - 也许您可以使用动态来执行此操作...我不确定
  • 我不确定,但我记得在 Java Head First 一书中读过类似的内容。

标签: c# list class


【解决方案1】:

怎么样

public class Animals<T>
    where T : Animal
{
    public List<T> List {get;set;}
}

var Cows = new Animals<Cow>();

【讨论】:

  • 为什么投反对票?这个问题不清楚,考虑到我给出了最好的答案。
  • 我不想使用模板(很可能他是指模板中的泛型)
  • 如果没有更好的方法,他想做的事情就有些无关紧要了。唯一的选择是在构造函数中指定类型(为什么不使用泛型呢?),然后创建他自己的列表对象来验证进入其中的类型,但这只会变得混乱。
【解决方案2】:

在每种情况下,您都可以将列表创建为List&lt;Animal&gt;,它会愉快地存储任何从 Animal 派生的对象。问题在于强制执行列表中的对象是相同的类型——不清楚你想在哪里强制执行,但我在下面尝试了它,将所需的类型保留在成员变量中。

如果你想要的只是一个特定类型的枚举器,你可以使用 OfType(感谢Kevin D)来生成枚举器。我知道您说过您不想使用泛型,但是您的 Animals 类不必有类型参数,使用模板方法是一种更优雅的解决方案(恕我直言)。

public class Animal
{
}

public class Cow : Animal
{
}

public class Animals
{
    private Type _animalType;
    private List<Animal> _animals = new List<Animal>();

    public Animals(Type animalType)
    {
        _animalType = animalType;
    }

    public IEnumerable<T> GetAnimals<T>() where T : Animal
    {
        return _animals.OfType<T>();
    }

    public void Add(Animal animal)
    {
        if (! _animalType.IsAssignableFrom(animal.GetType()))
            throw new Exception("Expected a " + _animalType.Name + " but was passed a " + animal.GetType().Name);
        _animals.Add(animal);
    }
}


public class Program
{
    public static void Main()
    {
        Animals animals = new Animals(typeof(Cow));

        animals.Add(new Cow());
        IEnumerable<Cow> cows = animals.GetAnimals<Cow>();

        foreach (var cow in cows)
        {
            // do something
        }
    }
}

【讨论】:

  • 对于您的GetAnimals&lt;T&gt;() 方法,为什么不直接返回_animals.OfType&lt;T&gt;()?这将不太容易出现异常。尤其是当您的列表包含多种不同类型的动物时。
  • 此外,使您的Add&lt;T&gt;(..) 方法通用似乎毫无意义。只需Add( Animal animal )
【解决方案3】:

我相信泛型是解决您的问题的最佳方式,顺便说一下,我希望这段代码对您有所帮助。

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication7
{
  public class Animal
  {

  }
  public class Cow : Animal
  {

  }
  public class Horse : Animal
  {

  }
  public class Sheep : Animal
  {

  }    

  public class Animals
  {        
    protected ArrayList List { get; set; }
    protected Type Type { get; set; }

    public Animals(Type type)
    {
        this.Type = type;
        this.List = new ArrayList();
    }

    public void AddAnimal(Animal animal)
    {
        if (animal.GetType() == this.Type)            
            this.List.Add(animal);            
        else
            throw new Exception("Not expected type");
    }
 }

class Program
{
    static void Main(string[] args)
    {
        var s1 = new Sheep();
        var s2 = new Sheep();
        var c1 = new Cow();
        var sheepList = new Animals(typeof(Sheep));
        sheepList.AddAnimal(s1);
        sheepList.AddAnimal(s2);
        sheepList.AddAnimal(c1);//throws an exception
    }
  }
}

【讨论】:

  • 我根本不会使用ArrayList。如有必要,可以替换其功能List&lt;object&gt;。在这种情况下,使用List&lt;Animal&gt; 会更好,因为 OP 似乎表明总会有一个公共基类。
  • @Kyle OP 似乎不想使用它。
  • @john OP 不清楚。唯一可能表明的是“模板”评论以及 OP 将它们称为“模板”的事实让我怀疑他们并不完全确定他们真正想要什么。我将那行解释为他们不想让他们的类通用,因为他们可能在编译时不知道类型(这可能是一个合理的限制)。我无法想象一个合理的案例来避免在任何地方使用所有泛型(除非他们使用 .NET 1.1)。
猜你喜欢
  • 2017-11-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-09
  • 2022-10-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多