I have a base class with a static factory method that makes derived classes:
public class Fruit
{
...
static Dictionary<string, Type> classes = new Dictionary<string, Type>
{
{"apple", typeof(Apple)}
,{"orange", typeof(Orange)}
}
public static Fruit makeFruit(string typeName) {
if(classes[typeName] == null) throw new Exception("invalid fruit type");
Fruit fruit = Activator.CreateInstance(classes[typeName]) as Fruit;
// do some intializations
return fruit;
}
}
How can I add a class derived from Fruit and let the Fruit class know about it without modifying the Fruit class code itself? Actually I need to be able to add a fruit simply by dropping in a Banana.DLL, or adding a Banana.cs file to my project. In other languages like javascript I simply add the class to Fruit’s static array right after class declaration:
function Banana()
{
...
}
Fruit.classes['banana'] = Banana;
Of course this is not possible in C#, I tried to put the code inside a static constructors but that doesn’t work either because the ctor gets called only before the first instantiation of the class. One other workaround that comes to mind is to have the base class scan all the classes defined in all assemblies to find all its derived classes and retrieve the typeName from a static string member defined in each derived class but that feels like overkill. What do you suggest?
Here is what I am doing right now after Gupta’s suggestion to use MEF:
Added a fruit info class like this:
abstract class FruitInfo
{
readonly Type type;
readonly string typeName;
public FruitInfo(Type type, string typeName)
{
this.type = type;
this.typeName = typeName;
}
}
Create a FruitInfo class for each Fruit:
class Banana : Fruit
{
...
}
[Export(typeof(FruitInfo))]
class BananaInfo : FruitInfo
{
public BananaInfo() : base(typeof(Banana), "banana") { }
};
Use this static function in Fruit to import types:
public static void importAllFruitTypes()
{
var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
var container = new CompositionContainer(catalog);
IEnumerable<FruitInfo> fruitInfos = container.GetExportedValues<FruitInfo>();
foreach(FruitInfo fruitInfo in fruitInfos) {
class[fruitInfo.typename] = fruitInfo.type;
}
}
Any suggestion to improve this is still very welcome.
If I understand correctly, then you should check MEF (Managed Extensibility Framework), check this link msdn.microsoft.com/en-us/library/dd460648.aspx