Pluggable Frameworks and Libraries - Discovering Classes Using Reflection and Attributes
by David Hayden ( Microsoft MVP C# ), Filed: C#
Based on ExpressionEvaluators that I mentioned in the following post to help evaluate expressions in the configuration of my dependency injection tool:
One could make ExpressionEvaluators ( and any classes ) more pluggable and discoverable by putting all the ExpressionEvaluators in a single assembly ( MyExpressionEvaluators ) for simplicity and decorate them with a custom attribute. Note I am just using fake filler classes to make a point, but here are examples of ExpressionEvaluators that are annotated with an attribute and share a common interface:
[ExpressionEvaluator("AppSetting")]
public class AppSettingExpressionEvaluator
: IExpressionEvaluator
{
public string Evaluate(string expression)
{
return string.Empty;
}
}
[ExpressionEvaluator("ConnectionString")]
public class ConnectionStringExpressionEvaluator
: IExpressionEvaluator
{
public string Evaluate(string expression)
{
return string.Empty;
}
}
We can then discover and load these into a container using reflection over the assembly:
_evaluators = new Dictionary<string,IExpressionEvaluator>();
Assembly assembly = Assembly.Load("MyExpressionEvaluators");
foreach (Type type in assembly.GetTypes())
{
// Get Custom Attributes if any
ExpressionEvaluatorAttribute[] attributes =
(ExpressionEvaluatorAttribute[])type.
GetCustomAttributes(typeof(ExpressionEvaluatorAttribute),
false);
// Is this an ExpressionEvaluator
if (attributes.Length > 0 &&
typeof(IExpressionEvaluator).IsAssignableFrom(type))
{
_evaluators.Add(
attributes[0].Prefix,
Activator.CreateInstance(type) as IExpressionEvaluator);
}
}
Now we can use the evaluators to evaluate the input from the configuration:
// Pretend this is the expression coming through
// minus tokens $,{,and}
string input = "ConnectionString:MyConnectionString";
// Split into parts
string[] expressionArray = input.Split(':');
string prefix = expressionArray[0];
string expression = expressionArray[1];
// Get the evaluator
IExpressionEvaluator evaluator = _evaluators[prefix];
// Get the results
string results = evaluator.Evaluate(expression);
The use of reflections and attributes is one of a number of ways to make an application more pluggable.
Feed: David Hayden ( Microsoft MVP C# ), Filed: C#