Динамически назначить поле - PullRequest
1 голос
/ 17 февраля 2020

Я пытаюсь сгенерировать код для динамического присвоения значений поля динамическому c классу. По сути, в этом случае я бы хотел что-то сделать:

il.Emit(OpCodes.Ldarg_0); // Object instance
il.Emit(OpCodes.Ldc_I4_0); // Value to assign to the field
il.Emit(OpCodes.Ld???, fieldInfo); // FieldInfo to assign the value to
il.Emit(OpCodes.Stfld); // Some kind of Stfld that pops the field and the value and assigns it

Я не смог найти ни одной инструкции, которая бы соответствовала моим потребностям. У меня была еще одна идея - сгенерировать метод установки для каждого поля и вызвать этот метод, но я не нашел способа сделать это без преобразования его в делегат, который генерировал бы много шаблонного кода.

У кого-нибудь есть лучшее решение?

РЕДАКТИРОВАТЬ: Проблема в том, что поле, которое должно быть назначено, должно быть найдено в стеке, и каким-то образом всплывающее окно, когда время назначить его приходит. К сожалению, ни одна из инструкций CIL не поддерживает извлечение fieldInfo для назначения ему, но, возможно, есть другие решения, о которых я не задумывался.

EDIT2: я расскажу немного больше об окружающем сценарии, надеюсь, контекст прояснит ситуацию.

Я пытаюсь сделать своего рода «перекомпилятор» из стекового байт-кода vm в CIL. Рассматриваемый байт-код не обращается к полям в структуре, как это делает CIL, то есть статически. Вместо этого ссылка на поле, к которому осуществляется доступ, помещается в стек, а инструкция store позаботится об остальном.

Вот пример того, как может выглядеть этот байт-код:

PushFloat 0.0
PushField [someField]
SetField

То, что я хотел бы получить, было бы похоже на код, который я написал выше, но CIL поддерживает присваивание только тем полям, которые известны во время кодирования.

1 Ответ

1 голос
/ 17 февраля 2020

Я решил это, используя ldflda и stind:

il.Emit(OpCodes.Ldarg_0); // Object instance
il.Emit(OpCodes.Ldflda, fieldInfo); // Loads reference to field
il.Emit(OpCodes.Conv_U); // Converts to pointer
il.Emit(OpCodes.Ldc_I4_0); // Something to put in the field
il.Emit(OpCodes.Stind_I4); // Put the value in the field

Что, похоже, делает примерно то, что я изначально намеревался сделать.

...