2011-01-28 27 views
7

私は一日中、このアイデアを打ち砕いてしまいました。私は分かりません。私がやっていることはばかげて良い方法があるかもしれないが、これが私の考えが私をもたらしたところだ。型名を文字列として型にキャストするにはどうすればよいですか?

私は、WinFormsの中でフォームをロードするために、一般的なメソッドを使用しようとしています:

protected void LoadForm<T>(ref T formToShow, bool autoLoaded) where T : FormWithWorker, new() 
{ 
    // Do some stuff 
} 

形はToolStripMenuItem(項目の選択によりまたはOpen Windowsのメニュー項目を使用してのいずれか)によってロードされています。それらは遅延ロードされているため、MDI親内のフォームのフィールドがありますが、必要になるまではnullになります。私は、メニューアイテムのすべてのクリックを処理するToolStripMenuItem_Clickに使用される共通のメソッドを持っています。このメソッドは、ToolStripMenuItemの名前が、対応するフォームクラス名に対して選択されたパターンと一致することを除いて、どのフォームが呼び出されているかを知る実際の方法を持っていません。したがって、ToolStripMenuItemの名前を使用して、要求されているフォームの種類の名前と、そのフォームの参照を格納するために割り当てられたプライベートフィールドの名前を指定できます。

これを使用して、特定のタイプのセット(望ましくない)を呼び出すために、ハードコードされたタイプと文字列の一致を伴う拡大/縮小switchステートメントを使用するか、Reflectionを使用してフィールドを取得してインスタンスを作成しますタイプの。私の問題は、System.Activator.CreateInstanceは、必要な型にキャストできないObjectHandlerを提供することです。ここで私がこれまで持っているものの抜粋です:

string formName = "_form" + ((ToolStripMenuItem)sender).Name.Replace("ToolStripMenuItem", ""); 
string formType = formName.Substring(1); 

FieldInfo fi = this.GetType().GetField(formName, BindingFlags.NonPublic | BindingFlags.Instance); 

FormWithWorker formToLoad = (FormWithWorker)fi.GetValue(this); 
if (formToLoad == null) 
{ 
    formToLoad = (????)System.Activator.CreateInstance("MyAssemblyName", formType); 
} 

this.LoadForm(ref formToLoad, false); 
fi.SetValue(this, formToLoad); 

私はのために行くのタイプの文字列名を(????)知っているが、それは変化するため、コンパイル時に、私は種類を知りません。私は、このキャスト/インスタンス化を機能させるためにさまざまな方法を試しましたが、どれも成功していません。私はそれが文字列としてだけ型を知っているそのようなキャストを実行することが可能かどうかを知りたいと思うでしょう。私はType.GetType(string, string)を使ってキャストを試みましたが、コンパイラはそれを気に入らなかった。私がちょうどそれをやっているので、フォームを動的にロードする方法について誰かが別のアイデアを持っているなら、それについて私に知らせてください。

+0

formformToLoadオブジェクトを作成し、LoadFormおよびSetValueポイントでFormWithWorkerにキャストしますか? – asawyer

答えて

5

あなたがTypeと、例えば使用かかりother overloadとしたほうが良いと思いますType.GetType(string)

FormWithWorker formToLoad = (FormWithWorker)fi.GetValue(this); 
if (formToLoad == null) 
{ 
    formToLoad = 
     (FormWithWorker)System.Activator.CreateInstance(Type.GetType("MyNamespace.MyFormType")); 
} 
+0

私はある時点で、この記事で特に 'System.Activator.CreateInstance'に' .UnWrap() 'メソッドを使用したことを覚えています。それは今は言いませんが、私の問題の解決策は、基本クラスの型でプライベートフィールドを宣言してから、 'CreateInstance(" namespace "、" type ")を呼び出すことでした。これにより、適切な型が作成され、メソッドが正しくインスタンス化されました。 –

12

この問題は、通常、潜在的なすべての型の共通基底クラスまたはインターフェイスにキャストすることで解決されます。

C#4では、変数をdynamic変数に代入して戻り値を保持し、任意のメソッドを呼び出すこともできます。メソッドは遅延バインドされます。しかし、私は可能な限り元の解決策に固執することを好みます。

+0

アップ票。私はインターフェイスを使って非常に似たようなことをやったことがあり、うまく動作します。 – Chuck

+0

私はこのメソッドを試しましたが、私が遭遇した問題は、割り当てを終了した動的型が実際のクラスではなく、基本クラスであるため、SetValueメソッドを呼び出すときに型キャストの例外がスローされたということでした。 –

+0

@Joelもう一つの答えとして、オブジェクト自体を返すオーバーロードを使うべきです。どうやら、使用しているオーバーロードは.NETリモート処理オブジェクトを有効にするのに便利です。 –

2

あなたがこれを行うことができますので、あなたが持っているものによると、FormWithWorkerは、あなたがインスタンス化されているタイプの基本クラスとして(少なくとも)でなければなりません:

FormWithWorker formToLoad = (FormWithWorker)fi.GetValue(this); 
if (formToLoad == null) 
{ 
    formToLoad = (FormWithWorker)System.Activator.CreateInstance("MyAssemblyName", formType); 
} 
+0

これを試しましたが、ObjectHandlerを返す 'System.Activator.CreateInstance'メソッドのためにキャストエラーが発生しました。私は@ Andras Vassの 'Unwrap()'呼び出しのアイデアを読んで、2つを組み合わせることで次に試してみたいことがあります。 –

0

共通のインタフェースがこれをアプローチする一つの方法ですが問題は、すべてのシーンでインターフェイスが実用的ではないことです。上記の決定は、工場パターン(switch文 - 具体的なクラス選択)を使うか、リフレクションを使うかのいずれかです。この問題に取り組むスタックポストがあります。私はあなたが直接あなたの問題にこれを適用することができると信じて:

Method Factory - case vs. reflection

関連する問題