views:

184

answers:

1

My 1st objective is to filter the types based on a specific interface with a generic.

My 2nd objective is to obtain the type of the generic parameter itself.

public UserService : IUserService, IDisposable, IExportableAs<IUserService>
{
  ...
}

I cannot assume the structure of the class, its interfaces (if any at all) or alike. The only thing I know I am targetting ExportableAs<T> from my shared assembly that was used to create this plugin. But yet, I need to register the type dynamically.

So, I am using a generic interface to mark the type to export. In this case, it's IUserService. I am doing this assuming some nifty Linq query can give me what I want. But, I am having a little trouble.

Here's what I have so far:

assembly.GetTypes()
    .Where(t => t.GetInterfaces().Any(i => 
                i.IsGenericType &&
                i.GetGenericTypeDefinition() == typeof(IExportableAs<>))
            ).ToList()
    .ForEach(t => _catalogs.Add(
            new ComposablePart()
            {
                Name = t.FullName,
                Type = t // This is incorrect
            })
        );

This is working, but notice the comment above for "This is incorrect". This type is the derived class of UserService.

What I need in my end result are:

  • The generic type pass into the IExportableAs<T> (IUserService in this case)
  • The derived class type (in this case, UserService)

This question got a good up-vote as it got me close (as you can see above): http://stackoverflow.com/questions/503263/how-to-determine-if-a-type-implements-a-specific-generic-interface-type But, I need to go one step further in finding that generic type.

Feel free to mangle my linq above.

Thanks in advance!

+3  A: 

Got it

assembly.GetTypes().SelectMany(t => t.GetInterfaces(), (t, i) => new { t, i })
    .Where(ti => ti.i.IsGenericType &&
                 ti.i.GetGenericTypeDefinition() == (typeof(IExportableAs<>)))
    .Select(ti => new ComposablePart() {
        Name = ti.t.FullName,
        Type = ti.i.GetGenericArguments()[0]
    });

[Edit] In my excitement, I didn't leave my test program running long enough to throw an Exception on the interface that wasn't generic. Thought the .NET Framework had been especially clever there. Corrected code now that I know it isn't.

pdr
Interesting. Using an anonymous type to create an object. This has promise. +1
eduncan911
Yep, that was it. Note though, you are creating a 2nd anonymous type in the Select() clause. It should be: `.Select(ti => new ComposablePart() { Name = ti.t.FullName, Type = ti.i.GetGenericArguments()[0] });` Or else, it will not convert to a known type on a ToList().
eduncan911
I have a concern with the `GetGenericTypeDefinition()[0]` index though. This limits me to only 1 `IExportableAs<>` correct?
eduncan911
Sorry about the error; I couldn't be bothered to define ComposablePart in my test app :). I'll fix that. There is no `GetGenericTypeDefinition()[0]` - there is a `GetGenericArguments()[0]` which limits you only to one type T in each generic type IExportableAs<T>. Easily extended if you need more, but it doesn't make sense. You can have as many IExportableAs<T> on a class as you like.
pdr
Just to clarify: `i.GetGenericTypeDefinition()` simply turns `IExportableAs<T>` into `IExportableAs<>` so that it can be compared.
pdr
Yep. Thanks man!
eduncan911