Armed with a text editor

mu's views on program and recipe! design

C# Internationalization Limits Posted 2006.05.29 07:31 PDT (#)

I need a trick. I want to build a plugin system in C# that supports internationalization. I want to be able to create various interfaces (called IPlugin here for simplicity) which classes in the plugins can implement so the framework knows how to load them. The framework must also able to get metadata from them in order to describe them to the user. What are my options?

Here's what I've come up with so far. I can create two interfaces, IPluginFactory and IPlugin when I only really want one. This is potentially useful anyway for a number of reasons so I might go with it. It would look something like this:

interface IPluginFactory
{
    string Name { get; }
    string Description { get; }
    IPlugin Load(string filename);
    IPlugin New(string filename);
    ...
}

interface IPlugin
{
    string PrettyName { get; }
    void Save();
    ...
}

Here IPluginFactory is implemented by a thin wrapper class which gives me data about the class implementing IPlugin which it knows how to manage. In the Name get method I can easly load and return Strings.MyString to retrieve a localized value. And all the meat can go into the IPlugin class. Thus it's cheap to instantiate all IPluginFactory classes, and put off instantiating a given IPlugin until I need it.

But isn't this sort of static metadata and creation needs exactly what attributes and static factory functions are for? Rather than having to implement two classes for every IPlugin, it would be nicer to just attribute one class.

[PluginInfo(Strings.PluginName, Strings.PluginDesc)]
class MyPlugin : IPlugin
{
    static MyPlugin Load(string filename) { ... }
    static MyPlugin New(string filename) { ... }
    
    string PrettyName { get { ... } }
    void Save() { ... }
}

But there are two problems with this approach:

  1. I can't create static methods in interfaces, and
  2. I can't use non-constant expressions in Attributes.

Between the two it means I can't easily enforce (compile-time) an implementation of the static methods, and I can't put localized strings into Attributes at all, as they all require runtime resource lookup. Because I can't put static properties in an interface, I also can't simply work around the second by putting the strings into static properties, although since unattributed classes aren't errors either, it's less of a compile time issue.

What ideas am I missing? I can use, but don't particularly like, the two interface approach. An inventive developer could probably implement both interfaces on one class, although it would only rarely be worth it, and would miss the point of having a thin wrapper class. I really like the look of the attributed single interface sample code. How close can I get?