views:

151

answers:

2

Hi people!

I'm working with a C# plugin architecture. Plugins are DLL's which expose a bunch of presenters, which are objects that implement the IPresenter interface. The IPresenter interface is available in a DLL shared by all plugins. Presenters can also implement additional methods as defined by IAction interfaces, like ILoadAction, ISaveAction etc. These interfaces are also shared by the same DLL so all plugins can have presenters that implement such interfaces.

Case: I have presenter X in plugin A which implements the IPresenter interface and the ILoadAction interface. In plugin B, I ask the plugin architecture to give me a presenter X. This gives me an IPresenter object. To call the LoadAction method of that presenter, I have to cast the presenter to ILoadAction.

Problem: if I remove ILoadAction from presenter X in plugin A, the code in plugin B will still compile even though the presenter doesn't implement ILoadAction anymore. In such cases, I'd like to be warned by the compiler. Actually, I'd like to avoid having to cast to a certain IAction all the time...

Question: how to deal with that?

A: 

Two options:

  1. Check your object (use 'as') instead of just casting it (and update your program logic to deal with the case the object does not implement the interface)
  2. Add an interface to your shared DLL that allows a plugin to inform others of its capabilities, and provides strongly typed methods to obtain implementations of the various interfaces. All plugins should then implement this interface, and use its methods to get references to capabilities in other plugins.
Fried Hoeben
These options will not actually cause a compile time error if you remove the interface as described in your Problem, but that can never be a compile time error since the whole point of your plugin approach seems to be that plugins are not explicitly coupled to each others capabilities, but can have 'additional methods'.If you want compile time checks: just make it mandatory for all plugins to implement ILoadAction...
Fried Hoeben
-1 That doesn't sound like an extensible architecture. Imagine that after having developed hundreds of implementations you now need to add another 'capability'. This would mean adding another method to the interface, and thus breaking hundreds of implementations.
Mark Seemann
+2  A: 

I'm afraid that the compiler won't help you here. Plugin A can be changed at any time, before, during or after B is build, so your plugin architecture needs to cope with the possible loss of interfaces - either return null values for the interface or throw an exception.

As for the getting items of the right type, this can be acheived using generics:

T IPresenter.GetAction <T> where T : class, IAction ()
{
   return (T) GetAction (typeof T)
}

so the cast is done in the GetAction method rather than the caller (sort of):

var action = PluginA.GetAction <ILoadAction> ();

EDIT:

If doing the <> in the call is too much, try:

bool GetAction<T> (out T a) where T : class, IAction
{
  // stuff
  return interface_found; // or throw an exception?
}

Then you can do:

ILoadAction action;
if (!PluginA.GetAction (out action))
{
   // failed to get interface!
}
Skizz