【问题标题】:Assign fields in constructor via Reflection Emit通过反射发射在构造函数中分配字段
【发布时间】:2018-03-26 19:45:59
【问题描述】:

寻找关于如何分配带有支持字段的属性的解决方案,这些支持字段是我在实例构造函数中在 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; }
  }

【问题讨论】:

  • Code DOM 比 Refection Emit 容易得多
  • 您发布的代码似乎将构造函数参数分配给支持字段。它不工作吗?
  • 有些事情不正常。它编译并返回类型。能够创建一个实例..检查时,我缺少一些字段/属性。例如,我应该有一个包含 3 个字段的接口类。 JSON 将附加字段/属性/方法附加到有效的类中,但我试图使成员在接口中定义为只读。公共接口 IComplexType { 字符串名称 { 获取;放; } 字符串 JSON { 获取;放; } [Bindable(true)] [TypeConverter(typeof(StringConverter))] object PropertyInfo { get;放; } }
  • 我不确定 Copy Cor 是否正确。不完全确定 System.Object 和 Ld_Arg0 是否正确。我不是想创建一个静态类。这是我期望被实例化和创建的一个:dynamic tx = DynamicClass.New(new KeyValuePair(arg.Tokens[0], arg.Tokens[1]), myPropertyInfos) ; // 其中 params 是 3x args,用于填充 ctor w/params 中的 backingfields。这个类没有扩展任何东西,那么为什么在这个例子中扩展了 System.Object?
  • return (T) Activator.CreateInstance(TypeCollection[type], kvp, collection);

标签: c# reflection constructor emit backing-field


【解决方案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);

【讨论】:

    猜你喜欢
    • 2021-10-05
    • 1970-01-01
    • 1970-01-01
    • 2021-09-27
    • 1970-01-01
    • 2012-05-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多