10

我知道以前有人问过这个问题,但我还没有看到一个简短而明确的答案,所以我希望他们不会删除这个问题,我现在会得到一个明确的答案:

我目前正在使用 C# 5.0;.NET 4.5;VS 2012。虽然我用 C# 做了很多工作,但我主要是一个 Delphi 人。

在 Delphi 中,我编写了数百个使用以下设计的类工厂(此处已简化):

unit uFactory;

interface


type

    TClassofMyClass = class of TMyClass;
    TFactoryDict = TDictionary<TMyEnum, TClassofMyClass>;

var fDict:TFactoryDict;

implementation  

procedure initDict;
begin

    fDict:=TFactoryDict.create;
    fDict.add(myEnum1, TMyClass1);
    fDict.add(myEnum2, TMyClass2);
    fDict.add(myEnum3, TMyClass3);

end;


function Factory(const aEnum: TMyEnum): TMyClass;

var

    ClassofMyClass: TClassofMyClass;

begin

    if fDict.TryGetValue(aEnum, ClassofMyClass) then

    result := ClassofMyClass.Create(aParam);

end;

end.

现在:我如何在 C# 中做这样的事情?!似乎 C# 中没有“类”类型。我错过了什么吗?如何在 C# 中简单优雅地实现这种类型的类工厂?这种设计也可以在 Python 中实现——为什么 C# 会更糟?!

4

4 回答 4

9

您可以使用类型:

Dictionary<ClassEnum, Type> TypeDictionary = new Dictionary<ClassEnum, Type>();

public void InitDictionary()
{
    TypeDictionary.Add(ClassEnum.FirstClass, typeof(FirstClass));
    //etc...
}

public object Factory(ClassEnum type)
{
    if (!TypeDictionary.ContainsKey(type))
        return null;

    var constructor = TypeDictionary[type].GetConstructor(....);
    return constructor.Invoke(....);
}

但我认为您应该使用通用方法:

public T Factory<T>(): where T is MyBaseClass
{
    var type = typeof(T);
    var constructor = type.GetConstructor(....);
    return constructor.Invoke(....) as T;
}

以下是参数化构造的多种形式:

public T Factory<T>(params object[] args): where T is MyBaseClass
{
    var argList = new List<object>(args);
    var type = typeof(T);
    var argtypes = argList.Select(o => o.GetType()).ToArray();
    var constructor = type.GetConstructor(argtypes);
    return constructor.Invoke(args) as T;
}

而且当然; 与第一个示例一样,如果找不到匹配的构造函数,它将抛出 nullpointerexception...

于 2013-04-08T07:20:16.520 回答
4
    class Potato
    {
    }

    class Potato1 : Potato
    {
        public Potato1(object[] param) { }
    }

    class Potato2 : Potato
    {
        public Potato2(object[] param);
    }

    enum MyEnum
    {
        E1, E2
    }

    Dictionary<MyEnum, Func<object[], Potato>> dict = new Dictionary<MyEnum, Func<object[], Potato>>(){
            {MyEnum.E1,(d)=>new Potato1(d)},
            {MyEnum.E2,(d)=>new Potato2(d)}
        };

    Potato Factory(MyEnum e, object[] param)
    {
        return dict[e](param);
    }
于 2013-04-08T07:27:11.967 回答
1

如果我理解你是正确的,你想引用一个静态类。这在 c# 中是不可能的。

只是工厂方法实现的一个例子:http: //www.codeproject.com/Tips/328826/implementing-Factory-Method-in-Csharp

于 2013-04-08T07:16:43.630 回答
1

C# 语言不支持元类。

所以你必须以另一种方式实现你的工厂。一种方法是在枚举上使用 switch 语句:

switch (aEnum)
{
     case myEnum1:
         return new MyClass1();
     case myEnum2:
         return new MyClass2();
     .....
}

另一个常用的选项是使用反射来完成,这将允许您编写更接近您习惯的代码。

还有一个选择是用返回对象的新实例的委托字典替换您的类字典。使用 lambda 语法,该选项会产生非常干净的代码。

反射的缺点是你放弃了编译时类型安全。因此,虽然基于反射的方法可能最接近问题中的 Delphi 代码,但这不是我个人会选择的路线。

我建议您寻找最惯用的 C# 解决方案,而不是试图将您的 Delphi 解决方案硬塞到不需要这种方法的语言中。从网络搜索类工厂开始。

于 2013-04-08T07:16:46.860 回答