2013-04-08 16 views
10

私はこの質問が以前に尋ねられたことを知っていますが、私はまだ短い、明確な答えを見ていないので、私は彼らがこの質問を削除しないことを望んでおり、C#のDelphiクラス

私は現在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#で、このようなことを行うのですか? NO C#の 'class of'タイプのようです。何か不足していますか? C#でこのタイプのクラスファクトリを簡単かつエレガントに実装するにはどうすればよいですか?この設計はPythonでも実装できます.C#を悪化させるのはなぜですか?

+0

TMyClass1およびTMyClass2サブクラスはTMyClassですか? – Martheen

+0

@martheenはい、それはTMyClassのクラスによって強制されます –

答えて

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

との:ここで

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

は、パラメータ化された建設のための多様ですコース;最初の例と同じように、一致するコンストラクタが見つからない場合、これはnullpointerexceptionをスローします。

+0

ありがとう - これもチェックします。ここでの別の答えはInvoke()も使用しています。また、Web上でコードを使用してファクトリメソッドで使用しています。 – Vector

+1

特定のコンストラクタを持つサブクラスを強制することはできないため、これはDelphiよりも少し強力ではないことに注意してください。 (そして、C#ではパラメータのないもののコンストラクタの一般的な制約はありません) –

+2

@ O.R.Mapper:Delphiジェネリックコンストラクタの制約は、パラメータのないものにも適用されます。これは、TObjectからメタクラスが定義されているクラスまでのクラス階層で定義されているように、より具体的なコンストラクタを使用できるメタクラスを使用する場合のみです。 –

1

あなたが正しいと分かっているのであれば、静的なクラスへの参照が必要です。これはC#では不可能です。

ファクトリメソッドの実装のほんの一例: http://www.codeproject.com/Tips/328826/implementing-Factory-Method-in-Csharp

+0

Delphiの 'Class of'はmetaClassです - 表現された子孫クラスに応じて、その基本クラスのすべての子孫を総称的に表現し、多態性を使用できる型です。静的クラスとは関係ありません。 – Vector

1

C#言語は、メタクラスをサポートしていません。

したがって、別の方法でファクトリを実装する必要があります。一つの方法は、列挙型にswitchステートメントを使用することです:

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

別の一般的に使用されるオプションは、あなたがやって使っているものに近いコードを書くことができるようになる反射でそれを行うことです。

また、クラスの辞書を、オブジェクトの新しいインスタンスを返す代理人の辞書で置き換えることもできます。 λオプションを使用すると、非常にクリーンなコードが得られます。

リフレクションの欠点は、コンパイル時の型の安全性をあきらめることです。したがって、リフレクションベースのアプローチは、おそらく質問のDelphiコードに最も近いですが、私が個人的に選択するルートではありません。

あなたのDelphiソリューションをそのアプローチを望まない言語に磨くのではなく、最も慣用的なC#ソリューションを探すことをお勧めします。クラスファクトリーのWeb検索から始めます。

+0

+1 - ありがとうございます。はい、私はswitch {case:}について知っています - あなたがよく知っているように、Delphiにも列挙型があります。 「クラスファクトリーのWeb検索で始める」 - もう一度ありがとうございます。今、すべての敬意を払って、私の質問をもう一度読んでください。 :-) – Vector

+1

私はその質問を理解したと思う。つまり、Web上にさまざまなC#ファクトリのサンプルを見つけることができます。それらを見て、あなたが一番好きなアプローチを選んでください。 –

+0

+1 OPは言った: "期待して...私は今明確な答えを得るだろう" - それはウェブ検索を意味しない。そういうわけでOPがそのように言いました。 :-) – Vector

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

これは素晴らしいですね。それをチェックする必要があります。しかし、私が気づいていない '=>' C#の構文ですか、あるいはC++で間違ってミックスしましたか?私はC#でデリゲート型などでコンストラクタfuncをラップする必要があると思います。 – Vector

+5

@Mikey:これは[ラムダ式](http://msdn.microsoft.com/en-us/library/bb397687.aspx)です。 @ –

+0

@O。 R. Mapper - ありがとうございました。私は2.0以降、.NETをあまり使用していませんでした。:-)私の質問の理由の1つは、これを支援するために何か新しいことがあったかどうか疑問に思っていたことです。そこにあると思われます... – Vector

関連する問題