1

この質問は、他の 2 つの質問と非常によく似ています: firstsecondを参照してください。ただし、これらは控えめに言ってもかなり時代遅れであり、.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の最後のパラメーターが削除された場合でも同様に機能します)。DynamicMethodtrue

ただし、下の例で同じことをしようとすると、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パラメータをtrueorに設定しても、false実際には問題になりません。これは、コードを .Net 5 環境で実行していることが原因だと思います。ただし、CAS が .Net 5 でサポートされていない場合、プライベート フィールドを読み取ることができるのはなぜですか?

DefineType目標は明らかに、 / DefineMethodAPIを使用して動的に生成されたメソッドからプライベート フィールド/メソッドにアクセスすることです。

4

1 に答える 1

1

skipVisibilityパラメーターをtrue/に設定することが重要ではない理由をまだ説明できfalseませんが、 csharp ランタイム ディスカッション リポジトリの GitHub にあるPathogenDavidは、予想よりもはるかに簡単な解決策を示してくれました。

// Add IgnoresAccessChecksTo attribute
var ignoresAccessChecksTo = new CustomAttributeBuilder
(
    typeof(IgnoresAccessChecksToAttribute).GetConstructor(new Type[] { typeof(string) }),
    new object[] { typeof(List<>).Assembly.GetName().Name }
);

assemblyBuilder.SetCustomAttribute(ignoresAccessChecksTo);

実際の例については、この.Net Fiddle を参照してください。

彼が言ったように、IgnoresAccessChecksTo属性はチェックをバイパスするために使用されます。

ランタイムは属性を認識しますが、BCL で定義されていないため、自分で定義する必要があります。

于 2021-02-09T14:59:41.390 に答える