var fieldBuilder = typeBuilder.DefineField(fieldName,
typee,
FieldAttributes.Private);
//define property
var propBuilder = typeBuilder.DefineProperty(propName, PropertyAttributes.SpecialName, typee, Type.EmptyTypes);
//define getter
var getPropMthdBldr = typeBuilder.DefineMethod($"get{fieldName}", getSetAttr, typee, Type.EmptyTypes);
var getIL = getPropMthdBldr.GetILGenerator();
getIL.Emit(OpCodes.Ldarg_0);
getIL.Emit(OpCodes.Ldfld, fieldBuilder);
getIL.Emit(OpCodes.Ret);
//define setter
var setPropMthdBldr = typeBuilder.DefineMethod($"set{fieldName}", getSetAttr, null, new Type[] { typee });
var idSetIL = setPropMthdBldr.GetILGenerator();
idSetIL.Emit(OpCodes.Ldarg_0);
idSetIL.Emit(OpCodes.Ldarg_1);
idSetIL.Emit(OpCodes.Stfld, fieldBuilder);
idSetIL.Emit(OpCodes.Ret);
// connect prop to getter setter
propBuilder.SetGetMethod(getPropMthdBldr);
propBuilder.SetSetMethod(setPropMthdBldr);
}
//create type
var type = typeBuilder.CreateType();
return type;
}
复制代码
下面让我们编写一个单元测试来测试一下:
var userClassDesc = new ClassDescription()
{
AssemblyName = "X",
ModuleName = "X",
ClassName = "User",
Properties = new List<PropertyDescription> {
new PropertyDescription {
Type = typeof(string),
Name = "Name"
},
new PropertyDescription
{
Type = typeof(int),
Name = "Age"
}
}
}; var generator = new ClassGeneratorByEmit(); var type = generator.Generate(userClassDesc); dynamic user = Activator.CreateInstance(type, null); Assert.IsNotNull(user); user.Name = "mj"; Assert.AreEqual("mj", user.Name); user.Age = 18; Assert.AreEqual(18, user.Age);
复制代码
获得 type 之后,我们使用反射来创建 User 的实例对象。然后通过 dynamic 来给属性赋值跟取值,避免了繁琐的反射代码。
运行上面的测试代码,单元测试绿色,通过了。
Roslyn
Roslyn 是微软最新开源的代码分析,编译工具。它提供了非常多的高级 API 来让用户在运行时分析代码,生成程序集、类。所以它现在是运行时代码生成的首选项。下面让我们看看怎么使用 Roslyn 来实现动态生成一个 User class 。
在使用 Roslyn 之前我们需要安装一个 nuget 包:
Microsoft.CodeAnalysis.CSharp
复制代码
我们平时正常编写的代码,其实就是一堆字符串,通过编译器编译后变成了 IL 代码。那么使用的 Roslyn 的时候过程也是一样的。我们首先就是要使用代码来生成这个 User class 的字符串模板。然后把这段字符串交给 Roslyn 去分析与编译。编译完后就可以获得这个 class 的 Type 了。