実際には、私はに失敗する可能性があります。少なくとも、メモリに生成すると、に失敗します。
のは、(ので、我々はすべてのaccessebilityルールを破っていない)public readonly
フィールドで、簡単に始めましょう。私の最初の試みは、以下のとおりであり、それは正常に動作します:
using System;
using System.Reflection;
using System.Reflection.Emit;
class Foo
{
public readonly int i;
public int I { get { return i; } }
public Foo(int i) { this.i = i; }
}
static class Program
{
static void Main()
{
var setter = CreateWriteAnyInt32Field(typeof(Foo), "i");
var foo = new Foo(123);
setter(foo, 42);
Console.WriteLine(foo.I); // 42;
}
static Action<object, int> CreateWriteAnyInt32Field(Type type, string fieldName)
{
var field = type.GetField(fieldName,
BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
var method = new DynamicMethod("evil", null,
new[] { typeof(object), typeof(int) });
var il = method.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Castclass, type);
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Stfld, field);
il.Emit(OpCodes.Ret);
return (Action<object, int>)method.CreateDelegate(typeof(Action<object, int>));
}
}
フィールドがprivate
であれば、それは面白いだけの時間がある:
private readonly int i;
上記のコードその後、OH-SO-漠然とを与えます:
操作は、ランタイムを不安定化させることができます。
しかし、我々はこの方法は、フィールドの宣言型の内側にあることをふりをすることにより、その回避:
var method = new DynamicMethod("evil", null,
new[] { typeof(object), typeof(int) }, field.DeclaringType);
他のいくつかの内部チェックがskipVisibility
を有効にすることによって行うことができます。
var method = new DynamicMethod("evil", null,
new[] { typeof(object), typeof(int) }, field.DeclaringType, true);
しかし、スタンドアローンアセンブリを生成する場合、このすべてが可能ではないことに注意してください。実際のDLLを作成する際には、より高い基準が適用されます。このため、(アセンブリをあらかじめ生成するための)ツールでは、メモリ内メタプログラミングコードで可能なシナリオと全く同じ範囲を処理できません。
すぐに確認します。たぶん私の問題は厳密に読み取り専用フィールドに関連していなかったでしょう。面白いことに、私のコードはMonoで動作し、.NETでは動作しません。 –
Doh。私はDeclaringTypeを提供できませんでした。しかし今、私はそれがなぜ機能するのだろうかと思います。オブジェクトのコンストラクタからのみ読み込み可能フィールドに書き込み可能にすべきではありませんか?とにかく答えてくれてありがとう。 –
@PiotrZierhofferコンパイラやPEVerifyでのみ多くのことが強制されます。最終的には、リフレクションを介して 'readonly'フィールドを変更することができますし、シリアライザ/マテリアライザーは**コンストラクタを完全にスキップします**その場合、値を代入する方法はありません –