关于Emit中动态类型TypeBuilder创建类标记的一点思考

时间:2021-03-17 17:22:29

 

利用TypeBuilder是可以动态创建一个类型,现在有个需求,动态生成一个dll,创建类型EmployeeEx,需要继承原dll里面的Employee类,并包含Employee类上的所有类标记。

 

网上有很多例子,

//创建TypeBuilder。
TypeBuilder myTypeBuilder = myModBuilder.DefineType(typeName,
TypeAttributes.Public); myTypeBuilder.SetParent(type);

 

大概处理方式如下:

CustomAttributeBuilder customAttributeBuilder = new CustomAttributeBuilder(typeof(SerializableAttribute).GetConstructor(Type.EmptyTypes), new Type[] { });
myTypeBuilder.SetCustomAttribute(customAttributeBuilder); att = type.GetCustomAttributes(typeof(DefaultPropertyAttribute), false);
if (att != null && att.Length > 0) {
DefaultPropertyAttribute dea = att[0] as DefaultPropertyAttribute;
customAttributeBuilder = new CustomAttributeBuilder(typeof(DefaultPropertyAttribute).GetConstructor(new Type[] { typeof(string) }), new object[] { dea.Name });
myTypeBuilder.SetCustomAttribute(customAttributeBuilder);
}

 

但是,这些都是已知类标记是Serializable或者DefaultProperty,如果原dll中的Employee再加个自定义标记,我们还需要再改程序,如何能够动态继承到类标记,TypeBuilder.SetCustomAttribute提供了2个重载SetCustomAttribute(CustomAttributeBuilder customBuilder)和SetCustomAttribute(ConstructorInfo con, byte[] binaryAttribute)。这两个都是需要ConstructorInfo来构造类标记。而我们通过类型Employee得到的类标记是通过反射得到的object[] atts = type.GetCustomAttributes(false);这是object数组,不能直接给ConstructorInfo使用。

 

所以就有了下面的代码,来动态产生标记。

#region 标记
object[] atts = type.GetCustomAttributes(false);
if (atts != null && atts.Length > 0) {
foreach (Attribute item in atts) {
if (item == null) continue;
try {
CustomAttributeBuilder c = null;
ConstructorInfo[] conInfos = item.GetType().GetConstructors();
ConstructorInfo cons = conInfos[conInfos.Length - 1];
ParameterInfo[] args = cons.GetParameters();
List<Type> argsList = new List<Type>();
List<object> argsValue = new List<object>();
if (args.Length > 0) {
foreach (var arg in args) {
argsList.Add(arg.ParameterType);
PropertyInfo pi = item.GetType().GetProperty(arg.Name.Substring(0, 1).ToUpper() + arg.Name.Substring(1));//微软规则首字母小写
if (pi != null) {
argsValue.Add(pi.GetValue(item, null));
} else {
pi = item.GetType().GetProperty(arg.Name.Remove(0, 1));//我们的规则p+Name
if (pi != null) {
argsValue.Add(pi.GetValue(item, null));
} else {
argsValue.Add(null);
}
}
}
}
PropertyInfo[] pis = item.GetType().GetProperties();
if (pis.Length > 0) {
List<PropertyInfo> piList = new List<PropertyInfo>();
List<object> valueList = new List<object>();
object[] pValues = new object[pis.Length];
for (int i = 0; i < pis.Length; i++) {
if (pis[i].CanWrite) {
pValues[i] = pis[i].GetValue(item, null);
if (pValues[i] != null) {
piList.Add(pis[i]);
valueList.Add(pValues[i]);
}
}
}
if (piList.Count > 0) {
c = new CustomAttributeBuilder(cons, argsValue.ToArray(), piList.ToArray(), valueList.ToArray());
} else {
c = new CustomAttributeBuilder(cons, argsValue.ToArray());
}
} else {
c = new CustomAttributeBuilder(cons, argsValue.ToArray());
}
myTypeBuilder.SetCustomAttribute(c);
} catch (Exception ex) {
throw new Exception(string.Format("{0}的标记[{1}]重写异常:{2}", typeName, item.ToString(),ex.ToString()));
}
}
}