6

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

示例Animal有 3 个后代Tiger, Human,Hippo

我只想让Tigers 和Hippos 被关在动物园的笼子里?我需要一份动物类型的清单。

我会喜欢比List<Type>

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

编辑

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

例子:

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

这有程序员可以做的限制,types.Add(typeof(Human))这是我不想反对的。

编辑2

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

4

6 回答 6

4

方法1 - 通过接口:

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
很抱歉没有实现诸如MarkedByAttribute,IsDerivedFromImplementsInterface- 我只是在当前机器上还没有 Visual Studio 并且不记得确切的 api 之类的方法。

于 2012-10-05T13:09:49.007 回答
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>();
于 2012-10-05T12:54:59.750 回答
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)
    {
       ....
    }

    .....

}
于 2012-10-05T12:58:43.457 回答
2

我会使用一个接口来确定动物是否是 ZooAnimal

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

  }
  public class Human : Animal
  {

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

然后检查动物是否是 Zoo Animalif (a is IZooAnimal)下面是你可以使用的 zoo 类。

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

编辑:

好的,现在使用类型来执行此操作并将类型限制为 aZooAnimal我已经创建了一个通用 zoo 类,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);
    }
  }

这会将typeTiger 添加到AnimalsInZoo. 希望这对你有用。

  Zoo<IZooAnimal> cage = new Zoo<IZooAnimal>();
  cage.AddType(typeof(Tiger));
  cage.AddType(typeof(Human));
于 2012-10-05T13:01:27.390 回答
1

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

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());
}
于 2012-10-05T12:56:56.373 回答
0

另一种选择:

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

并让嵌套类实现它们的行为。

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

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.
    }
}
于 2012-10-05T13:09:20.447 回答