我有一个带有静态工厂方法的基类,该方法可以生成派生类:
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;
}
}
任何改善这一点的建议仍然非常受欢迎。
答案 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