4

Say we have several assemblies, and they all implement IAnimal, and we'd like go to one place to find out about the presence of the other IAnimal implementation.

features:

  • we don't want pre-knowledge outside of an assembly

  • there could be a register class / method within the assembly

  • it is preferable not to use reflection. So far this seems to be the only way though

discussion:

I imagined doing this statically via inheritance, however, I'm not aware of an assembly level initialization sequence.

Cameron
  • 96,106
  • 25
  • 196
  • 225
sgtz
  • 8,849
  • 9
  • 51
  • 91
  • 10
    Discovering types dynamically at execution time is practically the *definition* of reflection... I can't imagine any other way of doing it. – Jon Skeet Aug 05 '11 at 12:50
  • @Jon Skeet: No answers are good. Maybe I can live with an [IAmAIAnimalRegistrar] attribute. Now to think about efficient discovery via LINQ. Via convention? Is it not possible (see: http://stackoverflow.com/questions/96317/how-do-you-get-the-root-namespace-of-an-assembly). Ahh. Could define the same Registration namespace in each assembly. That might work. – sgtz Aug 05 '11 at 13:04
  • 1
    All of these things are going to require reflection sooner or later... – Jon Skeet Aug 05 '11 at 13:12
  • Implement a factory in that assembly. The assembly itself has no trouble knowing what classes implement an interface. – Hans Passant Aug 05 '11 at 13:21
  • I've got a kind of Factory proxy going on. Still need to be able to find each factory in a naive way though. – sgtz Aug 05 '11 at 13:41

3 Answers3

6

I suggest taking a look at MEF. It is practically designed for this kind of thing.

It does use reflection, as this is the mechanism created for such dynamic discovery. I doubt you will find a solution that doesn't use some level of reflection.

Oded
  • 489,969
  • 99
  • 883
  • 1,009
  • I did look at this a while back. It's probably over the top for now. It appears that even MEF still uses meta data though. – sgtz Aug 05 '11 at 12:58
1

I've written an extension method which allows you to look up deployed Types which match certain criteria at runtime - it does use Reflection, but you may find it useful.

IEnumerable<Type> animalTypes = Assembly.GetExecutingAssembly()
    .GetAvailableTypes(
        typeFilter: t => !t.IsInterface && typeof(IAnimal).IsAssignableFrom(t));
Steve Wilkes
  • 7,085
  • 3
  • 29
  • 32
1

When starting your app you could register to the AssemblyLoad of your AppDomain:

AppDomain.CurrentDomain.AssemblyLoad += new AssemblyLoadEventHandler(NewAssemblyLoaded);

and define NewAssemblyLoad to add the IAnimal implementations to a list of Types (e.g. animalTypes) you maintain:

static void NewAssemblyLoaded(object sender, AssemblyLoadEventArgs args)
{
    Assembly anAss = args.LoadedAssembly;
    foreach (Type t in Assembly.GetTypes())
    {
        if (!t.IsInterface && typeof(IAnimal).IsAssignableFrom(t))
            animalsList.Add(t);
    }
}
Francesco Baruchelli
  • 7,320
  • 2
  • 32
  • 40
  • Neat touch. Is this a way to be naive about what is loaded and when? – sgtz Aug 05 '11 at 13:49
  • Yes, you just have to be sure that the assemblies containing IAnimal implementation are loaded after the subscription to the event (and of course you shouldn't change your AppDomain) – Francesco Baruchelli Aug 05 '11 at 13:52
  • 'just'. Sounds like I'd need two approaches -- subscribe + scan all now. Is there a way to guarantee assembly load order? – sgtz Aug 05 '11 at 14:43
  • If you put the event subscription as the first instruction of your Main method everything should work just fine – Francesco Baruchelli Aug 05 '11 at 15:09