5

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): 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!

Community
  • 1
  • 1
eduncan911
  • 17,165
  • 13
  • 68
  • 104

1 Answers1

4

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
  • 6,372
  • 1
  • 29
  • 38
  • Interesting. Using an anonymous type to create an object. This has promise. +1 – eduncan911 Feb 21 '10 at 03:29
  • 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 Feb 22 '10 at 00:11
  • I have a concern with the `GetGenericTypeDefinition()[0]` index though. This limits me to only 1 `IExportableAs<>` correct? – eduncan911 Feb 22 '10 at 00:15
  • 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. Easily extended if you need more, but it doesn't make sense. You can have as many IExportableAs on a class as you like. – pdr Feb 22 '10 at 00:20
  • Just to clarify: `i.GetGenericTypeDefinition()` simply turns `IExportableAs` into `IExportableAs<>` so that it can be compared. – pdr Feb 22 '10 at 00:25