利用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())); } } }