Delphi Class of in C#

本文关键字:in of Class Delphi | 更新日期: 2023-09-27 18:08:04

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

我目前正在使用c# 5.0;net 4.5;VS 2012。我主要是Delphi的家伙,虽然我做了很多与c#。

在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#会更糟呢?

Delphi Class of in C#

您可以使用Type:

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…

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

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

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

c#语言不支持元类。

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

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

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

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

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

与其试图将Delphi解决方案硬塞进一种不需要这种方法的语言中,我建议您寻找最惯用的c#解决方案。从web搜索类工厂开始。