Назначить поля в конструкторе с помощью Reflection Emit

Ищите решение о том, как назначать свойства с полями поддержки, которые я динамически создал в RT в конструкторе экземпляра. Подписи совпадают с сгенерированными компилятором атрибутами как авто-свойства. По сути, они будут эквивалентны коду, указанному ниже.

Использование.NET Core 2.0

Вопрос: Как мне назначить вспомогательные поля в конструкторе с помощью Emit?

Например:

public class MyClass {
  public MyClass(int f1, string f2) {
    _field1 = f1;
    _field2 = f2;
  }

  private readonly int _field1;
  private readonly string _field2;

  public int Field1 { get; }
  public string Field2 { get; }
}

private static void CreateConstructor(TypeBuilder typeBuilder, IReadOnlyList<dynamic> backingFields) {
  var constructorBuilder = typeBuilder.DefineConstructor(MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName, CallingConventions.Standard, new[] {typeof(KeyValuePair<string, string>), typeof(Dictionary<string, Type>)});
  var ctorIL = constructorBuilder.GetILGenerator();

  // Load the current instance ref in arg 0, along
  // with the value of parameter "x" stored in arg X, into stfld.

  for (var x = 0; x < backingFields.Count; x++) {
    ctorIL.Emit(OpCodes.Ldarg_0);
    ctorIL.Emit(OpCodes.Ldarg_S, x+1);
    ctorIL.Emit(OpCodes.Stfld, backingFields[x]);
  }

  ctorIL.Emit(OpCodes.Ret); 
}

  public .cctor(KeyValuePair<string, string> kvp, Dictionary<string, Type> collection) {
    _Name = kvp.Key;
    _JSON = kvp.Value;
    _PropertyInfo = collection;
  }

Переберите методы, определенные в интерфейсе, и создайте новые свойства и методы доступа с приватными сеттерами в новом типе.

  public interface IComplexType {
    string Name { get; set; }
    string JSON { get; set; }
    object PropertyInfo { get; set; }
  }

1 ответ

Решено!

Нужно изменить аргументы конструктора, чтобы они соответствовали количеству итераций, поскольку Ldarg_1 было труднее использовать KeyValuePair и соответственно назначить его Key & Value.

Устраняя KVP и предоставляя дополнительный параметр, конструктор определяется следующим образом:

  var constructorBuilder = typeBuilder.DefineConstructor(MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName, CallingConventions.Standard, new[] {typeof(string), typeof(string), typeof(Dictionary<string, Type>)});
  var ctorIl = constructorBuilder.GetILGenerator();

  for (var x = 0; x < backingFields.Count; x++) {
    ctorIl.Emit(OpCodes.Ldarg_0);
    ctorIl.Emit(OpCodes.Ldarg_S, x + 1);
    ctorIl.Emit(OpCodes.Stfld, backingFields[x]);
  }

  ctorIl.Emit(OpCodes.Ret);

Чтобы вызвать, я просто извлек содержимое KVP здесь:

  return (T) Activator.CreateInstance(TypeCollection[type], kvp.Key, kvp.Value, collection);
Другие вопросы по тегам