実際、少なくともメモリ内で生成するときは、失敗することはありません。
簡単に、フィールドから始めましょう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;
上記のコードは、非常に漠然としています。
操作により、ランタイムが不安定になる可能性があります。
しかし、メソッドがフィールドの宣言型の内側にあるふりをすることで、それを回避します。
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 を作成するときは、はるかに高い基準が適用されます。このため、precompiler
(アセンブリを事前に生成するための) ツールは、インメモリ メタプログラミング コードとまったく同じ範囲のシナリオを処理できません。