I have an Interface ISomeThing:
public interface ISomeThing {}
and 2 types implementing it:
public class SomeThing1 : ISomeThing {}
public class SomeThing2 : ISomeThing {}
and then I have a type using those types:
public class FooBar
{
public ICollection<SomeThing1> Foo { get; set; }
public ICollection<SomeThing2> Bar { get; set; }
}
I then have to use reflection to get access to the properties of FooBar:
var properties = typeof(FooBar).GetProperties()
.Where(p => typeof(ICollection<>).IsAssignableFrom(p.PropertyType));
Console.WriteLine(properties.Count());
The output will be 0. Even if I change the code to look for ICollection<ISomeThing> it won't work:
var properties = typeof(FooBar).GetProperties()
.Where(p => typeof(ICollection<ISomeThing>).IsAssignableFrom(p.PropertyType));
Console.WriteLine(properties.Count());
I want to get access to the property directly because ICollection brings in Remove etc.. So I need the cast to ICollection<T>.
Edit
I changed my sample to use ISomeThing instead of DateTime. The point is that I don't know the exact generic type at runtime but I need to yield a ICollection<ISomeThing> as the result.
** Edit 2 **
Now I finally come up with my example. This example here shows why I need the cast so badly.
var properties = instance.GetType().GetProperties();
foreach (var property in properties){
var value = property.GetValue(instance);
if (value is ISomeThing someThingValue && someThingValue.IsSomeCondition)
{
// Do a ISomeThing-specific thing here
}
else if (property.PropertyType.GetInterfaces().Concat(new []{property.PropertyType})
.Any(i => i.IsGenericType
&& i.GetGenericTypeDefinition() == typeof(ICollection<>)
&& typeof(ISomeThing).IsAssignableFrom(i.GetGenericArguments().Single())))
{
var someThingValues = value as ICollection<ISomeThing>; // <-- this results in null
foreach (var someThingInstance in someThingValues)
{
if(someThingInstance.IsSomeCondition)
{
// Do the thing again
}
}
}
// Enter recursion for possible nested ISomeThings
}
ICollection<DateTime> collection = new HashSet<ISomeThing>();
That makes no sense. I assume you meant to type
ICollection<ISomeThing> collection = new HashSet<ISomeThing>();
Moving on.
Console.WriteLine(collection.GetType() as ICollection<ISomeThing>);
This is null because collection.GetType() returns a Type, and a Type does not implement ICollection<ISomething>.
Console.WriteLine(typeof(ICollection<>)
.IsAssignableFrom(collection.GetType()));
This is false because IsAssignableFrom means "can a variable of type ICollection<> be assigned a value of type HashSet<ISomething>. There is no such thing as a variable of type ICollection<>. Generic types have to be constructed before they can be the type of a variable.
I feel almost like the output lies to me when I look at line 1 and 3
It does not.
but I want to get access to the property directly because ICollection brings in Remove etc. So I need the cast to ICollection<T>.
I cannot for the life of me figure out what this sentence means. Can you clarify it?
UPDATE:
Based on the update to the question I now suspect that the actual question is either
Given a Type, I wish to know how many properties are of type ICollection<T> where T is any type that implements ISomeThing"
Easy peasy:
Type type = typeof(FooBar);
var properties = type
.GetProperties()
.Where(p => p.PropertyType.IsGenericType)
.Where(p => p.PropertyType.GetGenericTypeDefinition() == typeof(ICollection<>))
.Where(p => typeof(ISomeThing).IsAssignableFrom(
p.PropertyType.GenericTypeArguments.Single()))
Console.WriteLine(properties.Count()); // 2
or perhaps it is
Given a Type, I wish to know how many properties are of types that implement ICollection<T> where T is any type that implements ISomeThing"
That would be
var properties = type
.GetProperties()
.Where(p => p.PropertyType
.GetInterfaces()
.Concat(new [] {p.PropertyType})
.Where(i => i.IsGenericType)
.Where(i => i.GetGenericTypeDefinition() == typeof(ICollection<>))
.Where(i => typeof(ISomeThing)
.IsAssignableFrom(i.GetGenericArguments().Single()))
.Any());
UPDATE: Based on the latest update to this confusing question, the question is now how to rewrite this loop so that it works:
{
var someThingValues = value as ICollection<ISomeThing>; // <-- this results in null
foreach (var someThingInstance in someThingValues)
{
if(someThingInstance.IsSomeCondition)
{
// Do the thing again
}
}
}
That's easy. You simply don't attempt to cast to ICollection<anything> because you don't need any member of that type in your example. What do we know? That the type is ICollection<T> where T is ISomeThing. It is a requirement that this type implements non-generic IEnumerable and generic IEnumerable<T>.
It is not a requirement that the IEnumerable only yield objects that implement ISomeThing, but the author of the object would be crazy to have IEnumerable yield different objects than could be in the collection, so let's be cautious and stick a type filter on there.
var properties = instance.GetType().GetProperties();
foreach (var property in properties){
// Let's emphasize here that we don't know the type by using
// object instead of var
object value = property.GetValue(instance);
// We need to bail if this is null.
if (value == null)
continue;
if (value is ISomeThing someThingValue && someThingValue.IsSomeCondition)
{
// Do a ISomeThing-specific thing here
}
else if (property.PropertyType.GetInterfaces().Concat(new []{property.PropertyType})
.Any(i => i.IsGenericType
&& i.GetGenericTypeDefinition() == typeof(ICollection<>)
&& typeof(ISomeThing).IsAssignableFrom(i.GetGenericArguments().Single())))
{
var ie = value as IEnumerable;
Debug.Assert(ie != null);
foreach (ISomeThing someThingInstance in ie.OfType<ISomeThing>())
{
if(someThingInstance.IsSomeCondition)
{
// Do the thing again
}
}
}
// Enter recursion for possible nested ISomeThings
}
You could also tighten that up a bit with
var q = ie.OfType<ISomeThing>().
.Where(x => x.IsSomeCondition);
foreach (ISomeThing someThingInstance in q)
{
// Do the thing again
}
BONUS EXERCISE
Now, one might reasonable note that ICollection<T> is also convertible to IEnumerable<T>. We could reason like this:
We know we have ICollection<T> for some T that implements ISomeThing.
We know that we can convert ICollection<T> to IEnumerable<T> for any T.
Therefore we can convert this to IEnumerable<T> for some T that implements ISomeThing.
IEnumerable<T> is covariant in T and therefore we can convert our ICollection<T> directly to IEnumerable<ISomeThing> and enumerate that.
Therefore we should really be writing
var ie = value as IEnumerable<ISomeThing>;
Debug.Assert(ie != null);
foreach (ISomeThing someThingInstance in ie)
The above argument contains a logical flaw. Do you see it?
Give it some thought and once you figure out why this logic is wrong, leave an answer in the comments.
With the updated example, this should get you what you want. It finds all properties that are of ICollection<> and have a generic parameter that implements ISomeThing.
var properties = typeof(FooBar).GetProperties().Where(p => p.PropertyType.IsGenericType && p.PropertyType.GetGenericTypeDefinition() == typeof(ICollection<>) && p.PropertyType.GenericTypeArguments[0].GetInterfaces().Contains(typeof(ISomeThing)));
Related
I'm struggling with implementing the IEquatable<> interface for a class. The class has a Parameter property that uses a generic type. Basically the class definition is like this:
public class MyClass<T> : IEquatable<MyClass<T>>
{
public T Parameter { get; }
...
}
In the Equals() method I'm using EqualityComparer<T>.Default.Equals(Parameter, other.Parameter) to compare the property. Generally, this works fine – as long as the property is not a collection, for example an IEnumerable<T>. The problem is that the default equality comparer for IEnumerable<T> is checking reference equality.
Obviously, you'd want to use SequenceEqual() to compare the IEnumerable<T>. But to get this running, you need to specify the generic type of the SequenceEqual() method. This is the closest I could get:
var parameterType = typeof(T);
var enumerableType = parameterType.GetInterfaces()
.Where(type => type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IEnumerable<>))
.Select(type => type.GetGenericArguments().First()).FirstOrDefault();
if (enumerableType != null)
{
var castedThis = Convert.ChangeType(Parameter, enumerableType);
var castedOther = Convert.ChangeType(other.Parameter, enumerableType);
var isEqual = castedThis.SequenceEqual(castedOther);
}
But this does not work because Convert.ChangeType() returns an object. And of course object does not implement SequenceEqual().
How do I get this working? Thanks for any tipps!
Best regards,
Oliver
Given that you have a generic container that you want to compare various generic items, you don't want to be hard coding in various specific equality checks for certain types. There are going to be lots of situations where the default equality comparison won't work for what some particular caller is trying to do. The comments have numerous different examples of problems that can come up, but also just consider the many many classes out there who's default equality is a reference comparison by for which someone might want a value comparison. You can't have this equality comparer just hard code in a solution for all of those types.
The solution of course is easy. Let the caller provide their own equality implementation, which in C#, means an IEqualityComparer<T>. Your class can become:
public class MyClass<T> : IEquatable<MyClass<T>>
{
private IEqualityComparer<T> comparer;
public MyClass(IEqualityComparer<T> innerComparer = null)
{
comparer = innerComparer ?? EqualityComparer<T>.Default;
}
public T Parameter { get; }
...
}
And now by default the default comparer will be used for any given type, but the caller can always specify a non-default comparer for any type that needs different equality semantics.
Effectively you want a way to say
var castedThis = (IEnumerable<U>)Convert.ChangeType(Parameter, enumerableType);
where T is IEnumerable<U> and U is dynamic.
I don't think you can do that.
If you are happy with some boxing though, you can use the non-generic IEnumerable interface:
public bool Equals(MyClass<T> other)
{
var parameterType = typeof(T);
if (typeof(IEnumerable).IsAssignableFrom(parameterType))
{
var castedThis = ((IEnumerable)this.Parameter).GetEnumerator();
var castedOther = ((IEnumerable)other.Parameter).GetEnumerator();
try
{
while (castedThis.MoveNext())
{
if (!castedOther.MoveNext())
return false;
if (!Convert.Equals(castedThis.Current, castedOther.Current))
return false;
}
return !castedOther.MoveNext();
}
finally
{
(castedThis as IDisposable)?.Dispose();
(castedOther as IDisposable)?.Dispose();
}
}
else
{
return EqualityComparer<T>.Default.Equals(this.Parameter, other.Parameter);
}
}
If you are not happy with the boxing, then you can use reflection to construct and call SequenceEqual (as inspired by How do I invoke an extension method using reflection?):
public bool Equals(MyClass<T> other)
{
var parameterType = typeof(T);
if (typeof(IEnumerable).IsAssignableFrom(parameterType))
{
var enumerableType = parameterType.GetGenericArguments().First();
var sequenceEqualMethod = typeof(Enumerable)
.GetMethods(BindingFlags.Static | BindingFlags.Public)
.Where(mi => {
if (mi.Name != "SequenceEqual")
return false;
if (mi.GetGenericArguments().Length != 1)
return false;
var pars = mi.GetParameters();
if (pars.Length != 2)
return false;
return pars[0].ParameterType.IsGenericType && pars[0].ParameterType.GetGenericTypeDefinition() == typeof(IEnumerable<>) && pars[1].ParameterType.IsGenericType && pars[1].ParameterType.GetGenericTypeDefinition() == typeof(IEnumerable<>);
})
.First()
.MakeGenericMethod(enumerableType)
;
return (bool)sequenceEqualMethod.Invoke(this.Parameter, new object[] { this.Parameter, other.Parameter });
}
else
{
return EqualityComparer<T>.Default.Equals(this.Parameter, other.Parameter);
}
}
You can cache the sequenceEqualMethod for better performance.
I'm trying to support mapping to/from any kind of collection that implements ICollection<T> via reflection, because ICollection<T> requires implementation of the Add method.
This works fine for most common collection types, but fails for edge cases like LinkedList<T> where the Add method is hidden and can only be called by casting the LinkedList<T> to ICollection<T>.
However it's not possible to convert to ICollection<> because it is not covariant.
The other option I was considering was searching for both implicit and explicit implementations of Add, but I don't see any information on how to do this when the interface is generic?
What would be the correct approach to take?
Updated to show code snippet where I'm reflecting from xml to object mapping.
private object CollectionXmlNodeListToObject(
XmlNodeList nodeList, System.Type collectionType)
{
// this is not possible because ICollection<> is not covariant
object collection = Convert.ChangeType(
CreateInstanceOfType(collectionType), ICollection<>);
Type containedType = collectionType.GetTypeInfo().GenericTypeArguments[0];
foreach (XmlNode node in nodeList)
{
object value = CreateInstanceOfType(containedType);
if (containedType.IsClass && MetaDataCache.Contains(containedType))
value = ToObject(value, node, node.Name);
else
value = node.InnerText;
// this throws NullReferenceException when the type is LinkedList,
// because this is explicitly implemented in LinkedList
collectionType.GetMethod("Add")
.Invoke(collection, new[] { value });
}
return collection;
}
I am writing a small framework to map from object to xml using class and property attributes. So I cannot use generics because all of this is being done at runtime.
I initially was checking for IEnumerable before, but ran into other oddities with it (strings implement IEnumerable and are immutable) that I decided it was safest to stick to ICollection<>
With explicit interface implementation, the object has all the interface methods, but the object's Type does not.
So here's how to add an item to a LinkedList<T>, or any ICollection<T> through reflection:
var ll = new LinkedList<int>();
var t = typeof(int);
var colType = typeof(ICollection<>).MakeGenericType(t);
var addMethod = colType.GetMethod("Add");
addMethod.Invoke(ll, new object[] { 1 });
This functionality is met at compile-time using the Cast<T>() method. You just need a run-time version, which is pretty straightforward:
static public object LateCast(this ICollection items, Type itemType)
{
var methodDefintionForCast = typeof(System.Linq.Enumerable)
.GetMethods(BindingFlags.Static | BindingFlags.Public)
.Where(mi => mi.Name == "Cast")
.Select(mi => mi.GetGenericMethodDefinition())
.Single(gmd => gmd != null && gmd.GetGenericArguments().Length == 1);
var method = methodDefintionForCast.MakeGenericMethod(new Type[] { itemType });
return method.Invoke(null, new[] { items });
}
Now you can take any non-generic collection and make it generic at run-time. For example, these two are equivalent:
var list = nodeList.Cast<XmlNode>();
object list = nodeList.LateCast(typeof(XmlNode));
And you can convert a whole collection with this:
static public IEnumerable ConvertToGeneric(this ICollection source, Type collectionType)
{
return source.LateCast(collectionType.GetGenericArguments()[0]) as IEnumerable;
}
object list = nodeList.ConvertToGeneric(nodeList, typeof(ICollection<XmlNode>));
This solution works with linked lists as well as all the other collection types.
See my working example on DotNetFiddle
Pretty much all .NET collections take an IEnumerable<T> as the constructor, so you could make use of that:
private static object CollectionXmlNodeListToObject(System.Type collectionType)
{
// T
Type containedType = collectionType.GetTypeInfo().GenericTypeArguments[0];
// List<T>
Type interimListType = typeof(List<>).MakeGenericType(containedType);
// IEnumerable<T>
Type ienumerableType = typeof(IEnumerable<>).MakeGenericType(containedType);
IList interimList = Activator.CreateInstance(interimListType) as IList;
interimList.Add(null);
interimList.Add(null);
interimList.Add(null);
interimList.Add(null);
// If we can directly assign the interim list, do so
if (collectionType == interimListType || collectionType.IsAssignableFrom(interimListType))
{
return interimList;
}
// Try to get the IEnumerable<T> constructor and use that to construct the collection object
var constructor = collectionType.GetConstructor(new Type[] { ienumerableType });
if (constructor != null)
{
return constructor.Invoke(new object[] { interimList });
}
else
{
throw new NotImplementedException();
}
}
Try it online
Obviously you could optimise this by moving the list population to another method, and then maybe use your existing method as far as you can, and then use this where you can't.
I've got a generic method:
Func<IEnumerable<T>, bool> CreateFunction<T>()
where T can be any number of different types. This method does a bunch of stuff using reflection and if T is an IDictionary, regardless of the the dictionary's TKey and TValue I need to execute dictionary specific code.
So the method could be called:
var f = CreateFunction<string>();
var f0 = CreateFunction<SomePocoType>();
var f1 = CreateFunction<IDictionary<string,object>>();
var f2 = CreateFunction<Dictionary<string,object>>();
var f3 = CreateFunction<SomeDerivedDictionaryType<string,object>>();
etc.
Clarification per #Andy's answer
Ultimately I want to know if T inherits from/implements IDictionary even if T itself is Dictionary or some other type that derives from that interface.
if(typeof(T) == typeof(IDictionary<,>)
doesn't work because T is the generic type not the generic type definition.
And without knowing TKey and TValue (which are not known at compile time) I can't do a comparison to any concrete type that I would know about until runtime.
The only thing that I've come up with are looking at the type's name or inspecting its method with reflection, looking for methods that would lead me to believe it is a dictionary (i.e. look for ContainsKey and get_Item).
Is there any straightforward way to make this sort of determination?
You can avoid using ugly and potentially risky type name string checking using the IsGenericType and GetGenericTypeDefinition members, as follows:
var type = typeof (T);
if (typeof (IDictionary).IsAssignableFrom(type))
{
//non-generic dictionary
}
else if (type.IsGenericType &&
type.GetGenericTypeDefinition() == typeof (IDictionary<,>))
{
//generic dictionary interface
}
else if (type.GetInterfaces().Any(
i => i.IsGenericType &&
i.GetGenericTypeDefinition() == typeof (IDictionary<,>)))
{
//implements generic dictionary
}
The easy way is just this:
Type iDict = null;
if (typeof(T).GetGenericTypeDefinition() == typeof(IDictionary<,>))
iDict = typeof(T);
else
iDict = typeof(T).GetInterface(typeof(IDictionary<,>).Name);
if (iDict != null)
{
var genericParams = iDict.GetGenericArguments();
Type tKey = genericParams[0], tValue = genericParams[1];
}
Note that this will not work (throws an exception) if T implements more than one IDictionary<,> interface, but that will probably be fine for your purposes.
For the sake of completeness, here's an implementation that will work on types with multiple IDictionary<,> interfaces by using the first one:
Type iDict = t.GetType().GetInterfaces()
.Where(t => t.IsGenericType
&& t.GetGenericTypeDefinition() == typeof(IDictionary<,>))
.FirstOrDefault();
if (iDict != null)
{
var genericParams = iDict.GetGenericArguments();
Type tKey = genericParams[0], tValue = genericParams[1];
}
Note that in this second routine t is an object, whereas T is a type in the first routine.
You could do something like
class Program
{
static void Main(string[] args)
{
Example<IDictionary<int, string>>.IsDictionary();
Example<SortedDictionary<int, string>>.IsDictionary();
Example<Dictionary<int, string>>.IsDictionary();
Console.ReadKey();
}
}
public class Example<T>
{
public static void IsDictionary()
{
if (typeof(T).GetInterface(typeof(IDictionary<,>).Name) != null || typeof(T).Name.Contains("IDictionary"))
{
Console.WriteLine("Is IDictionary");
}
else
{
Console.WriteLine("Not IDictionary");
}
}
}
I think that if you call Type.GetGenericTypeDefinition() that should return the "base" generic type used to construct the concrete Type.
Note that just comparing this to IDictionary<,> is likely not enough, because if someone passes in an instance of Dictionary<,> I assume you would want to use that, as well. You could either check to see if the Type implements IDictionary<,> or you might be able to call Type.IsAssignableFrom(), although based on the doc I'm not sure how well this would work with generic Types.
I'm trying to fetch all ICollection<T> properties from class of unknown type. Also, type T (what the collection is of) is not known at compile time. Firstly I've tried this approach:
foreach (var property in entity.GetType().GetProperties())
{
if (typeof(ICollection).IsAssignableFrom(property.PropertyType) || typeof(ICollection<>).IsAssignableFrom(property.PropertyType))
{
// do something
}
}
but it's not working (evaluating false even for ICollection properties).
I got it working like this:
foreach (var property in entity.GetType().GetProperties())
{
var getMethod = property.GetGetMethod();
var test = getMethod.Invoke(entity, null);
if (test is ICollection)
{
// do something
}
}
but I do not want to execute all getters. Why is the first piece of code not working? How can I find ICollection properties without executing all getters?
It turns out that with IsAssignableFrom check you can't find whether the interface is a derivative of another interface:
Console.WriteLine(typeof(ICollection<>).IsAssignableFrom(typeof(ICollection<Int32>)));
Console.WriteLine(typeof(ICollection<Int32>).IsAssignableFrom(typeof(ICollection<>)));
will both write false;
With little help from here this is the best solution I can come of:
static IEnumerable<PropertyInfo> GetICollectionOrICollectionOfTProperties(this Type type)
{
// Get properties with PropertyType declared as interface
var interfaceProps =
from prop in type.GetProperties()
from interfaceType in prop.PropertyType.GetInterfaces()
where interfaceType.IsGenericType
let baseInterface = interfaceType.GetGenericTypeDefinition()
where (baseInterface == typeof(ICollection<>)) || (baseInterface == typeof(ICollection))
select prop;
// Get properties with PropertyType declared(probably) as solid types.
var nonInterfaceProps =
from prop in type.GetProperties()
where typeof(ICollection).IsAssignableFrom(prop.PropertyType) || typeof(ICollection<>).IsAssignableFrom(prop.PropertyType)
select prop;
// Combine both queries into one resulting
return interfaceProps.Union(nonInterfaceProps);
}
This solution may yield some duplicates(it is hardly possible, but to be sure use Distinct) and it doesn't look very nice.
But it works well on such class with properties with both the interface return types and concrete return types :
class Collections
{
public List<Int32> ListTProp
{
get;
set;
}
public IDictionary<Int32, String> IDictionaryProp
{
get;
set;
}
public ICollection ICollectionProp
{
get;
set;
}
public ICollection<DateTime> IDateTimeCollectionProp
{
get;
set;
}
}
After attempting to use the accepted answer I had a situation where only partial matches where being returned. My object had 3 ICollection<T> properties and I was only being returned with 2. I spent some time testing and trying to figure out why, but I moved on and wrote this:
public static IEnumerable<PropertyInfo> GetICollectionProperties(object entity)
{
return entity.GetType().GetProperties()
.Where(p => p.PropertyType.IsGenericType
&& p.PropertyType.GetGenericTypeDefinition() == typeof(ICollection<>));
}
I have tested with the same test cases and I am getting the correct results returned from this method.
This will not pick up non-generic ICollections, but the OP did ask for ICollection<T>properties, all-though it could be easily re-factored to include. It will also not return properties that are not exactly of type ICollection (ie, Eugene's List and IDictionary in his test case would not be returned (but again, what the OP wanted)).
Is there any way to determine if an object is a generic list? I'm not going to know the type of the list, I just know it's a list. How can I determine that?
This will return "True"
List<int> myList = new List<int>();
Console.Write(myList.GetType().IsGenericType && myList is IEnumerable);
Do you care to know if it's exactly a "List"... or are you ok with it being IEnumerable, and Generic?
The following method will return the item type of a generic collection type.
If the type does not implement ICollection<> then null is returned.
static Type GetGenericCollectionItemType(Type type)
{
if (type.IsGenericType)
{
var args = type.GetGenericArguments();
if (args.Length == 1 &&
typeof(ICollection<>).MakeGenericType(args).IsAssignableFrom(type))
{
return args[0];
}
}
return null;
}
Edit: The above solution assumes that the specified type has a generic parameter of its own. This will not work for types that implement ICollection<> with a hard coded generic parameter, for example:
class PersonCollection : List<Person> {}
Here is a new implementation that will handle this case.
static Type GetGenericCollectionItemType(Type type)
{
return type.GetInterfaces()
.Where(face => face.IsGenericType &&
face.GetGenericTypeDefinition() == typeof(ICollection<>))
.Select(face => face.GetGenericArguments()[0])
.FirstOrDefault();
}
The accepted answer doesn't guarantee the type of IList<>.
Check this version, it works for me:
private static bool IsList(object value)
{
var type = value.GetType();
var targetType = typeof (IList<>);
return type.GetInterfaces().Any(i => i.IsGenericType
&& i.GetGenericTypeDefinition() == targetType);
}
Try:
if(yourList.GetType().IsGenericType)
{
var genericTypeParams = yourList.GetType().GetGenericArguments;
//do something interesting with the types..
}
The question is ambiguous.
The answer depends on what you mean by a generic list.
A List<SomeType> ?
A class that derives from List<SomeType> ?
A class that implements IList<SomeType> (in which case an array can be considered to be a generic list - e.g. int[] implements IList<int>)?
A class that is generic and implements IEnumerable (this is the test proposed in the accepted answer)? But this will also consider the following rather pathological class to be a generic list:
.
public class MyClass<T> : IEnumerable
{
IEnumerator IEnumerable.GetEnumerator()
{
return null;
}
}
The best solution (e.g. whether to use GetType, IsAssignableFrom, etc) will depend on what you mean.
Theres a GetType() function in the System.Object class. Have you tried that?