この質問は、他の 2 つの質問と非常によく似ています: first、secondを参照してください。ただし、これらは控えめに言ってもかなり時代遅れであり、.Net 5 で状況が変わったことを願っています。
それでは、まず問題を明確にさせてください。の基になる配列を取得しようとする簡単な例でList<int>.
var method = new DynamicMethod("GetUnderlyingArray", typeof(int[]), new[] { typeof(List<int>) }, typeof(List<int>), true);
var ilGenerator = method.GetILGenerator();
ilGenerator.Emit(OpCodes.Ldarg_0);
ilGenerator.Emit(OpCodes.Ldfld, typeof(List<int>).GetField("_items", BindingFlags.NonPublic | BindingFlags.Instance));
ilGenerator.Emit(OpCodes.Ret);
var arrayGetter = (Func<List<int>, int[]>)method.CreateDelegate(typeof(Func<List<int>, int[]>));
これは、可視性チェックをスキップするように伝えることができるため、完全に正常に機能します (コンストラクターDynamicMethod
の最後のパラメーターが削除された場合でも同様に機能します)。DynamicMethod
true
ただし、下の例で同じことをしようとすると、FieldAccessException
.
var assemblyName = new AssemblyName("Example");
var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
var dynamicModule = assemblyBuilder.DefineDynamicModule(assemblyName.Name + ".dll");
var type = dynamicModule.DefineType("GetUnderlyingArrayClass");
var method = type.DefineMethod("GetUnderlyingArray", MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Static, typeof(int[]), new[] { typeof(List<int>) });
var ilGenerator = method.GetILGenerator();
ilGenerator.Emit(OpCodes.Ldarg_0);
ilGenerator.Emit(OpCodes.Ldfld, typeof(List<int>).GetField("_items", BindingFlags.NonPublic | BindingFlags.Instance));
ilGenerator.Emit(OpCodes.Ret);
type.CreateType();
var arrayGetter = (Func<List<int>, int[]>)type.GetMethod("GetUnderlyingArray").CreateDelegate(typeof(Func<List<int>, int[]>));
System.FieldAccessException: メソッド 'GetUnderlyingArrayClass.GetUnderlyingArray(System.Collections.Generic.List'1)' によるフィールド 'System.Collections.Generic.List'1<System.Int32>._items' へのアクセスに失敗しました。+ GetUnderlyingArrayClass.GetUnderlyingArray(リスト)
上記のコードを含む .Net フィドル リンクを次に示します。
さて、私が言及した質問の 1 つは、次の属性を指していますReflectionPermissionAttribute
。ただし、ドキュメントに記載されているとおりCode Access Security is not supported or honored by the runtime.
です。私が理解していることから、これは基本的に .Net Core/.Net 5が CAS をサポートしていないことを意味します。
ここで私は混乱しています。skipVisibility
パラメータをtrue
orに設定しても、false
実際には問題になりません。これは、コードを .Net 5 環境で実行していることが原因だと思います。ただし、CAS が .Net 5 でサポートされていない場合、プライベート フィールドを読み取ることができるのはなぜですか?
DefineType
目標は明らかに、 / DefineMethod
APIを使用して動的に生成されたメソッドからプライベート フィールド/メソッドにアクセスすることです。