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 Tiger
s and Hippo
s 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 if
s as some answers bellow.
Absolutely, this is normal as an object can contain lists that belong to only that particular object.
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 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.
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>();
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With