Late binding plugin example for .Net

Just the urls, ma'am.
Post Reply
Jason
Veteran Doodler
Posts: 1520
Joined: Fri Jul 18, 2003 12:53 am
Location: Fairfax, VA

Late binding plugin example for .Net

Post by Jason »

http://www.divil.co.uk/net/articles/plugins/plugins.asp

For anyone who has to do some .Net stuff, this is useful to know.

Peijen
Minion to the Exalted Pooh-Bah
Posts: 2790
Joined: Fri Jul 18, 2003 2:28 pm
Location: Irvine, CA

Post by Peijen »

Not too bad. I would've done it slightly differently.

First I would use events and callbacks rather than IHost implementation. IHost increases coupling for no good reason. Using events and callbacks the host is the consumer while the plugin is the producer no mixing role. With IHost both host and plugin are consumer and producer at the same time.

Second I would use attribute rather than which interface is implemented for plugin discovery. If you want to use any sort of delegation pattern such as chain of responsibility or flyweight you can't hide private classes because they might implement the same interface. Attribute also allows you to add extra information about the plugin.

Jason
Veteran Doodler
Posts: 1520
Joined: Fri Jul 18, 2003 12:53 am
Location: Fairfax, VA

Post by Jason »

I don't quite understand what you mean. Remind me to ask you about this the next time I see you.

George
Veteran Doodler
Posts: 1267
Joined: Sun Jul 18, 2004 12:26 am
Location: Arlington, VA

Post by George »

I was playing around with stuff like this for one of my many never-finished test tools. I think I may even have read this article as part of that. It's a very cool idea, but unfortunately I got bogged down writing one component and gave up.

I agree with Peijen's comment about the IHost being pointless for most plugins.

The use of attributes for discovery is interesting, though I think you'd still have to use a common interface per plugin category to be practical. I don't think being aware of the "hidden" class is a problem at all. The entire point of a plugin is that the program is able to work with anything matching the interface. If Plugins A and B both implement your interface, why should you be denied access to Plugin B just because A happens to call it? Limiting choices of plugins should be done by the application, not by the plugin architecture.

Peijen
Minion to the Exalted Pooh-Bah
Posts: 2790
Joined: Fri Jul 18, 2003 2:28 pm
Location: Irvine, CA

Post by Peijen »

Oh yeah, you still need to use interface but use attribute for discovery. Here is how it might work

Code: Select all

public class PluginAttribute : Attribute
{ // implement some properties for the attribute }

public interface IObjectA {}
public interface IObjectB {}
public interface IFactory
{
  IObjectA CreateObjectA();
  IObjectB CreateObjectB();
}
And the plugin

Code: Select all

[Plugin("name", "description")]
public class Factory : IFactory { /*...*/ }

private class JoeSucksFactory : IFactory { /*...*/ }
private class VinnySucksFactory : IFactory { /*...*/ }
Even though JoeSucksFactory and VinnySucksFactory are marked as private they are still visible through Reflection. With attribute, only Factory class would be visible and instantiated by the host, and the Factory class can determine which inner factory to use base on whatever parameter you choose.

His code does check for public classes, but I still think it's not as elegant.
Last edited by Peijen on Thu Jun 22, 2006 2:40 pm, edited 1 time in total.

Peijen
Minion to the Exalted Pooh-Bah
Posts: 2790
Joined: Fri Jul 18, 2003 2:28 pm
Location: Irvine, CA

Post by Peijen »

George wrote:I don't think being aware of the "hidden" class is a problem at all. The entire point of a plugin is that the program is able to work with anything matching the interface. If Plugins A and B both implement your interface, why should you be denied access to Plugin B just because A happens to call it? Limiting choices of plugins should be done by the application, not by the plugin architecture.
Let's say your plugin does something with a text editor. You wanted it to behave differently depend on which language is in the text editor. With the example I gave you can have CShareFactory and VBFactory, but you don't necessary want both to be present to elimited jerky mouse. The problem is even more critical if when you run VB plugin for C# causes the computer to be reformatted or something equally bad.

Jason
Veteran Doodler
Posts: 1520
Joined: Fri Jul 18, 2003 12:53 am
Location: Fairfax, VA

Post by Jason »

Well, I still don't understand ...

George
Veteran Doodler
Posts: 1267
Joined: Sun Jul 18, 2004 12:26 am
Location: Arlington, VA

Post by George »

Peijen wrote:Let's say your plugin does something with a text editor. You wanted it to behave differently depend on which language is in the text editor. With the example I gave you can have CShareFactory and VBFactory, but you don't necessary want both to be present to elimited jerky mouse. The problem is even more critical if when you run VB plugin for C# causes the computer to be reformatted or something equally bad.
Hmm, I'd always believed that implementing an interface should guarantee certain behaviors/expectations beyond just the method signature. It seems like to make a decision, you must be passing some kind of context to your DecisionMakerFactory. But the same context passing must be present in VBFactory (it's the same interface, otherwise we wouldn't be having this discussion). If DecisionMakerFactory is the only class aware of VBFactory's limitations, then VBFactory is silently ignoring that context and not behaving according to the interface. It seems like what you really want is DecisionMakerFactory to implement IPlugin and VBFactory and CSharpFactory to implement the IFactory. IPlugin and IFactory might have similar signatures, but the expectations are different so they can't be the same type.

If I wanted the plugins to be chosen automatically, I would have probably implemented a method along the lines of bool DoISupportThisSituation(SituationDescription) and queried them to decide which to use. That way, each class is aware of its own limitations. In the past, I've always used UI or configuration files (not the standard .NET ones) to determine which plugins to load and used a query method to determine when to use them (though usually I cached the results by creating some kind of list).

Peijen
Minion to the Exalted Pooh-Bah
Posts: 2790
Joined: Fri Jul 18, 2003 2:28 pm
Location: Irvine, CA

Post by Peijen »


Post Reply