我可以持有List<>对象类型的同一后代?

时间:2012-10-05 12:48:35

标签: c# oop list inheritance

我需要保留允许执行某些操作的对象类型列表。

示例Animal有3个后代TigerHumanHippo

我想只允许TigerHippo被关在动物园的笼子里?我需要一份动物类型清单。

我会喜欢比List<Type>

更好的东西

这只是一个简化的例子。我不喜欢笼子里的动物......

修改

因为不清楚。我想在列表中保存对象类型而不是实际对象。

示例:

List<Type> types = new List<Type>();
types.Add(typeof(Hippo));
types.Add(typeof(Tiger));

这有一个程序员可以types.Add(typeof(Human))的限制,这是我不想解释的。

EDIT2

只是为了澄清我的问题。我希望能够动态Register允许的类型,而不是后续的if,因为下面有一些答案。

6 个答案:

答案 0 :(得分:4)

如果您只想要某些类型的列表:

泛型中没有任何内容可以支持您的要求,因此只需创建一个自定义类型,允许您存储Type类型并在运行时使用代码来防止无效条目:

public class CagedTypes 
{
    private readonly List<Type> _types;

    public void Add(Type t)
    {
        if (t == typeof(Hippo) || t == typeof(Tiger))
            _types.Add(t);
    }
}

虽然我不明白为什么你可能需要这个。

如果您只想要某些类型的列表,请选择

执行与上面相同的操作,但请在下面添加界面并将添加检查更改为:

public void Add(Type t)
{
    if (t.GetInterfaces().Contains(typeof(ICanBeHeldInZooCage)))
        _types.Add(t);
}

您也可以使用属性,因为您可以使用GetAttributes方法查询任何属性的类型。

如果您希望列表中只包含某些实例:

创建标记界面:

public interface ICanBeHeldInZooCage

TigerHippo实现(无需执行任何操作),然后您可以:

var cagedAnimals = new List<ICanBeHeldInZooCage>();

答案 1 :(得分:3)

界面怎么样?

public interface ICageable {}

public abstract class Animal {}

public class Hippo : Animal, ICageable {}

public class Tiger : Animal, ICageable {}

public class Human : Animal, ICageable {}

public class Ape : Animal {}

....
List<ICageable> ZooAnimals = new List<ICageable>{hippo, tiger, human};

(从人猿星球的角度写作)

如果您需要列表中的类型本身,则井类型是Type类型的实例,因此无论您创建什么类型,它都是类型的集合。封装是这样的:

public class CageableTypesCollection : 
{
    private List<Type> _cageableTypes;

    public CageableTypesCollection()
    {
       _cageableTypes = new List<Type>();
    }

    public RegisterType(Type t)
    {
       if (!typeof(ICageable).IsAssignableFrom(t))
          throw new ArgumentException("wrong type of type");
       _cageableTypes.Add(t);
    }

    public UnregisterType(Type t)
    {
       ....
    }

    .....

}

答案 2 :(得分:3)

Approach1 - 通过接口:

public interface ICageable
{ }

public abstract class Animal
{}

public class Hippo : Animal, ICageable
{}

public class Human : Animal, ICageable
{}

public IEnumerable<Type> GetCageableAnimals()
{
    return  GetAssemblyTypes(assembly:typeof(Animal).Assembly)
        .Where(type=>IsDerivedFrom(type, typeof(Animal)))
        .Where(type=>ImplementsInterface(type,typeof(ICageable)));
}

方法2 - 通过属性:

public class InCageAttribute : Attribute
{ }

public abstract class Animal
{}

[InCage]
public class Hippo : Animal
{}

public class Human : Animal
{}

public IEnumerable<Type> GetCageableAnimals()
{
    return  GetAssemblyTypes(assembly:typeof(Animal).Assembly)
        .Where(type=>IsDerivedFrom(type, typeof(Animal)))
        .Where(type=>MarkedByAttribute(type,typeof(InCageAttribute)));
}

更新

重要

这两种方法都只提供运行时检查。有编译检查实现会更好,但不知道如何实现它。

<强> UPDATE2
对于动态注册:

public class CageRegistry
{
    private List<Type> _allowedTypes = new List<Type>();
    public IEnumerable<Type> AllowedTypes{get{return _allowedTypes;}}

    public bool TryAdd(Type type)
    {
        if(ImplementsInterface(type, typeof(ICageable)))// for approach with attributes code is pretty similar
        {
            _allowedTypes.Add(type);
            return true;
        }
        return false;
    }
}

<强> PS2
很抱歉没有实现的方法,例如MarkedByAttributeIsDerivedFromImplementsInterface - 我当前的机器上还没有visual studio,也不记得api。

答案 3 :(得分:2)

我会使用界面来确定动物是否是ZooAnimal

  public class Animal
  {
    public string Name;
  }
  public class Tiger : Animal, IZooAnimal
  {

  }
  public class Human : Animal
  {

  }
  public interface IZooAnimal
  {
    //Some zoo animal properties
  }

然后检查动物是否是动物园动物if (a is IZooAnimal)下面是动物园类,你可以使用。

  public class Zoo
  {
    public List<IZooAnimal> AnimalsInZoo = new List<IZooAnimal>();
    public void AddAnimal(IZooAnimal a)
    {
      AnimalsInZoo.Add(a);
    }
  }

编辑:

现在好了用类型来做这个并将类型约束到ZooAnimal我创建了一个通用的动物园类,它取T,其中T是一个ZooAnimal - 你可以有一个ZooAnimals列表或者我们案例中的老虎名单。

  public class Zoo<T> where T : IZooAnimal
  {
    public List<Type> AnimalTypes = new List<Type>();
    public void AddType(Type a)
    {
      if (typeof(T) == a)
        AnimalTypes.Add(a);
    }
  }

这会将type Tiger添加到AnimalsInZoo。希望这对你有用。

  Zoo<IZooAnimal> cage = new Zoo<IZooAnimal>();
  cage.AddType(typeof(Tiger));
  cage.AddType(typeof(Human));

答案 4 :(得分:1)

人类是动物,虎是动物应该在动物园。因此,在您的情况下,我将为TigerHippo再创建一个基类。

public class AnimalInZoo : Animal {}
public class Tiger : AnimalInZoo {}
public class Hippo : AnimalInZoo {}
public class Human : Animal {}

您可以创建帮助函数AddInZoo(AnimalInZoo obj)以添加List<Type> m_Zoo

void AddInZoo(AnimalInZoo obj)
{
    m_Zoo.Add(obj.GetType());
}

答案 5 :(得分:0)

另一种选择:

public abstract class Animal
{
    public abstract bool IsCagable { get; }
}

让嵌套类实现他们的行为。

稍后,在Add方法中,主要在本主题的答案中呈现的某种Zoo类必须进行检查:

public sealed class ZooList : List<Animal> // I believe you need Animal, not Type
{
    // ... some implementations ...

    public override sealed void Add(Animal animal)
    {
        if (!animal.IsCagable)
            // Prevent from adding.
    }
}