Reputation: 1071
I have a type that uses generics. Let's call it FlowerDescriptor<T>
some flowers are described using numbers, others using strings etc.
so FlowerDescriptor<int>;
FlowerDescriptor<string>;
etc
I want a mechanism (probably extension methods) for doing 2 things
FlowerDescriptor
andI.e.
FlowerDescriptor<string>.GetType().IsFlowerDescriptor == true
string.GetType().IsFlowerDescriptor == false
.equally I might derive from FlowerDescriptor<int>
i.e. class NumberedFlower: FlowerDescriptor<int>
new NumberedFlower.GetType().IsFlowerDesriptor == true;
FlowerDescriptor<string>.GetType().GetFlowerDescriptor() == typeof(string)
FlowerDescriptor<int>.GetType().GetFlowerDescriptor() == typeof(int)
new NumberedFlower.GetType().GetFlowerDescriptor() == typeof(int)
I have played about with variations of IsAssignableFrom
and it feels like that ought to work with typeof(FlowerDescriptor<>).IsAssignableFrom(typeof(FlowerDescriptor<string>))
but it doesn't work. If it add the generic type however it does.
I am currently exploring GetInterfaces
to know available interfaces. It'd be great to actually understand what I am doing wrong too..
Upvotes: 4
Views: 95
Reputation: 25370
You might consider having a non-generic base class. Then your structure could look like:
public abstract class FlowerDescriptor { }
public class FlowerDescriptor<T> : FlowerDescriptor { }
public class NumberedFlower : FlowerDescriptor<int> { }
Your 2 extensions would be:
public static class Extensions
{
public static bool IsFlowerDescriptor(this object o)
{
return o is FlowerDescriptor;
}
public static Type GetFlowerDescriptor<T>(this FlowerDescriptor<T> o)
{
return typeof (T);
}
}
and you'd use it like:
public static void Main()
{
Console.WriteLine(new NumberedFlower().IsFlowerDescriptor()); //true
Console.WriteLine(new NumberedFlower().GetFlowerDescriptor()); //System.Int32
}
Generics have an adverse effect when it comes to reflecting over and comparing types, because a FlowerDescriptor<int>
is a different type from FlowerDescriptor<string>
. This is something I have not found a good rhythm for.
Upvotes: 0
Reputation: 7545
Here is how you would get those two values:
bool isFlowerDescriptor = x is FlowerDescriptor<object>;
Type descriptorType = x.GetType().GetGenericArguments()[0];
You could wrap these in extension methods if you like. And add null-checks etc.
Upvotes: 0
Reputation: 2254
I would not expect the string or int class to know if its a descriptor, it makes a lot more sense to get that information from the FlowerDescriptor.
That being said if you want to use reflection you could get the generic type definition from the FlowerDescriptor instance
FlowerDescriptor<int> f = new FlowerDescriptor<int>();
Type t = f.GetType();
Type[] typeArguments = t.GetGenericArguments();
//check if type you care about is in typeArguments
Upvotes: 2
Reputation: 391286
Unless you want to add interfaces into the mix, the only choice you have is to
FlowerDescriptor<T>
FlowerDescriptor<T>
Unfortunately I don't think you can use IsAssignableFrom
when it comes to open generics which means we're left with walking the inheritance chain up to the base classes.
Here is an example piece of code that would do the right thing:
public static bool IsFlowerDescriptor(this Type type)
{
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(FlowerDescriptor<>))
return true;
if (type.BaseType != null)
return type.BaseType.IsFlowerDescriptor();
return false;
}
Here's a .NET Fiddle you can experiment with.
Upvotes: 4