【问题标题】:Delphi Class of in C#C#中的Delphi类
【发布时间】:2013-03-30 04:24:12
【问题描述】:

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

我目前正在使用 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# 中有 NO 'class of ' 类型。我错过了什么吗?如何在 C# 中简单优雅地实现这种类型的类工厂?这种设计也可以在 Python 中实现——为什么 C# 会更糟糕?!

【问题讨论】:

  • TMyClass1 和 TMyClass2 是 TMyClass 的子类吗?
  • @martheen 是的,这是由 TMyClass 的类强制执行的
  • C# 中还缺少这个吗?

标签: c# .net delphi oop factory


【解决方案1】:

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

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

【讨论】:

  • 'Class of' 在 Delphi 中是一个元类 - 一种可以通用地表示该基类的所有后代的类型,并根据所表示的后代类使用多态性。与静态类无关。
【解决方案2】:

C# 语言不支持元类。

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

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

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

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

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

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

【讨论】:

  • +1 - 谢谢。是的,我知道 switch {case:} - 如你所知,Delphi 也有枚举。 '从网络搜索类工厂开始' - 再次感谢您。现在恕我直言,请再次阅读我的问题。 :-)
  • 我想我理解了这个问题。我的意思是你会在网上找到各种 C# 工厂的例子。查看它们并选择您最喜欢的方法。
  • 你得到了明确的答案。一个简单的声明,没有等价于 class of。我已经概述了实现工厂的三种可能方法。我认为一些网络搜索会产生更多的想法。您可能已经这样做了,只是想知道您是否可以使用元类来做到这一点。嗯,不完全是。最接近元类的是使用反射。
  • 但是什么?我只是说有很多方法可以做工厂。很难推荐一个。您需要做出个人选择。使用网络搜索会给你一些超出这里的额外想法。有什么害处?虽然我个人想不出除了我所概述的之外的任何想法,但我敢打赌有一些!
  • 这就是我不同意的地方。最接近您的代码的是基于反射的方法。但我会选择代表字典。我认为您需要针对该语言进行编程,而不是尝试将一种语言解决方案用于一种不适合的语言。我个人不喜欢反射方法。除非没有干净的替代方案,否则我会避免反思。这就是我最后一段的重点。
【解决方案3】:

你可以使用类型:

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

当然还有;和第一个例子一样,如果找不到匹配的构造函数,这将抛出一个空指针异常......

【讨论】:

  • 谢谢 - 也会检查一下。这里的另一个答案也使用 Invoke() ,我在网络上看到代码也在工厂方法中使用它。
  • 请注意,这没有 Delphi 强大,因为您不能强制/依赖具有特定构造函数的子类。 (除了 C# 中的无参数构造函数之外,构造函数没有通用约束。)
  • @O.R.Mapper:Delphi 泛型构造函数约束也适用于无参数约束。只有在使用元类时,您才能使用在从 TObject 到定义元类的类的类层次结构中定义的更具体的构造函数。
  • @MarjanVenema:没错,我指的是 C# 比 Delphi 的元类略逊一筹。
  • @Stig-Rune Skansgård - 我也不需要 Delphi 中带有基于枚举的键的字典,但代码在 webServer 上运行,该服务器接受发送到工厂的基于 XML 的请求,因此枚举和字典使它更容易 - 可以轻松地表示 XML 中的枚举并将 XML 枚举直接发送到工厂。当然,有时我会使用参数化构造函数。
【解决方案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);
    }

【讨论】:

  • @Mikey:那是lambda expression
  • C#中没有...的数组MyEnum不是很可惜
  • 是否需要Invoke,或者可以写dict[e]()
  • @Martheen 存在于 Oxygene 中。我也相信元类。我不认为 .net 施加了很多限制。
  • @Mikey 编辑了我的答案。如果需要,object[] 可以更改为更具体的示例
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-21
相关资源
最近更新 更多