C# 将动态类型的属性添加到动态类型
我正在尝试创建类似以下内容的动态类型:C# 将动态类型的属性添加到动态类型,c#,C#,我正在尝试创建类似以下内容的动态类型: public class DataObjects { public DataObjectsLesser1 SomeRandom0 { get; } public DataObjectsLesser2 SomeRandom1 { get; } } public class DataObjectsLesser1 { public int Prop0 { get; } } public class DataObjectsLesser2 {
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; }
}
下面的完整代码示例是real程序的简化版本,它使用第三方api创建树结构,您可以在其中导航嵌套类型
在实际的程序中,我可以轻松地创建顶级类型的DataObjects,以及DataObjectsLesser1/2的空版本。问题是,当我想创建DataObjectsLesser1/2的属性时——如果要复制错误——则忽略最内部循环中的值“Prop”+num,而将值“SomeRandom”+I*10用作属性名称。我看不出有任何逻辑上的原因,因为类型是按预期设置的(示例中为int) 我也不知道如何验证示例中发生了什么。我在实例变量中获得了一个动态类型,其中包含我生成的属性,但每个属性都不显示为类型化的-只有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;
}
}
}
关于你的第二个问题: 我需要浏览对象图进行测试
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;
}
}
}
我想到的最简单的方法是将动态程序集保存到磁盘,然后在或其他反编译器中查看它。为此,请指定AssemblyBuilderAccess.RunAndSave
选项到defineddynamicassembly
方法,并在defineddynamicmodule
方法中提供文件名:
AssemblyBuilder assemblyBuilder = Thread.GetDomain().DefineDynamicAssembly(assembly, AssemblyBuilderAccess.RunAndSave);
ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule(assembly.Name,
"temp.dll");
然后在末尾添加:
assemblyBuilder.Save("temp.dll");
“如果要复制错误”?我已经试过你的代码,它似乎工作正常,所以我想知道我们能如何帮助你。@konRadkokosa我的最后一段呢?谢谢,正如我在回答中所说的,我建议简单地将其保存到磁盘。我恐怕这不起作用,错误消息出现在第一行:mscorlib.dll中出现“System.NotSupportedException”类型的未处理异常。其他信息:瞬态程序集中不能有持久化模块。这也是需要定义的DynamicAssembly(assembly,AssemblyBuilderAccess.RunAndSave),请更新您的answer@Jaycee是的,我忘记提了。我刚刚更新了我的答案。