最近在ORM的实现当中碰到一个新的需求:映射一个接口或者抽象类. 问题可以简单描述为:为一个接口或抽象类生成属性的具体实现,据个例子:
有接口如下
{
int Age{get;set;}
string Name{get;set;}
}
{
protected int m_Age;
public int Age
{
get{return m_Age;}
set{m_Age=value;}
}
protected int m_Name;
public string Name
{
get{return m_Name;}
set{m_Name=value;}
}
}
解决方法有很多,我选择用Emit实现,关于Emit,网上简单的例子非常多,我只把重要的一些代码列出来:
PropertyInfo propInfo;//假设已经用反射获得某个porroperty的属性
TypeBuilder typeBuilder;//假设前面代码已经定义
//构造私有/保护成员(field)
FieldBuilder fieldBuilder = typeBuilder.DefineField("m_"+ propInfo.Name, propInfo.PropertyType, FieldAttributes.Private);
//开始构造property
PropertyBuilder propBuilder = typeBuilder.DefineProperty(propInfo.Name, PropertyAttributes.HasDefault, propInfo.PropertyType, null);
//get,set的属性(在这里可以看到get和set在.NET里面其实是一种特殊的method)
MethodAttributes methodAttribute = MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig | MehodAttributes.Virtual;
//生成方法构造器
MethodBuilder getMethodBuilder = typeBuilder.DefineMethod("get_"+ propInfo.Name, methodAttribute, propInfo.PropertyType, Type.EmptyTypes);
ILGenerator getILGen = getMethodBuilder.GetILGenerator();
//以下3行是IL,是get_XXX方法里面的具体代码
getILGen.Emit(OpCodes.Ldarg_0);
getILGen.Emit(OpCodes.Ldfld, fieldBuilder);
getILGen.Emit(OpCodes.Ret);
propBuilder.SetGetMethod(getMethodBuilder);//不要遗漏这句哦,普通的method是不需要这句的
MethodBuilder setMethodBuilder = typeBuilder.DefineMethod("set_" + propInfo.Name, methodAttribute, null, new Type[] { propInfo.PropertyType });
ILGenerator setILGen = setMethodBuilder.GetILGenerator();
//以下四行是IL,是set_XXX方法里面的具体代码
setILGen.Emit(OpCodes.Ldarg_0);
setILGen.Emit(OpCodes.Ldarg_1);
setILGen.Emit(OpCodes.Stfld, fieldBuilder);
setILGen.Emit(OpCodes.Ret);
propBuilder.SetSetMethod(setMethodBuilder);