C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[9]: 文字列からインスタンス作成|内部クラスへTyp


(過去ログ 70 を表示中)

[トピック内 13 記事 (1 - 13 表示)]  << 0 >>

■40623 / inTopicNo.1)  文字列からインスタンス作成|内部クラスへTypeから呼び出し
  
□投稿者/ mic (2回)-(2009/08/31(Mon) 11:24:03)

分類:[C#] 

またお世話になります。
今回「文字列からインスタンスを作成」してからそれを利用してメソッドを呼ぶプログラムを作っています。
文字列から呼ばなくてはいけない理由は、
担当しているライブラリと呼び出すライブラリが全く別の部が管理しているため直接インスタンス作成ができないのと、
いつのメソッドがスイッチによって多数の処理にわかれているためこのような仕様となっています。
これは変更できないことなので「文字列からインスタンスを作成」することを前提となっています。

今回こまったのは、「System.Math」などのインスタンスを作成することはGetType("System.Math")で可能だったのですが、内部クラスなど
「System.Diagnostics.Debug」はどうしてもNullしか返って来ずメソッドを呼ぶことができません。
いろいろやってみた結果、「System.Math、System.String、System.Int32」など入れ子になっていないものはGetTypeで苦労することなく取得できるのですが、
他の入れ子となった内部クラスなどは指定することができませんでした。
なので今回の外部ライブラリもそれが原因だと判断しています。(DLL利用時のAssembly.LoadFrom(Path)でのエラーはなく、次のGetTypeでNullでした)

このような入れ子となったクラスを文字列からインスタンスを作成するにはどのような方法があるのでしょうか?
よろしくお願いいたします。
引用返信 編集キー/
■40625 / inTopicNo.2)  Re[1]: 文字列からインスタンス作成|内部クラスへTypeから呼び出し
□投稿者/ よねKEN (413回)-(2009/08/31(Mon) 11:56:42)
No40623 (mic さん) に返信
> 文字列から呼ばなくてはいけない理由は、
> 担当しているライブラリと呼び出すライブラリが全く別の部が管理しているため直接インスタンス作成ができないのと、
> いつのメソッドがスイッチによって多数の処理にわかれているためこのような仕様となっています。
> これは変更できないことなので「文字列からインスタンスを作成」することを前提となっています。

ご説明の内容だと”文字列からインスタンス作成する”必然性の説明になっていないように思いますが、
まぁそれは横においておきます。
#他部署から受け取ったライブラリ(dll)を参照設定すれば、そのままインスタンス化できます。
#上記の説明では、参照設定ができない理由になっていないので。

> 「System.Diagnostics.Debug」はどうしてもNullしか返って来ずメソッドを呼ぶことができません。

Assembly asm = Assembly.LoadFrom(@"C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\System.dll");
Console.WriteLine(asm.GetType("System.Diagnostics.Debug"));

で取得できますが、どんなコードを書かれたのでしょうか?

> いろいろやってみた結果、「System.Math、System.String、System.Int32」など入れ子になっていないものはGetTypeで苦労することなく取得できるのですが、

mscorlib.dllに入っているクラスですね。
mscorlibは通常のアプリならデフォルトで読み込まれているので、

Type.GetType("System.Math")

というコードでも取得できますね。

引用返信 編集キー/
■40626 / inTopicNo.3)  Re[2]: 文字列からインスタンス作成|内部クラスへTypeから呼び出し
□投稿者/ なちゃ (322回)-(2009/08/31(Mon) 12:36:54)
入れ子のクラスは、
外側のフルクラス名+入れ子のクラス名
という名前になります。
※+記号で区切る必要があります。
参考まで。

引用返信 編集キー/
■40628 / inTopicNo.4)  Re[3]: 文字列からインスタンス作成|内部クラスへTypeから呼び出し
□投稿者/ 囚人 (412回)-(2009/08/31(Mon) 12:57:46)
かなり余計なお世話かと思いますが、文字列からインスタンスを作るよりは、インターフェースを定義、インスタンスはファクトリ経由で行う、などしてその辺はぼかした方がいいんじゃないでしょうか。

「文字列からインスタンスを作る(しかも大半のインスタンスを対象としている?)」はかなり最低なアイディアかと思います。コンパイル時点での解決が殆どできなくなりますよね。

引用返信 編集キー/
■40629 / inTopicNo.5)  Re[3]: 文字列からインスタンス作成|内部クラスへTypeから呼び出し
□投稿者/ mic (3回)-(2009/08/31(Mon) 12:59:49)
No40626 (なちゃ さん) に返信
■No40625 (よねKEN さん) に返信

なんとか無事に呼び出すことができました!
かなり厳密にパス指定してあげないとだめなんですね・・・。
よねKENさんの言うとおり入れ子とかよりDLLの呼び出し問題でした。
今まで何も疑うことなくSystem.Mathなどは「GetType("System.Diagnostics.Debug")」だけでAssembly.LoadFromを省いていました。

また、入れ子のパスはなちゃさんの言った通り「+」となっていました。
(テストDLLを作りTypeを直にとって検証)
おかげさまでDLLの呼び出しに成功しました!
質問には書いていませんでしたが、自分自身を文字列から呼び出すことにも成功しました!
が、少々不安が残る仕上がりです・・・。
やっぱりこういった場合にはusing{}などで呼び出し後にobjectを開放とかするべきなのでしょうか?
(自分自身のファイルを自分で読み込むという動作はプログラム的に予期しないことが起こるのではないかと不安)

using System.Reflection;

namespace WpfApplication1
{
	/// <summary>
	/// Window1.xaml の相互作用ロジック
	/// </summary>
	public partial class Window1 : Window
	{
		public Window1() { InitializeComponent(); }

		private void Button_Click(object sender, RoutedEventArgs e)
		{
			Assembly ass = Assembly.LoadFrom(System.Reflection.Assembly.GetExecutingAssembly().Location);
			Type testyep = ass.GetType("WpfApplication1.testclass+testchild");

			object inst = testyep.InvokeMember(null, System.Reflection.BindingFlags.CreateInstance, null, null, null);
			object metho = testyep.InvokeMember("testvoid", System.Reflection.BindingFlags.InvokeMethod, null, inst, new object[] { 1, "!" });
		}
	}
	public class testclass
	{
		public class testchild
		{
			public void testvoid(int i, string st) { if (i == 1 || st == "!") { System.Diagnostics.Debug.Print("OK!"); } }
		}
	}
}

引用返信 編集キー/
■40630 / inTopicNo.6)  Re[4]: 文字列からインスタンス作成|内部クラスへTyp
□投稿者/ mic (4回)-(2009/08/31(Mon) 13:13:30)
2009/08/31(Mon) 13:29:32 編集(投稿者)
2009/08/31(Mon) 13:16:57 編集(投稿者)

No40628 (囚人 さん) に返信
> かなり余計なお世話かと思いますが、文字列からインスタンスを作るよりは、インターフェースを定義、インスタンスはファクトリ経由で行う、などしてその辺はぼかした方がいいんじゃないでしょうか。
>
> 「文字列からインスタンスを作る(しかも大半のインスタンスを対象としている?)」はかなり最低なアイディアかと思います。コンパイル時点での解決が殆どできなくなりますよね。
>

自分でもめんどくさい作業となるのであまりやりたくないのですが、このようにやれとのご命令なのでw
あとなぜ文字列なのかと問い合わせた結果、
社内のセキュリティ上ファイルを読み込めてもダウンロードする行為が禁止が原因らしくDLLを文字列で叩けとのことでした。
(仕組みはだれもわからず関係ないような気も・・・
ファクトリの行動は無意識でとっていました。
問題はファクトリという言葉を知りませんでした、許してください許してください。

引用返信 編集キー/
■40637 / inTopicNo.7)  Re[5]: 文字列からインスタンス作成|内部クラスへTyp
□投稿者/ 囚人 (413回)-(2009/08/31(Mon) 14:23:07)
No40630 (mic さん) に返信
> 2009/08/31(Mon) 13:29:32 編集(投稿者)
> 2009/08/31(Mon) 13:16:57 編集(投稿者)
>
> ■No40628 (囚人 さん) に返信
>>かなり余計なお世話かと思いますが、文字列からインスタンスを作るよりは、インターフェースを定義、インスタンスはファクトリ経由で行う、などしてその辺はぼかした方がいいんじゃないでしょうか。
>>
>>「文字列からインスタンスを作る(しかも大半のインスタンスを対象としている?)」はかなり最低なアイディアかと思います。コンパイル時点での解決が殆どできなくなりますよね。
>>
>
> 自分でもめんどくさい作業となるのであまりやりたくないのですが、このようにやれとのご命令なのでw
> あとなぜ文字列なのかと問い合わせた結果、
> 社内のセキュリティ上ファイルを読み込めてもダウンロードする行為が禁止が原因らしくDLLを文字列で叩けとのことでした。
> (仕組みはだれもわからず関係ないような気も・・・
> ファクトリの行動は無意識でとっていました。
> 問題はファクトリという言葉を知りませんでした、許してください許してください。
>


いえ、どうにもならない事情はそれぞれあると思いますので、最終的には自分たちの決定で行えば良いと思います。

> 社内のセキュリティ上ファイルを読み込めてもダウンロードする行為が禁止が原因らしくDLLを文字列で叩けとのことでした。

ダウンロードが何の関係あるのかな?とは思いましたが・・・。
引用返信 編集キー/
■40666 / inTopicNo.8)  Re[5]: 文字列からインスタンス作成|内部クラスへTyp
□投稿者/ Jitta on the way (418回)-(2009/08/31(Mon) 19:41:38)
No40630 (mic さん) に返信
> あとなぜ文字列なのかと問い合わせた結果、
> 社内のセキュリティ上ファイルを読み込めてもダウンロードする行為が禁止が原因らしくDLLを文字列で叩けとのことでした。

dllを「読み込む」ということは、メモリ上にダウンロードしているとも言えるのではないかと。
ウィルスの感染を防ぐためということなら、ウィルス側としてはメモリ上に乗ってしまえば、ローカルのハードディスクにコピーされる必要はないのですけどね。
引用返信 編集キー/
■40709 / inTopicNo.9)  Re[4]: 文字列からインスタンス作成|内部クラスへTypeから呼び出し
□投稿者/ お だ (7回)-(2009/09/01(Tue) 20:26:28)
No40629 (mic さん) に返信
> ■No40626 (なちゃ さん) に返信
> ■No40625 (よねKEN さん) に返信
>
> なんとか無事に呼び出すことができました!
> かなり厳密にパス指定してあげないとだめなんですね・・・。
> よねKENさんの言うとおり入れ子とかよりDLLの呼び出し問題でした。
> 今まで何も疑うことなくSystem.Mathなどは「GetType("System.Diagnostics.Debug")」だけでAssembly.LoadFromを省いていました。
>
> また、入れ子のパスはなちゃさんの言った通り「+」となっていました。
> (テストDLLを作りTypeを直にとって検証)
> おかげさまでDLLの呼び出しに成功しました!
> 質問には書いていませんでしたが、自分自身を文字列から呼び出すことにも成功しました!
> が、少々不安が残る仕上がりです・・・。
> やっぱりこういった場合にはusing{}などで呼び出し後にobjectを開放とかするべきなのでしょうか?
> (自分自身のファイルを自分で読み込むという動作はプログラム的に予期しないことが起こるのではないかと不安)
自分自身の場合は、Type.GetType("〜"); でも問題無いですよ。(自分自身というのは、実行しているアセンブリの事と解釈しています)
http://msdn.microsoft.com/ja-jp/library/w3f99sx1.aspx MSDN Type.GetType(string) メソッドのパラメータの説明に、
「型が現在実行されているアセンブリ内または Mscorlib.dll にある場合は、名前空間で修飾された型名を提供するだけで十分です。 」
と書かれています。
また、System.Diagnostics.Debug を Type.GetType() メソッドで取得する場合は、型名 + アセンブリ名で指定すれば問題ありません。(既に System.dll が読み込まれているならば)
ただ、アセンブリはフルネームで書く必要があるので、大変かもしれません。
例:Type.GetType("System.Diagnostics.Debug,System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
※読み込まれていないアセンブリの型を取得する場合は、LoadFrom等で読み込む必要があります。
引用返信 編集キー/
■40712 / inTopicNo.10)  Re[6]: 文字列からインスタンス作成|内部クラスへTyp
□投稿者/ なちゃ (323回)-(2009/09/01(Tue) 21:13:30)
>※読み込まれていないアセンブリの型を取得する場合は、LoadFrom等で読み込む必要があります。

なぜかこの誤解をあちこちで見かけるのですが、そんなことはありません。
Type.GetType()でアセンブリ名まできちんと指定すれば、必要に応じて自動で読み込んでくれます。
既にロード済みかどうかを意識する必要はありません。
※もちろん認識できる場所にアセンブリが配置されている必要はありますが

また、明示的にロードする場合でも、認識できる場所にアセンブリが配置されている場合は、
LoadFromではなくLoadを使うのが基本です。
これもなぜかLoadFromを使った例ばかり見かけますが。

引用返信 編集キー/
■40715 / inTopicNo.11)  Re[7]: 文字列からインスタンス作成|内部クラスへTyp
□投稿者/ お だ (8回)-(2009/09/01(Tue) 22:12:38)
No40712 (なちゃ さん) に返信
> >※読み込まれていないアセンブリの型を取得する場合は、LoadFrom等で読み込む必要があります。
>
> なぜかこの誤解をあちこちで見かけるのですが、そんなことはありません。
> Type.GetType()でアセンブリ名まできちんと指定すれば、必要に応じて自動で読み込んでくれます。
> 既にロード済みかどうかを意識する必要はありません。
> ※もちろん認識できる場所にアセンブリが配置されている必要はありますが

誤った回答をしてしまい、申し訳ありませんでした。MSDN にも「GetType により、typeName で指定されたアセンブリが読み込まれます。」と書いてありました。

> また、明示的にロードする場合でも、認識できる場所にアセンブリが配置されている場合は、
> LoadFromではなくLoadを使うのが基本です。
> これもなぜかLoadFromを使った例ばかり見かけますが。
>

Load メソッドだと、GAC にあるか、プローブ による検索で見つかる場所にアセンブリが無いと読み込めないのでは?
と思い調べてみましたが、AssemblyName を渡す オーバーロード があり、CodeBase プロパティでアセンブリの場所を指定出来るんですね。
深く調べる機会を頂き、ありがとうございました。
引用返信 編集キー/
■40718 / inTopicNo.12)  Re[8]: 文字列からインスタンス作成|内部クラスへTyp
□投稿者/ なちゃ (324回)-(2009/09/01(Tue) 22:46:13)
GAC、コードベース、プローブ対象のパス以外の場所(例えば厳密名のないアセンブリをサブディレクトリ以外の場所に配置する場合など)からアセンブリを読み込むにはLoadFromを使用する必要がありますが、LoadFromは通常のLoadとは少し動作が異なります。
LoadFromでの読み込みはトラブルのもとになる可能性もあり、基本的には推奨されていません。
※やむを得ない状況というのはありますが

分かっていてあえてやる分にはいいのですが、アセンブリを読み込むのにとりあえずLoadFromというのは間違っています。
基本はLoadであり、LoadFromは特殊な要件を満たすためという明確な理由がある場合に使用するものです。

引用返信 編集キー/
■40723 / inTopicNo.13)  Re[9]: 文字列からインスタンス作成|内部クラスへTyp
□投稿者/ mic (5回)-(2009/09/01(Tue) 23:46:07)
No40718 (なちゃ さん) に返信
■No40715 (お だ さん) に返信
返信遅れてしまいました、ごめんなさい(泣
おださんの指定していただいた事では、今実行している環境はアセンブリ内(DLL内で自分自身のDLLを呼ぶ)のことなのでType指定のみで行けるはずでした。
そこで今まで出てきた注意(内部クラスには+など)を守ってLoadformを無効にしてもう一度やってみると、見事Loadfromを行うことなくTypeを取ってきました!
また、なちゃさんの指摘通り、試しにDLLを作って違うディレクトリにあるDLLをLoadで呼ぶと無事に取得することができました。

自分が自分を読み取るプログラムは感覚的に危なく思っていたので、今回のご指摘のおかげでやっと落ち着くことができました。
出来る限り自分の力のみで頑張っていこうと思いますが、また何かありましたらお力をお借り出来ますようお願いいたします。

改編後コード
string DLLOSconstantclassPath = "XXXXXXXXXXX.xxxxxxxxxxx+xxxxxxxxxxx" + "+" + xxxxxxxxxxx;

//Assembly dllassembly = Assembly.Load(System.Reflection.Assembly.GetExecutingAssembly().Location);
//Type dllclasstype = dllassembly.GetType(DLLOSconstantclassPath);

//Assembly dllassembly = Assembly.Load(System.Reflection.Assembly.GetExecutingAssembly().Location);
Type dllclasstype = Type.GetType(DLLOSconstantclassPath);

object instance = dllclasstype.InvokeMember(null, System.Reflection.BindingFlags.CreateInstance, null, null, null);
List<int> contentlist = (List<int>)instance.GetType().InvokeMember(keyname, System.Reflection.BindingFlags.GetProperty, null, instance, null);

解決済み
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -