DOBON.NET DOBON.NETプログラミング掲示板過去ログ

コントロールの型を指定してコピーを作成したい

環境/言語:[VB.NET 2005]
分類:[.NET]

こんにちは。

引数で渡したコントロールに対して
それと同じコントロールを生成したいと思っています。

Dim NewControl as Control
Public Sub ObjectCopyNew(ByVal Value as Control)
NewControl.Dispose()

NewControl = New Button
NewControl.Parent = Me
End Sub

この、New Buttonの部分を、引数のValueに対応したクラスとして
生成したいのですが、生成する型を動的に変更する方法がわかりません。

こちらのテクニック、
文字列で指定されたクラスのインスタンスを作成し、メソッドを実行する: .NET Tips: C#, VB.NET, Visual Studio
http://dobon.net/vb/dotnet/programing/createinstancefromstring.html

または、こちらのテクニック
Dim a As [Assembly] = GetType(Control).Assembly
http://www.atmarkit.co.jp/fdotnet/dotnettips/175createctrl/createctrl.html

の応用になってくると思うのですが
ご存じの方おられましたら教えてください。

よろしくお願いします。
■No25336に返信(FutoNekoさんの記事)
> こんにちは。
> 
> 引数で渡したコントロールに対して
> それと同じコントロールを生成したいと思っています。
> ・・・・中略・・・・
> この、New Buttonの部分を、引数のValueに対応したクラスとして
> 生成したいのですが、生成する型を動的に変更する方法がわかりません。

こんな感じになるかと思います。

Private m_newControl As Control = Nothing

Public Sub CopyControl(ByVal Value As Control)

  If (Not m_newControl Is Nothing) Then m_newControl.Dispose()

  Dim t As Type = Value.GetType()
  m_newControl = _
    DirectCast(t.InvokeMember(Nothing, _
        System.Reflection.BindingFlags.CreateInstance, _
        Nothing, Nothing, Nothing), Control)
  m_newControl.Parent = Me

End Sub
ありがとうございます。

■No25338に返信(ひらぽんさんの記事)
>>引数で渡したコントロールに対して
>>それと同じコントロールを生成したいと思っています。
> こんな感じになるかと思います。
>
> Private m_newControl As Control = Nothing
>
> Public Sub CopyControl(ByVal Value As Control)
>   If (Not m_newControl Is Nothing) Then m_newControl.Dispose()
>
>   Dim t As Type = Value.GetType()
>   m_newControl = _
>     DirectCast(t.InvokeMember(Nothing, _
>         System.Reflection.BindingFlags.CreateInstance, _
>         Nothing, Nothing, Nothing), Control)
>   m_newControl.Parent = Me
> End Sub

いくつかやり方があるようですね。
試していて、クラス名から作成すればいいのかなと思い
次のコードで動かす事ができました。

  Dim NewControl as Control
  Public Sub ObjectCopyNew(ByVal Value as Control)
    NewControl.Dispose()

    Dim a As [Assembly] = GetType(Control).Assembly
    Dim ctrlName As String = Value.GetType.ToString
    NewControl = CType(a.CreateInstance(ctrlName), Control)

    NewControl = New Button
    NewControl.Parent = Me
  End Sub

InvokeMemberのやり方についても、勉強させていただきます。
> 試していて、クラス名から作成すればいいのかなと思い
> 次のコードで動かす事ができました。

なるほど・・・

> http://www.atmarkit.co.jp/fdotnet/dotnettips/175createctrl/createctrl.html

こちらはよく見ておりませんでした。大変面白い機能です。

これ見てたら、以前「Modern C++ Design」読みながら、C++ でオブジェクトファクトリを作ったの思い出しました。

C++ にはクラス名の文字列からクラスを生成する機能がなくて
オブジェクトファクトリをゴリゴリ作ってインスタンスを生成しておりましたが、
.NET には大変面白い機能があったのですね。これは参考になりました。
■No25342に返信(FutoNekoさんの記事)
> 試していて、クラス名から作成すればいいのかなと思い
> 次のコードで動かす事ができました。
>
>   Dim NewControl as Control
>   Public Sub ObjectCopyNew(ByVal Value as Control)
>     NewControl.Dispose()
>
>     Dim a As [Assembly] = GetType(Control).Assembly
>     Dim ctrlName As String = Value.GetType.ToString
>     NewControl = CType(a.CreateInstance(ctrlName), Control)
>
>     NewControl = New Button
>     NewControl.Parent = Me
>   End Sub
ちょっと待って下さい。
CreateInstance でインスタンスを生成した後に、New Button で置き換えていませんか?
結果としては同じように見えるかもしれませんが、意味は違うのでもうちょっと見直して下さい。


CreateInstance を使わないやり方としてはジェネリックという手もあるかな。
但し、コンパイル時点で具体的な型が特定でき、その型の変数を引数に渡せることが前提になりますので、今回のやりたいこと次第では使えません。
こんにちは。
解決チェックを忘れていましたので解決にしておきます。

■No25344に返信(Azuleanさんの記事)
> CreateInstance でインスタンスを生成した後に、New Button で置き換えていませんか?
> 結果としては同じように見えるかもしれませんが、意味は違うのでもうちょっと見直して下さい。

ん?ラジオボタンを引数として渡せばラジオボタンを生成して
ボタンを渡せば、ボタンを生成
パネルを渡せば、パネルを生成
というコードが実現できれば、それでよいので
大丈夫ですよ。

あ!!確かにNew Buttonのコードは余計ですね。

ご指摘ありがとうございます。

以下、サンプルになります。

  Dim NewControl as Control
  Public Sub ObjectCopyNew(ByVal Value as Control)
    NewControl.Dispose()

    Dim a As [Assembly] = GetType(Control).Assembly
    Dim ctrlName As String = Value.GetType.ToString
    NewControl = CType(a.CreateInstance(ctrlName), Control)

    NewControl.Size = Value.Size
    NewControl.Location = Value.Location
    NewControl.Text = Value.Text
    NewControl.Parent = Me
  End Sub

こんな感じでしょうか。

> CreateInstance を使わないやり方としてはジェネリックという手もあるかな。
> 但し、コンパイル時点で具体的な型が特定でき、その型の変数を引数に渡せることが前提になりますので、今回のやりたいこと次第では使えません。

そうですね。
実行時にユーザーに選ばせる機能になりますので
ジェネリックではないですね。

ご指摘ありがとうございました。
解決済み!

DOBON.NET | プログラミング道 | プログラミング掲示板