Скажем, у меня есть следующий код, который обновляет поле struct
с использованием отражения. Поскольку экземпляр 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 в многократно используемый делегат (скажем, используя функцию Dynamic Method). В частности, я хочу заменить указанный выше код на 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, который вызывает сеттер с использованием отражения (как 1-й сегмент кода в этом сообщении). Это не имеет смысла, поскольку требование состоит в том, чтобы избавиться от рефлексии, но это возможная реализация, поэтому я просто упоминаю.
- Вместо использования
Action<object, object>
используйте пользовательский делегат, подпись которогоpublic delegate void Setter(ref object target, object value)
. - Вместо
Action<object, object>
используйтеAction<object[], object>
, когда 1-й элемент массива является целевым объектом.
Причина, по которой мне не нравятся 2 и 3, состоит в том, что я не хочу иметь разных делегатов для установщика объекта и сеттера структуры (а также не хочу, чтобы делегировать делегат объекта set-object чем необходимо, например, Action<object, object>
). Я полагаю, что реализация CreateSetIdDelegate
создавала бы другой CIL в зависимости от того, является ли целевой тип структурой или объектом, но я хочу, чтобы он возвращал тому же делегату, предлагающему пользователю тот же API.