Using .NET reflection to determine if a Class implements a generic interface.

Reflection and me? Big friends. With all the love and hate a good friendship should have. A few days ago it was all about hate again. I had a bunch of service classes, some of them would implement a generic interface... Let's call it IHasAdorable - so a Service-Implementation could look like this:

  1. public class MarketMerchant : IHasAdorable<CheeseBurger>, IProductSeller
  2. {
  3. // defined in IHasAdorable
  4. CheeseBurger BuyAdorable()
  5. {
  6. return new AdorableCheeseburger();
  7. }
  8.  
  9. // defined in IProductSeller
  10. IProduct Buy(String eanCode)
  11. {
  12. if (eanCode.equals("12345"))
  13. return this.bigStackOfSmellyFishburgers.Pop();
  14. else
  15. throw new IAmSoSorryException("We don't have any of these!");
  16. }
  17. }

Now lets assume we want to browse through ALL market merchants and have a look if they have any adorable products. Let's skip the iteration process and pay attention to the probing of all market merchants in order to buy a adorable product from each of them. First attempt might be to use "is":

  1. IProductSeller merchant;
  2. // iteration goes here
  3. if (merchant is IHasAdorable<object>)
  4. {
  5. // this wont work. We are selling something very special, not just a stupid object!
  6. // Casting to IHasAdorable<> won't even compile.
  7. }

This one would not work either, although it makes sense to me:
  1. typeof(IHasAdorable<object>).IsAssignableFrom(merchant)

It seems we need to know what kind of objects a unknown merchant sells before we can "see" if those are also adorable. So here is how I got it working. Let me know if you do know a better solution:
  1. // `1 means there is 1 Generic parameter
  2. Type adorableInterfaceType = merchant.GetType().GetInterface("IHasAdorable`1");
  3.  
  4. if (adorableInterfaceType != null)
  5. {
  6. // yay, the merchant has adorable products, what whould those be!?
  7. Type adorableProductType = adorableInterfaceType.GetGenericArguments()[0];
  8.  
  9. // here is the magic we need to get the correct IHasAdorable Type
  10. // with "filled in" generic type.
  11. Type genericAdorableInterfaceType =
  12. typeof(IHasAdorable<>).MakeGenericType(adorableProductType);
  13. MethodInfo mi = genericAdorableInterfaceType.GetMethod("BuyAdorable");
  14. myBagOfAdorableProducts.Add(mi.invoke(merchant,null));
  15. }

Bon Appétit

Comments

maybe your love and hate got confused this time?

In this case you should continue to love generics as they saved you, yet the generics turned out to be your enemy this time... ;-)