2009-07-11 3 views
1

次の状況を示します。次のように私はのHttpRequestの単一パラメータを取りプロセスと呼ばれる単一抽象メソッドとコントロールと呼ばれる抽象クラスを持っているC#でのダイナミックキャスティング

<Form> 
    <Control Type="Text" Name="FirstName" /> 
    <Control Type="DateTime" Name="DateOfBirth" /> 
    <Control Type="Text" Name="PlaceOfBirth" /> 
</Form> 

、XMLドキュメントを持っています。私はまた、TextControlとDateTimeControlというControlから派生した2つのクラスを持っています。 TextとDateTimeの両方が独自の実装を提供するProcessメソッドをオーバーライドします。

私はまた、HttpRequest型の単一のパラメータを取るProcessメソッドと、XmlDocument型の単一のパラメータをとるコンストラクタを持つFormクラスを持っています。

Formの新しいインスタンスが作成され、上記のXmlがXmlDocumentパラメータ(文字列からXmlDocumentにどのように取得されるかは関係ありません)を介して渡されます。私はちょうど作成したフォームのインスタンスのProcessメソッドを呼び出し、期待どおりHttpRequest型のパラメータを渡します。

これまでのところすべて良いです。今質問に。

コントロールの処理を拡張可能にするために、クラスをコントロールタイプにマップできるようにしたいと考えています。

例えば、フォームの処理方法内

Form.RegisterControl("Text", Text) 
Form.RegisterControl("DateTime", DateTimeControl) 

Iは、文書内の各制御ノード上itterateたい(これは再び無関係で行う方法)と登録クラスに基づいて、そのタイプに一致するクラスのインスタンスをインスタンス化します私たちのRegisterControlメソッドによって。この段階では、コントロールから派生したものであることを明示できますが、明示的に型を指定することはできません。それらはどちらもControlから派生しているので、私が知っているProcessメソッドを呼びたいと思います。

これも可能ですか?もしそうなら、私はそれについてどうやって行くのですか?

答えて

4

(この答えはあなたの質問の意味に応じて、いくつかの方法で、二つの異なる答えです。うまくいけば、はそれの1つの一部が、とにかく便利です:)


おそらく最良の方法は、渡すことです適切な時刻に新しいコントロールを作成するために使用できる関数である引数で指定します。あなたがC#3を使用している場合、これは同じくらい簡単です:コントロールであるための1、およびパラメータなしのコンストラクタを持つために1:また

Form.RegisterControl("Text",() => new Text()) 

、あなたはそれの2つの制約を持つジェネリックメソッド作ることができます。

public void RegisterControl<T>(string name) where T : Control, new() 

、その後でそれを呼び出す:

Form.RegisterControl<Text>("Text"); 
Form.RegisterControl<DateTimeControl>("DateTime"); 

RegisterControlはそれが使っているものは何でもストレージにtypeof(T)を覚えているだろうが、少なくともActivator.CreateInstance(Type)は後でうまくいくことを合理的に確認することができ - あなた」コンパイル時のチェックがあります。

個人的に私は最初のフォームの柔軟性が好きです。デリゲートを渡している場合は、シングルトン、あるいはおそらく内部コンストラクタまたはプライベートコンストラクタ(どこから呼び出されているかによる)を使用するかを選択できます。あなたは、あまりにも、適切なデータを取ったデリゲートを使用することができます。

Form.RegisterControl("Text", data => new Text(data)); 

あなたは、一般的な制約にコンストラクタのその種を表現することはできません、とにかく、後で呼び出すことが比較的難しいだろう。


編集:自分自身とメドラドの両方が質問を誤解している可能性があります。あなたは実際にコントロールタイプに基づいて異なる過負荷のRegisterControlを持っていますか?そうであれば、実行時に適切なオーバーロードを直接呼び出す唯一の方法は、C#4でリフレクションを使用する方法と動的な型を使用する方法です。

もう一つの方法は、double dispatchを使う方法です。フォームに自身を登録する方法を知っています。これは、インターフェイスまたは基本クラスで指定されますが、具象サブクラスではオーバーライドされます。だから、現在お使いのコード:

Form.RegisterControl("Text", control); 

はなる:

control.RegisterWith(Form, "Text"); 

が、その後問題なく正しいオーバーロードを呼び出すことができること。

基本的には、オーバーロードの解決はコンパイル時に実行されますが、実行時にオーバーライドの解像度が実行されることを覚えておく必要があります。したがって、何かを動的にする場合は、多態性でアプローチしてください。

+0

ありがとうございました。最初の答えは正しいはずです(あなたは正しく仮定しています)。私は今それに亀裂があります! –

+0

ジョンさんに感謝します。これは完璧に機能しました。 –