struct
使用中のリフレクションのフィールドを更新する次のコードがあるとします。DynamicUpdate
構造体インスタンスはメソッドにコピーされるため、渡される前にオブジェクトにボックス化する必要があります。
struct Person
{
public int id;
}
class Test
{
static void Main()
{
object person = RuntimeHelpers.GetObjectValue(new Person());
DynamicUpdate(person);
Console.WriteLine(((Person)person).id); // print 10
}
private static void DynamicUpdate(object o)
{
FieldInfo field = typeof(Person).GetField("id");
field.SetValue(o, 10);
}
}
コードは正常に機能します。さて、リフレクションは遅いので使いたくないとしましょう。代わりに、フィールドを直接変更するCILを生成id
し、そのCILを再利用可能なデリゲートに変換します(たとえば、動的メソッド機能を使用)。特に、上記のコードを次のようなs/tに置き換えたいと思います。
static void Main()
{
var action = CreateSetIdDelegate(typeof(Person));
object person = RuntimeHelpers.GetObjectValue(new Person());
action(person, 10);
Console.WriteLine(((Person)person).id); // print 10
}
private static Action<object, object> CreateSetIdDelegate(Type t)
{
// build dynamic method and return delegate
}
私の質問:CreateSetIdDelegate
次のテクニックのいずれかを使用する以外に実装する方法はありますか?
- リフレクションを使用してセッターを呼び出すCILを生成します(この投稿の最初のコードセグメントとして)。リフレクションを取り除くことが要件であることを考えると、これは意味がありませんが、実装の可能性があるので、ここで説明します。
- を使用する代わりに
Action<object, object>
、署名が。であるカスタムデリゲートを使用しますpublic delegate void Setter(ref object target, object value)
。 Action<object, object>
を使用する代わりにAction<object[], object>
、配列の最初の要素をターゲットオブジェクトとして使用します。
2と3が好きではない理由は、オブジェクトのセッターと構造体のセッターに異なるデリゲートを設定したくないためです(また、set-object-fieldデリゲートを必要以上に複雑にしたくないためです。例Action<object, object>
)。の実装でCreateSetIdDelegate
は、ターゲットタイプが構造体かオブジェクトかによって異なるCILが生成されると思いますが、同じAPIをユーザーに提供する同じデリゲートを返すようにしたいです。