将类型名称映射到派生类

时间:2012-07-25 11:08:30

标签: c#

我有一个带有静态工厂方法的基类,该方法可以生成派生类:

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;
    }
}

如何添加一个派生自Fruit的类,让Fruit类知道它而不修改Fruit类代码本身?实际上我需要能够通过放入Banana.DLL或者在我的项目中添加Banana.cs文件来添加水果。在其他语言中,例如javascript,我只需在类声明之后将类添加到Fruit的静态数组中:

function Banana()
{
    ...
}
Fruit.classes['banana'] = Banana;

当然这在C#中是不可能的,我试图将代码放在静态构造函数中,但这不起作用,因为ctor仅在类的第一次实例化之前被调用。我想到的另一个解决方法是让基类扫描所有程序集中定义的所有类,以查找其所有派生类,并从每个派生类中定义的静态字符串成员中检索typeName,但这听起来有点过分。你有什么建议?


在Gupta建议使用MEF之后,我现在正在做的事情是:

添加了这样的水果信息类:

abstract class FruitInfo
{
    readonly Type type;
    readonly string typeName;

    public FruitInfo(Type type, string typeName)
    {
        this.type = type;
        this.typeName = typeName;
    }
}

为每个Fruit创建一个FruitInfo类:

class Banana : Fruit
{
    ...
}

[Export(typeof(FruitInfo))]
class BananaInfo : FruitInfo
{
    public BananaInfo() : base(typeof(Banana), "banana") { }
};

在Fruit中使用此静态函数导入类型:

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;
    }
}

任何改善这一点的建议仍然非常受欢迎。

2 个答案:

答案 0 :(得分:2)

你必须寻找继承Fruit的类,但你无法到处看。您需要定义要查看的程序集。如果所有类都在同一个程序集中,那么很容易:

var types = Assembly.GetAssembly(tyepof(Fruit)).GetTypes();
var derived = types.Where(t => t.IsSubclassOf(typeof(Fruit)).Select(t => new { t.Name, t });

答案 1 :(得分:1)

如果我理解正确,那么您应该检查MEF(托管扩展框架),查看此链接msdn.microsoft.com/en-us/library/dd460648.aspx