views:

80

answers:

2

I struggled to come up with a good title for this question, so suggestions are welcome.

Let's say we have an abstract base class ActionBase that looks something like this:

public abstract class ActionBase
{
    public abstract string Name { get; }
    public abstract string Description { get; }

    // rest of declaration follows
}

And we have a bunch of different actions defined, like a MoveFileAction, WriteToRegistryAction, etc. These actions get attached to Worker objects:

public class Worker
{
    private IList<ActionBase> _actions = new List<ActionBase>();
    public IList<ActionBase> Actions { get { return _actions; } }

    // worker stuff ...
}

So far, pretty straight-forward. Now, I'd like to have a UI for setting up Workers, assigning Actions, setting properties, and so on. In this UI, I want to present a list of all available actions, along with their properties, and for that I'd want to first gather up all the names and descriptions of available actions (plus the type) into a collection of the following type of item:

public class ActionDescriptor
{
    public string Name { get; }
    public string Description { get; }
    poblic Type Type { get; }
}

Certainly, I can use reflection to do this, but is there a better way? Having Name and Description be instance properties of ActionBase (as opposed to statics on derived classes) smells a bit, but there isn't an abstract static in C#.

Thank you!

+2  A: 

What you're talking about is creating Metadata for your concrete Action classes to describe them. For the simple case of Name and Description, I recommend the DisplayName and Description attributes like this:

[DisplayName("MyAction Name")]
[Description("My description goes here")]
public class MyAction : ActionBase
{
    //Declaration goes here
}

These attributes are defined in System.ComponentModel.

Dan Bryant
Thanks Dan. With that approach, would you still use reflection to gather the list?
Michael Teper
Yes, you would Reflect to locate the ActionBase derivatives and then use Attribute.GetCustomAttribute to retrieve the attributes.
Dan Bryant
What alternatives exist to reflection for this scenario?
Michael Teper
You could use an extensibility framework, such as MEF, to automate discovery of the available types, though it's using Reflection internally. Another possibility is to require any extension DLLs to explicitly register themselves (though a standard interface) and provide a list of available action types, though generally you'd be using Reflection to find the standard interface. Reflection is well-suited to this particular task, as you're doing type _discovery_, so I don't think there's really a better way.
Dan Bryant
Thanks Dan, MEF + Metadata seems like a good a answer for my needs.
Michael Teper
A: 

You could add an abstract method to ActionBase which returns an ActionDescriptor, and then you could query each action for its descriptor.

DanJ
Dan, I would still somehow have to get a list of actions.
Michael Teper
Right. I am working with a project which uses something like an ActionManager that each action registers with upon creation. The mgr can then be queried for the list of actions.
DanJ
I've implemented this pattern before. The bit that I don't like about it is that all actions have to be artifically instantiated in order to have them self-register.
Michael Teper