在C#编程世界中,动态类型生成是一项强大而又神秘的技术。无论是开发插件系统、构建ORM框架,还是实现代码生成工具,运行时动态创建类型的能力都能让我们的应用更加灵活和强大。本文将带您深入了解C#中的动态类型生成技术,掌握这一高级开发技能。
在传统的静态编译语言中,类型通常在编译时确定。但在某些场景下,我们需要在程序运行时根据外部数据或条件动态创建新的类型:
Reflection.Emit
是.NET框架提供的最强大的动态类型生成工具,它允许我们在IL(中间语言)级别创建新类型。
C#using System.Reflection.Emit;
using System.Reflection;
namespace AppReflectionEmit
{
internal class Program
{
public static Type CreateDynamicType()
{
// 创建动态程序集
AssemblyName assemblyName = new AssemblyName("DynamicAssembly");
AssemblyBuilder assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(
assemblyName, AssemblyBuilderAccess.Run);
// 创建模块
ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("DynamicModule");
// 定义类型
TypeBuilder typeBuilder = moduleBuilder.DefineType(
"DynamicPerson", TypeAttributes.Public | TypeAttributes.Class);
// 添加字段
FieldBuilder nameField = typeBuilder.DefineField(
"_name", typeof(string), FieldAttributes.Private);
// 创建构造函数
ConstructorBuilder constructorBuilder = typeBuilder.DefineConstructor(
MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName,
CallingConventions.Standard,
new[] { typeof(string) });
// 生成构造函数的 IL 代码
ILGenerator constructorIL = constructorBuilder.GetILGenerator();
constructorIL.Emit(OpCodes.Ldarg_0);
constructorIL.Emit(OpCodes.Call, typeof(object).GetConstructor(Type.EmptyTypes));
constructorIL.Emit(OpCodes.Ldarg_0);
constructorIL.Emit(OpCodes.Ldarg_1);
constructorIL.Emit(OpCodes.Stfld, nameField);
constructorIL.Emit(OpCodes.Ret);
// 添加属性
PropertyBuilder nameProperty = typeBuilder.DefineProperty(
"Name", PropertyAttributes.HasDefault, typeof(string), null);
// 创建 getter 方法
MethodBuilder getterMethod = typeBuilder.DefineMethod(
"get_Name",
MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig,
typeof(string),
Type.EmptyTypes);
ILGenerator getterIL = getterMethod.GetILGenerator();
getterIL.Emit(OpCodes.Ldarg_0);
getterIL.Emit(OpCodes.Ldfld, nameField);
getterIL.Emit(OpCodes.Ret);
// 创建 setter 方法
MethodBuilder setterMethod = typeBuilder.DefineMethod(
"set_Name",
MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig,
null,
new[] { typeof(string) });
ILGenerator setterIL = setterMethod.GetILGenerator();
setterIL.Emit(OpCodes.Ldarg_0);
setterIL.Emit(OpCodes.Ldarg_1);
setterIL.Emit(OpCodes.Stfld, nameField);
setterIL.Emit(OpCodes.Ret);
// 将方法与属性关联
nameProperty.SetGetMethod(getterMethod);
nameProperty.SetSetMethod(setterMethod);
// 创建最终类型
return typeBuilder.CreateType();
}
static void Main(string[] args)
{
// 创建动态类型
Type dynamicPersonType = CreateDynamicType();
// 创建实例
object personInstance = Activator.CreateInstance(dynamicPersonType, "张三");
// 获取属性
PropertyInfo nameProperty = dynamicPersonType.GetProperty("Name");
// 读取属性值
object nameValue = nameProperty.GetValue(personInstance);
Console.WriteLine($"姓名: {nameValue}"); // 输出: 姓名: 张三
// 设置新值
nameProperty.SetValue(personInstance, "张三丰");
Console.WriteLine($"修改后姓名: {nameProperty.GetValue(personInstance)}");
Console.ReadKey();
}
}
}
上面的代码演示了如何使用Reflection.Emit创建一个完整的动态类型。这个例子看似复杂,但它展示了以下几个关键步骤:
我们可以进一步扩展上面的示例,添加自定义方法和事件:
C#using System.Reflection.Emit;
using System.Reflection;
namespace AppReflectionEmit
{
internal class Program
{
public static Type CreateDynamicType()
{
// 创建动态程序集
AssemblyName assemblyName = new AssemblyName("DynamicAssembly");
AssemblyBuilder assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(
assemblyName, AssemblyBuilderAccess.Run);
// 创建模块
ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("DynamicModule");
// 定义类型
TypeBuilder typeBuilder = moduleBuilder.DefineType(
"DynamicPerson", TypeAttributes.Public | TypeAttributes.Class);
// 添加字段
FieldBuilder nameField = typeBuilder.DefineField(
"_name", typeof(string), FieldAttributes.Private);
// 添加事件字段
FieldBuilder eventField = typeBuilder.DefineField(
"NameChangedEvent", typeof(EventHandler), FieldAttributes.Private);
// 创建构造函数
ConstructorBuilder constructorBuilder = typeBuilder.DefineConstructor(
MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName,
CallingConventions.Standard,
new[] { typeof(string) });
// 生成构造函数的 IL 代码
ILGenerator constructorIL = constructorBuilder.GetILGenerator();
constructorIL.Emit(OpCodes.Ldarg_0);
constructorIL.Emit(OpCodes.Call, typeof(object).GetConstructor(Type.EmptyTypes));
constructorIL.Emit(OpCodes.Ldarg_0);
constructorIL.Emit(OpCodes.Ldarg_1);
constructorIL.Emit(OpCodes.Stfld, nameField);
constructorIL.Emit(OpCodes.Ret);
// 添加属性
PropertyBuilder nameProperty = typeBuilder.DefineProperty(
"Name", PropertyAttributes.HasDefault, typeof(string), null);
// 创建 getter 方法
MethodBuilder getterMethod = typeBuilder.DefineMethod(
"get_Name",
MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig,
typeof(string),
Type.EmptyTypes);
ILGenerator getterIL = getterMethod.GetILGenerator();
getterIL.Emit(OpCodes.Ldarg_0);
getterIL.Emit(OpCodes.Ldfld, nameField);
getterIL.Emit(OpCodes.Ret);
// 创建 setter 方法
MethodBuilder setterMethod = typeBuilder.DefineMethod(
"set_Name",
MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig,
null,
new[] { typeof(string) });
ILGenerator setterIL = setterMethod.GetILGenerator();
// 保存旧名称用于比较
Label skipEvent = setterIL.DefineLabel();
LocalBuilder oldNameLocal = setterIL.DeclareLocal(typeof(string));
setterIL.Emit(OpCodes.Ldarg_0);
setterIL.Emit(OpCodes.Ldfld, nameField);
setterIL.Emit(OpCodes.Stloc, oldNameLocal);
// 设置新名称
setterIL.Emit(OpCodes.Ldarg_0);
setterIL.Emit(OpCodes.Ldarg_1);
setterIL.Emit(OpCodes.Stfld, nameField);
// 触发事件
setterIL.Emit(OpCodes.Ldarg_0);
setterIL.Emit(OpCodes.Ldfld, eventField);
setterIL.Emit(OpCodes.Ldnull);
setterIL.Emit(OpCodes.Ceq);
setterIL.Emit(OpCodes.Brtrue, skipEvent);
setterIL.Emit(OpCodes.Ldarg_0);
setterIL.Emit(OpCodes.Ldfld, eventField);
setterIL.Emit(OpCodes.Ldarg_0);
setterIL.Emit(OpCodes.Ldnull);
setterIL.Emit(OpCodes.Callvirt, typeof(EventHandler).GetMethod("Invoke"));
setterIL.MarkLabel(skipEvent);
setterIL.Emit(OpCodes.Ret);
// 将方法与属性关联
nameProperty.SetGetMethod(getterMethod);
nameProperty.SetSetMethod(setterMethod);
// 添加自定义方法 Introduce
MethodBuilder introduceMethod = typeBuilder.DefineMethod(
"Introduce",
MethodAttributes.Public,
typeof(string),
Type.EmptyTypes);
ILGenerator introduceIL = introduceMethod.GetILGenerator();
// 创建字符串:"我的名字是" + Name
introduceIL.Emit(OpCodes.Ldstr, "我的名字是");
introduceIL.Emit(OpCodes.Ldarg_0);
introduceIL.Emit(OpCodes.Call, getterMethod);
introduceIL.Emit(OpCodes.Call, typeof(string).GetMethod("Concat", new[] { typeof(string), typeof(string) }));
introduceIL.Emit(OpCodes.Ret);
// 添加事件
EventBuilder nameChangedEvent = typeBuilder.DefineEvent(
"NameChanged",
EventAttributes.None,
typeof(EventHandler));
// 添加事件的 add 方法
MethodBuilder addMethod = typeBuilder.DefineMethod(
"add_NameChanged",
MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig,
null,
new[] { typeof(EventHandler) });
ILGenerator addIL = addMethod.GetILGenerator();
addIL.Emit(OpCodes.Ldarg_0);
addIL.Emit(OpCodes.Ldarg_0);
addIL.Emit(OpCodes.Ldfld, eventField);
addIL.Emit(OpCodes.Ldarg_1);
addIL.Emit(OpCodes.Call, typeof(Delegate).GetMethod("Combine", new[] { typeof(Delegate), typeof(Delegate) }));
addIL.Emit(OpCodes.Castclass, typeof(EventHandler));
addIL.Emit(OpCodes.Stfld, eventField);
addIL.Emit(OpCodes.Ret);
// 添加事件的 remove 方法
MethodBuilder removeMethod = typeBuilder.DefineMethod(
"remove_NameChanged",
MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig,
null,
new[] { typeof(EventHandler) });
ILGenerator removeIL = removeMethod.GetILGenerator();
removeIL.Emit(OpCodes.Ldarg_0);
removeIL.Emit(OpCodes.Ldarg_0);
removeIL.Emit(OpCodes.Ldfld, eventField);
removeIL.Emit(OpCodes.Ldarg_1);
removeIL.Emit(OpCodes.Call, typeof(Delegate).GetMethod("Remove", new[] { typeof(Delegate), typeof(Delegate) }));
removeIL.Emit(OpCodes.Castclass, typeof(EventHandler));
removeIL.Emit(OpCodes.Stfld, eventField);
removeIL.Emit(OpCodes.Ret);
// 将方法与事件关联
nameChangedEvent.SetAddOnMethod(addMethod);
nameChangedEvent.SetRemoveOnMethod(removeMethod);
// 创建最终类型
return typeBuilder.CreateType();
}
static void Main(string[] args)
{
// 创建动态类型
Type dynamicPersonType = CreateDynamicType();
// 创建实例
object personInstance = Activator.CreateInstance(dynamicPersonType, "张三");
// 获取属性
PropertyInfo nameProperty = dynamicPersonType.GetProperty("Name");
// 添加事件处理程序
EventInfo nameChangedEvent = dynamicPersonType.GetEvent("NameChanged");
EventHandler handler = (sender, e) => Console.WriteLine("名称已更改!");
nameChangedEvent.AddEventHandler(personInstance, handler);
// 读取属性值
object nameValue = nameProperty.GetValue(personInstance);
Console.WriteLine($"姓名: {nameValue}");
// 调用 Introduce 方法
MethodInfo introduceMethod = dynamicPersonType.GetMethod("Introduce");
string introduction = (string)introduceMethod.Invoke(personInstance, null);
Console.WriteLine(introduction);
// 设置新值 (这将触发事件)
nameProperty.SetValue(personInstance, "张三丰");
Console.WriteLine($"修改后姓名: {nameProperty.GetValue(personInstance)}");
// 再次调用 Introduce 方法
introduction = (string)introduceMethod.Invoke(personInstance, null);
Console.WriteLine(introduction);
Console.ReadKey();
}
}
}
如果只需要简单的动态对象,而不是完整的类型定义,ExpandoObject
是一个更简单的选择:
C#using System.Reflection.Emit;
using System.Reflection;
using System.Dynamic;
namespace AppReflectionEmit
{
internal class Program
{
static void Main(string[] args)
{
dynamic person = new ExpandoObject();
// 动态添加属性
person.Name = "李四";
person.Age = 30;
person.Address = "北京市海淀区";
// 动态添加方法
person.Introduce = new Func<string>(() =>
$"大家好,我是{person.Name},今年{person.Age}岁,住在{person.Address}");
// 调用动态添加的方法
Console.WriteLine(person.Introduce());
// 输出: 大家好,我是李四,今年30岁,住在北京市海淀区
// 作为字典使用
var personDict = (IDictionary<string, object>)person;
personDict["Profession"] = "软件工程师";
// 遍历所有属性
foreach (var prop in personDict)
{
Console.WriteLine($"{prop.Key}: {prop.Value}");
}
Console.ReadKey();
}
}
}
ExpandoObject
的优点是使用简单,无需编写IL代码,但它只能创建单个对象实例,不能定义可复用的类型。
表达式树是C#函数式编程的强大工具,可用于创建动态委托和LINQ查询:
C#using System.Reflection.Emit;
using System.Reflection;
using System.Dynamic;
using System.Linq.Expressions;
namespace AppReflectionEmit
{
internal class Program
{
static void Main(string[] args)
{
// 创建表达式参数
ParameterExpression x = Expression.Parameter(typeof(int), "x");
ParameterExpression y = Expression.Parameter(typeof(int), "y");
// 创建复杂表达式: (x * 2) + (y * y)
Expression multiplyX = Expression.Multiply(x, Expression.Constant(2));
Expression squareY = Expression.Multiply(y, y);
Expression body = Expression.Add(multiplyX, squareY);
// 编译为强类型委托
Func<int, int, int> calculator = Expression.Lambda<Func<int, int, int>>(
body, x, y
).Compile();
// 使用动态创建的委托
Console.WriteLine($"计算结果: {calculator(5, 3)}");
// 创建更复杂的条件表达式
Expression condition = Expression.GreaterThan(x, y);
Expression ifTrue = Expression.Multiply(x, y);
Expression ifFalse = Expression.Subtract(x, y);
Expression conditional = Expression.Condition(condition, ifTrue, ifFalse);
// 编译条件表达式
Func<int, int, int> conditionalCalc = Expression.Lambda<Func<int, int, int>>(
conditional, x, y
).Compile();
Console.WriteLine($"x=5, y=3时: {conditionalCalc(5, 3)}");
Console.WriteLine($"x=3, y=5时: {conditionalCalc(3, 5)}");
Console.ReadKey();
}
}
}
表达式树的优势在于:
动态类型生成会带来一定的性能开销:
C#public class DynamicTypePerformanceDemo
{
// 使用缓存避免重复创建相同类型
private static readonly Dictionary<string, Type> _typeCache =
new Dictionary<string, Type>();
public static Type GetOrCreateDynamicType(string typeName, List<PropertyInfo> properties)
{
// 创建唯一的类型键
string typeKey = $"{typeName}_{string.Join("_", properties.Select(p => $"{p.Name}_{p.PropertyType.Name}"))}";
// 检查缓存
if(_typeCache.TryGetValue(typeKey, out Type cachedType))
{
return cachedType;
}
// 创建新类型
Type newType = CreateDynamicTypeWithProperties(typeName, properties);
// 添加到缓存
_typeCache[typeKey] = newType;
return newType;
}
private static Type CreateDynamicTypeWithProperties(string typeName, List<PropertyInfo> properties)
{
// 实现动态类型创建
// ...
}
}
C#的动态类型生成技术提供了强大的元编程能力,使开发者能够构建更灵活、更强大的应用程序。虽然这些技术有一定学习曲线,但掌握它们将极大地扩展您的编程视野。
随着.NET的发展,我们可以期待更多改进:
无论您是开发框架、库还是应用程序,动态类型生成技术都能为您的项目带来巨大价值,值得每一位C#开发者深入学习。
本文作者:技术老小子
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!