2012/03/23
method2について、会社でもう少し楽が出来る方法を若様に教わったので修正。
2012/03/21
C# + .NET FrameworkでReflectionを使う際のメモ書き。
うまくまとまった解説をなかなか見つけられなかったので、個人的に調べてわかった範囲でサンプルコードを書いてメモとする。
あるメーカーが提供する製品のSDK、新バージョン毎にSDK用DLLを出してくるので、これを利用するプログラムを毎回リコンパイルする必要があった。 毎回行うのがしんどくなってきたので、リフレクションで解決できないか、というのが動機。
Assembly クラスでターゲットのアセンブリ(DLL)をロードしてアクセスする。
メソッド、プロパティ、フィールドへはInvoke(),InvokeMember()でアクセスする。ただこの際の引数指定が色々面倒。
あとから機能追加するとか、プラグイン形式で機能追加するとか、そういった理由が無いならリフレクションは使わないほうがいい。遅いよ。
それに、IDEでメソッド名とかの補完が出来ないからターゲットのDLLの内容をきちんと押さえておく必要もある。
動的呼び出しするDLL。reflectioncheck.dll の名前で生成しておく。
using System; namespace reflectionCheck { public enum sampleEnum { tas, low, kau, wah }; public class positionClass { public int ipos; public positionClass(sampleEnum pos) { ipos = (int)pos; } } public class targetClass { private String str1; public String propStr { get { return str1; } set { str1 = value; } } public String method1(sampleEnum ff) { return ff.ToString(); } public String method2(sampleEnum[] ff) { String ans = ""; for (int i=0; i< ff.Length; i++) { switch (ff[i]) { case sampleEnum.kau: ans += "か;"; break; case sampleEnum.low: ans += "ろ;"; break; case sampleEnum.tas: ans += "た;"; break; case sampleEnum.wah: ans += "わ;"; break; } } return ans; } public positionClass method3(sampleEnum ff) { positionClass ans = new positionClass( ff ); return ans; } } }
DLLを呼び出すEXE。reflectioncheckcall.exe の名前で生成しておく。
using System; using System.Collections; using System.Reflection; using System.IO; namespace reflectioncheckcall { class Program { static void Main(string[] args) { String here = Path.GetDirectoryName( Assembly.GetExecutingAssembly().Location ) + @"\reflectioncheck.dll"; // 同じフォルダにDLLがあることを前提とする Assembly reflectionCheckDLL = Assembly.LoadFrom(here); Type TtargetClass = reflectionCheckDLL.GetType("reflectionCheck.targetClass",true); Type TpositionClass = reflectionCheckDLL.GetType("reflectionCheck.positionClass", true); Type TsampleEnum = reflectionCheckDLL.GetType("reflectionCheck.sampleEnum", true); // reflectionCheck.targetClass を生成(コンストラクタなし) Object oTargetClass = Activator.CreateInstance(TtargetClass, true); // reflectionCheck.positionClass を生成(コンストラクタあり) Object oPositionClass5 = TpositionClass.InvokeMember(null, BindingFlags.CreateInstance, null, null, new Object[] { TsampleEnum.InvokeMember("wah", BindingFlags.GetField, null, null, null) }); // 生成したtargetClassのpropStrプロパティに設定 TtargetClass.InvokeMember("propStr", BindingFlags.SetProperty, null, oTargetClass, new Object[] { "ABCD" }); // reflectionCheck.sampleEnumの生成と値設定 Object oSampleEnum = TsampleEnum.InvokeMember("low", BindingFlags.GetField, null, null, null); // reflectionCheck.sampleEnum[]の生成と値設定 ArrayList oSampleEnums = new ArrayList(); oSampleEnums.Add(TsampleEnum.InvokeMember("kau", BindingFlags.GetField, null, null, null)); oSampleEnums.Add(TsampleEnum.InvokeMember("low", BindingFlags.GetField, null, null, null)); oSampleEnums.Add(TsampleEnum.InvokeMember("tas", BindingFlags.GetField, null, null, null)); // targetClassのpropStrプロパティ読み出し String s1 = (String)TtargetClass.InvokeMember("propStr", BindingFlags.GetProperty, null, oTargetClass, null); // targetClassのmethod1メソッド呼び出し String s2 = (String)TtargetClass.InvokeMember("method1", BindingFlags.InvokeMethod, null, oTargetClass, new Object[] { oSampleEnum }); // targetClassのmethod2メソッド呼び出し String s3 = (String)TtargetClass.InvokeMember("method2", BindingFlags.InvokeMethod, null, oTargetClass, new Object[] { oSampleEnums.ToArray(TsampleEnum) }); // targetClassのmethod3メソッド呼び出し Object oPositionClass4 = TtargetClass.InvokeMember("method3", BindingFlags.InvokeMethod, null, oTargetClass, new Object[] { oSampleEnum }); String s4 = oPositionClass4.ToString(); // positionClassのiposフィールド読み出し String s5 = ((int)TpositionClass.InvokeMember("ipos", BindingFlags.GetField, null, oPositionClass5, null)).ToString(); Console.WriteLine("propStr : {0}", s1); Console.WriteLine("method1 : {0}", s2); Console.WriteLine("method2 : {0}", s3); Console.WriteLine("method3 : {0}", s4); Console.WriteLine("ipos : {0}", s5); return; } } }