将动态类型的属性添加到动态类型

时间:2013-12-18 17:26:09

标签: c#

我正在尝试创建类似于此的动态类型:

public class DataObjects
{
  public DataObjectsLesser1 SomeRandom0 { get; }
  public DataObjectsLesser2 SomeRandom1 { get; }
}

public class DataObjectsLesser1 
{
  public int Prop0 { get; }
}

public class DataObjectsLesser2
{
  public int Prop0 { get; }
}

以下完整的代码示例是真实程序的缩减版本,它使用第三方API创建一个树结构,您可以在其中导航嵌套类型。

在真实程序中,我可以轻松创建顶级类型DataObjects以及DataObjectsLesser1 / 2的空版本。问题是当我想创建DataObjectsLesser1 / 2的属性时 - 如果要复制错误 - 则忽略最内层循环中的值“Prop”+ num 并且值< strong>“SomeRandom”+ i * 10 用于属性名称。我没有看到任何合乎逻辑的原因,因为类型是按预期设置的(示例中为int)。

我也不知道如何验证示例中发生了什么。我在实例var中获得了一个带有我生成的属性的动态类型,但是每个属性都没有出现类型 - 只是null属性,无法告诉我们生成了什么类型。我需要浏览对象图以进行测试。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Threading;

namespace TyeTes
{
    internal class Program
    {
        private static void CreateProperty(TypeBuilder typeBuilder, Type propertyType, string propertyName)
        {
            FieldBuilder fieldBuilder = typeBuilder.DefineField(propertyName + "X", propertyType, FieldAttributes.Private);
            PropertyBuilder propertyBuilder = typeBuilder.DefineProperty(propertyName, PropertyAttributes.HasDefault, propertyType, null);
            MethodBuilder propertyGetter = typeBuilder.DefineMethod("get_" + propertyName, MethodAttributes.Public |
                                                MethodAttributes.SpecialName | MethodAttributes.HideBySig, propertyType, Type.EmptyTypes);
            ILGenerator randomPropertyGetterIL = propertyGetter.GetILGenerator();
            randomPropertyGetterIL.Emit(OpCodes.Ldarg_0);
            randomPropertyGetterIL.Emit(OpCodes.Ldfld, fieldBuilder);
            randomPropertyGetterIL.Emit(OpCodes.Ret);
            propertyBuilder.SetGetMethod(propertyGetter);
        }

        private static void Main(string[] args)
        {
            var assembly = new AssemblyName("FieldTypes");
            AssemblyBuilder assemblyBuilder = Thread.GetDomain().DefineDynamicAssembly(assembly, AssemblyBuilderAccess.Run);
            ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule(assembly.Name);
            TypeBuilder typeBuilder = DefineType(moduleBuilder, "DataObjects");

            foreach (var i in Enumerable.Range(0, 3))
            {
                TypeBuilder subTypeBuilder = DefineType(moduleBuilder, "DataObjectsLesser" + i);
                foreach (var num in Enumerable.Range(0, 2))
                {
                    CreateProperty(subTypeBuilder, typeof(int), "Prop" + num);
                }
                CreateProperty(typeBuilder, subTypeBuilder.CreateType(), "SomeRandom" + i * 10);
            }
            Type randomType = typeBuilder.CreateType();
            var instance = Activator.CreateInstance(randomType);
        }

        public static TypeBuilder DefineType(ModuleBuilder modBuilder, string typeName)
        {
            TypeBuilder typeBuilder = modBuilder.DefineType(typeName,
                TypeAttributes.Public |
                TypeAttributes.Class |
                TypeAttributes.AutoClass |
                TypeAttributes.AnsiClass |
                TypeAttributes.BeforeFieldInit |
                TypeAttributes.AutoLayout,
                typeof(object));
            return typeBuilder;
        }
    }
}

1 个答案:

答案 0 :(得分:2)

关于你的第二个问题:

  

我需要浏览对象图以进行测试。

我想到的最简单的方法是将动态程序集保存到磁盘,然后在ILSpy或其他反编译器中查看它。为此,请为AssemblyBuilderAccess.RunAndSave方法指定DefineDynamicAssembly选项,并使用DefineDynamicModule方法提供文件名:

AssemblyBuilder assemblyBuilder = Thread.GetDomain().DefineDynamicAssembly(assembly, AssemblyBuilderAccess.RunAndSave);
ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule(assembly.Name, 
                                                                 "temp.dll");

最后添加:

assemblyBuilder.Save("temp.dll");