Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I hold a List<> of Object Types of the same descendant?

I need to hold a list of object types that are allowed to do certain actions.

Example Animal has 3 descendants Tiger, Human, Hippo

I want to allow only Tigers and Hippos to be held in zoo cages? I need a list of animal types.

I would love something better than List<Type>

This is just a simplified example. I don't like animals in cages..

edit

Since it's not clear. I want to hold object types in the list and not actual objects.

Example:

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

This has the limit that a programmer can do types.Add(typeof(Human)) and this is what I wan't to dissallow.

edit2

Just to clarify my question. I want to be able to dynamically Register allowed types and not having consequent ifs as some answers bellow.

like image 833
Odys Avatar asked Oct 05 '12 12:10

Odys


People also ask

Can an object have a list?

Absolutely, this is normal as an object can contain lists that belong to only that particular object.

How does list work in C#?

List in C# is a collection of strongly typed objects. These objects can be easily accessed using their respective index. Index calling gives the flexibility to sort, search, and modify lists if required. In simple, List in C# is the generic version of the ArrayList.

What is list in C# w3schools?

What is C# List? List<T> class in C# represents a strongly typed list of objects. List<T> provides functionality to create a list of objects, find list items, sort list, search list, and manipulate list items. In List<T>, T is the type of objects.


2 Answers

If you want a list of only certain types:

There isn't anything in generics that can support what you are asking for, so simply create a custom type that allows you to store Type types and have code at runtime for guarding against invalid entries:

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

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

Although I can't see why you might need this.

Alternative if you want a list of only certain types:

Do the same as above, but include the interface below and change the add check to something like:

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

You could also use attributes, as you can query a type for any attributes using the GetAttributes method.

If you wish to only have certain instances in a list:

Create a marker interface:

public interface ICanBeHeldInZooCage

That Tiger and Hippo implement (doesn't have to do anything), then you can have:

var cagedAnimals = new List<ICanBeHeldInZooCage>();
like image 103
Adam Houldsworth Avatar answered Sep 22 '22 01:09

Adam Houldsworth


Approach1 - via interfaces:

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

Approach 2 - via attribute:

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

UPDATE

IMPORTANT

Both these approaches provide only runtime check. having compilation check implementation would be better, but don't know for know how to achieve that.

UPDATE2
For dynamic registration:

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
Sorry for not implemented methods like MarkedByAttribute, IsDerivedFrom and ImplementsInterface - I just don't have visual studio on current machine yet and don't remember api exactly.

like image 44
alex.b Avatar answered Sep 18 '22 01:09

alex.b