Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting the type argument of an ICollection<T> implementing class

I am writing a little serialization library in .net. The goal is to have a replacement for XmlSerialize but easier to configure and without messing up the model with attributes.

The problem that I face is that I need the type of each ICollection<T> I find during traversing the model. The naive approach is this:

 var theType=myModel.GetType().GetGenericArguments()[0];

But it does not help for classes that derive from ICollection<T> with a specific T.

public class MyClass:A,ICollection<B>{}

I tried getting the interface with reflection

  var iCollectionInterface =
  o.GetType().GetInterfaces()
     .Where(i => i.IsGenericType)
     .Select(i => i.GetGenericTypeDefinition())
     .FirstOrDefault(i => i == typeof(ICollection<>));

but iCollectionInterface.GetGenericArguments()[0] is just T, not B because it describes only the definition of the interface and not the usage of it.

Any ideas? I also need it for IDictionary<TKey, TValue> but that is basically the same problem and will have the same solution.

Thank you!

Edit

Thank you all, here is what I ended up with:

public static Type GetTypeParameter(object o, Type typeToSearch, int argumentNumber)
{
    return o.GetType()
            .GetInterfaces()
            .Where(i => i.IsGenericType)
            .Where(i => i.GetGenericTypeDefinition() == typeToSearch)
            .Select(t => t.GetGenericArguments()[argumentNumber])
            .FirstOrDefault();
}
like image 625
Enton Avatar asked Dec 29 '25 03:12

Enton


1 Answers

From the comments it seems you need to figure out how to filter the collection to only include ICollection. You can reach that goal by:

var iCollectionInterfaces =
      from i in o.GetType().GetInterfaces()
      where i.IsGenericType 
            && i.GetGenericTypeDefinition() == typeof(IColection<>)
      select i;

You can then iterate over the collection and do whatever you need to with each type argument

//same type might implement ICollection<T> more than once
foreach(var collection in iCollectionInterfaces) {
     //More than one is invalid for ICollection<T>
    var T = collection.GetGenericArguments().Single();
    //do what ever you need
}

of course if you want to make it more generic. Ie to support interfaces/types with more than one type argument you need to remove the call to Single and replace with iteration of the type arguments

like image 197
Rune FS Avatar answered Dec 31 '25 16:12

Rune FS