C# 动态添加属性 非原创 有修改
View Code
1 using System; 2 using System.Collections.Generic; 3 using System.Reflection.Emit; 4 using System.Reflection; 5 using System.Threading; 6 7 namespace System 8 { 9 public class ClassHelper 10 { 11 #region 公有方法 12 /**/ 13 /// <summary> 14 /// 防止实例化。 15 /// </summary> 16 private ClassHelper() { } 17 18 /**/ 19 /// <summary> 20 /// 根据类的类型型创建类实例。 21 /// </summary> 22 /// <param name="t">将要创建的类型。</param> 23 /// <returns>返回创建的类实例。</returns> 24 public static object CreateInstance(Type t) 25 { 26 return Activator.CreateInstance(t); 27 } 28 29 /**/ 30 /// <summary> 31 /// 根据类的名称,属性列表创建型实例。 32 /// </summary> 33 /// <param name="className">将要创建的类的名称。</param> 34 /// <param name="lcpi">将要创建的类的属性列表。</param> 35 /// <returns>返回创建的类实例</returns> 36 public static object CreateInstance(string className, List<CustPropertyInfo> lcpi) 37 { 38 Type t = BuildType(className); 39 t = AddProperty(t, lcpi); 40 return Activator.CreateInstance(t); 41 } 42 43 /**/ 44 /// <summary> 45 /// 根据属性列表创建类的实例,默认类名为DefaultClass,由于生成的类不是强类型,所以类名可以忽略。 46 /// </summary> 47 /// <param name="lcpi">将要创建的类的属性列表</param> 48 /// <returns>返回创建的类的实例。</returns> 49 public static object CreateInstance(List<CustPropertyInfo> lcpi) 50 { 51 return CreateInstance("DefaultClass", lcpi); 52 } 53 54 /**/ 55 /// <summary> 56 /// 根据类的实例设置类的属性。 57 /// </summary> 58 /// <param name="classInstance">将要设置的类的实例。</param> 59 /// <param name="propertyName">将要设置属性名。</param> 60 /// <param name="propertSetValue">将要设置属性值。</param> 61 public static void SetPropertyValue(object classInstance, string propertyName, object propertSetValue) 62 { 63 classInstance.GetType().InvokeMember(propertyName, BindingFlags.SetProperty, 64 null, classInstance, new object[] { Convert.ChangeType(propertSetValue, propertSetValue.GetType()) }); 65 } 66 67 /**/ 68 /// <summary> 69 /// 根据类的实例获取类的属性。 70 /// </summary> 71 /// <param name="classInstance">将要获取的类的实例</param> 72 /// <param name="propertyName">将要设置的属性名。</param> 73 /// <returns>返回获取的类的属性。</returns> 74 public static object GetPropertyValue(object classInstance, string propertyName) 75 { 76 return classInstance.GetType().InvokeMember(propertyName, BindingFlags.GetProperty, 77 null, classInstance, new object[] { }); 78 } 79 80 /**/ 81 /// <summary> 82 /// 创建一个没有成员的类型的实例,类名为"DefaultClass"。 83 /// </summary> 84 /// <returns>返回创建的类型的实例。</returns> 85 public static Type BuildType() 86 { 87 return BuildType("DefaultClass"); 88 } 89 90 /**/ 91 /// <summary> 92 /// 根据类名创建一个没有成员的类型的实例。 93 /// </summary> 94 /// <param name="className">将要创建的类型的实例的类名。</param> 95 /// <returns>返回创建的类型的实例。</returns> 96 public static Type BuildType(string className) 97 { 98 99 AppDomain myDomain = Thread.GetDomain(); 100 AssemblyName myAsmName = new AssemblyName(); 101 myAsmName.Name = "MyDynamicAssembly"; 102 103 //创建一个永久程序集,设置为AssemblyBuilderAccess.RunAndSave。 104 AssemblyBuilder myAsmBuilder = myDomain.DefineDynamicAssembly(myAsmName, 105 AssemblyBuilderAccess.RunAndSave); 106 107 //创建一个永久单模程序块。 108 ModuleBuilder myModBuilder = 109 myAsmBuilder.DefineDynamicModule(myAsmName.Name, myAsmName.Name + ".dll"); 110 //创建TypeBuilder。 111 TypeBuilder myTypeBuilder = myModBuilder.DefineType(className, 112 TypeAttributes.Public); 113 114 //创建类型。 115 Type retval = myTypeBuilder.CreateType(); 116 117 //保存程序集,以便可以被Ildasm.exe解析,或被测试程序引用。 118 //myAsmBuilder.Save(myAsmName.Name + ".dll"); 119 return retval; 120 } 121 122 /**/ 123 /// <summary> 124 /// 添加属性到类型的实例,注意:该操作会将其它成员清除掉,其功能有待完善。 125 /// </summary> 126 /// <param name="classType">指定类型的实例。</param> 127 /// <param name="lcpi">表示属性的一个列表。</param> 128 /// <returns>返回处理过的类型的实例。</returns> 129 public static Type AddProperty(Type classType, List<CustPropertyInfo> lcpi) 130 { 131 //合并先前的属性,以便一起在下一步进行处理。 132 MergeProperty(classType, lcpi); 133 //把属性加入到Type。 134 return AddPropertyToType(classType, lcpi); 135 } 136 137 /**/ 138 /// <summary> 139 /// 添加属性到类型的实例,注意:该操作会将其它成员清除掉,其功能有待完善。 140 /// </summary> 141 /// <param name="classType">指定类型的实例。</param> 142 /// <param name="cpi">表示一个属性。</param> 143 /// <returns>返回处理过的类型的实例。</returns> 144 public static Type AddProperty(Type classType, CustPropertyInfo cpi) 145 { 146 List<CustPropertyInfo> lcpi = new List<CustPropertyInfo>(); 147 lcpi.Add(cpi); 148 //合并先前的属性,以便一起在下一步进行处理。 149 MergeProperty(classType, lcpi); 150 //把属性加入到Type。 151 return AddPropertyToType(classType, lcpi); 152 } 153 154 /**/ 155 /// <summary> 156 /// 从类型的实例中移除属性,注意:该操作会将其它成员清除掉,其功能有待完善。 157 /// </summary> 158 /// <param name="classType">指定类型的实例。</param> 159 /// <param name="propertyName">要移除的属性。</param> 160 /// <returns>返回处理过的类型的实例。</returns> 161 public static Type DeleteProperty(Type classType, string propertyName) 162 { 163 List<string> ls = new List<string>(); 164 ls.Add(propertyName); 165 166 //合并先前的属性,以便一起在下一步进行处理。 167 List<CustPropertyInfo> lcpi = SeparateProperty(classType, ls); 168 //把属性加入到Type。 169 return AddPropertyToType(classType, lcpi); 170 } 171 172 /**/ 173 /// <summary> 174 /// 从类型的实例中移除属性,注意:该操作会将其它成员清除掉,其功能有待完善。 175 /// </summary> 176 /// <param name="classType">指定类型的实例。</param> 177 /// <param name="ls">要移除的属性列表。</param> 178 /// <returns>返回处理过的类型的实例。</returns> 179 public static Type DeleteProperty(Type classType, List<string> ls) 180 { 181 //合并先前的属性,以便一起在下一步进行处理。 182 List<CustPropertyInfo> lcpi = SeparateProperty(classType, ls); 183 //把属性加入到Type。 184 return AddPropertyToType(classType, lcpi); 185 } 186 #endregion 187 188 #region 私有方法 189 /**/ 190 /// <summary> 191 /// 把类型的实例t和lcpi参数里的属性进行合并。 192 /// </summary> 193 /// <param name="t">实例t</param> 194 /// <param name="lcpi">里面包含属性列表的信息。</param> 195 private static void MergeProperty(Type t, List<CustPropertyInfo> lcpi) 196 { 197 foreach (PropertyInfo pi in t.GetProperties()) 198 { 199 CustPropertyInfo cpi = new CustPropertyInfo(pi.PropertyType.FullName, pi.Name); 200 lcpi.Add(cpi); 201 } 202 } 203 204 private static object DefaultForType(Type targetType) 205 { 206 return targetType.IsValueType ? Activator.CreateInstance(targetType) : null; 207 } 208 209 /**/ 210 /// <summary> 211 /// 从类型的实例t的属性移除属性列表lcpi,返回的新属性列表在lcpi中。 212 /// </summary> 213 /// <param name="t">类型的实例t。</param> 214 /// <param name="ls">要移除的属性列表。</param> 215 private static List<CustPropertyInfo> SeparateProperty(Type t, List<string> ls) 216 { 217 List<CustPropertyInfo> ret = new List<CustPropertyInfo>(); 218 foreach (PropertyInfo pi in t.GetProperties()) 219 { 220 foreach (string s in ls) 221 { 222 if (pi.Name != s) 223 { 224 CustPropertyInfo cpi = new CustPropertyInfo(pi.PropertyType.FullName, pi.Name); 225 ret.Add(cpi); 226 } 227 } 228 } 229 230 return ret; 231 } 232 233 /**/ 234 /// <summary> 235 /// 把lcpi参数里的属性加入到myTypeBuilder中。注意:该操作会将其它成员清除掉,其功能有待完善。 236 /// </summary> 237 /// <param name="myTypeBuilder">类型构造器的实例。</param> 238 /// <param name="lcpi">里面包含属性列表的信息。</param> 239 private static void AddPropertyToTypeBuilder(TypeBuilder myTypeBuilder, List<CustPropertyInfo> lcpi) 240 { 241 PropertyBuilder custNamePropBldr; 242 MethodBuilder custNameGetPropMthdBldr; 243 MethodBuilder custNameSetPropMthdBldr; 244 MethodAttributes getSetAttr; 245 ILGenerator custNameGetIL; 246 ILGenerator custNameSetIL; 247 248 // 属性Set和Get方法要一个专门的属性。这里设置为Public。 249 getSetAttr = 250 MethodAttributes.Public | MethodAttributes.SpecialName | 251 MethodAttributes.HideBySig; 252 253 // 添加属性到myTypeBuilder。 254 foreach (CustPropertyInfo cpi in lcpi) 255 { 256 //定义字段。 257 FieldBuilder customerNameBldr = myTypeBuilder.DefineField(cpi.FieldName, 258 Type.GetType(cpi.Type), 259 FieldAttributes.Private); 260 customerNameBldr.SetConstant(DefaultForType(Type.GetType(cpi.Type))); 261 //定义属性。 262 //最后一个参数为null,因为属性没有参数。 263 custNamePropBldr = myTypeBuilder.DefineProperty(cpi.PropertyName, 264 PropertyAttributes.HasDefault, 265 Type.GetType(cpi.Type), 266 null); 267 268 custNamePropBldr.SetConstant(DefaultForType(Type.GetType(cpi.Type))); 269 //定义Get方法。 270 custNameGetPropMthdBldr = 271 myTypeBuilder.DefineMethod(cpi.GetPropertyMethodName, 272 getSetAttr, 273 Type.GetType(cpi.Type), 274 Type.EmptyTypes); 275 276 custNameGetIL = custNameGetPropMthdBldr.GetILGenerator(); 277 278 try 279 { 280 custNameGetIL.Emit(OpCodes.Ldarg_0); 281 //custNameGetIL.Emit(OpCodes.Ldfld, customerNameBldr); 282 custNameGetIL.Emit(OpCodes.Ldfld, customerNameBldr); 283 custNameGetIL.Emit(OpCodes.Ret); 284 } 285 catch (Exception ex) 286 { 287 288 289 } 290 291 //定义Set方法。 292 custNameSetPropMthdBldr = 293 myTypeBuilder.DefineMethod(cpi.SetPropertyMethodName, 294 getSetAttr, 295 null, 296 new Type[] { Type.GetType(cpi.Type) }); 297 298 custNameSetIL = custNameSetPropMthdBldr.GetILGenerator(); 299 300 custNameSetIL.Emit(OpCodes.Ldarg_0); 301 custNameSetIL.Emit(OpCodes.Ldarg_1); 302 custNameSetIL.Emit(OpCodes.Stfld, customerNameBldr); 303 custNameSetIL.Emit(OpCodes.Ret); 304 //custNamePropBldr.SetConstant("ceshi"); 305 //把创建的两个方法(Get,Set)加入到PropertyBuilder中。 306 custNamePropBldr.SetGetMethod(custNameGetPropMthdBldr); 307 custNamePropBldr.SetSetMethod(custNameSetPropMthdBldr); 308 } 309 } 310 311 /**/ 312 /// <summary> 313 /// 把属性加入到类型的实例。 314 /// </summary> 315 /// <param name="classType">类型的实例。</param> 316 /// <param name="lcpi">要加入的属性列表。</param> 317 /// <returns>返回处理过的类型的实例。</returns> 318 public static Type AddPropertyToType(Type classType, List<CustPropertyInfo> lcpi) 319 { 320 AppDomain myDomain = Thread.GetDomain(); 321 AssemblyName myAsmName = new AssemblyName(); 322 myAsmName.Name = "MyDynamicAssembly"; 323 324 //创建一个永久程序集,设置为AssemblyBuilderAccess.RunAndSave。 325 AssemblyBuilder myAsmBuilder = myDomain.DefineDynamicAssembly(myAsmName, 326 AssemblyBuilderAccess.RunAndSave); 327 328 //创建一个永久单模程序块。 329 ModuleBuilder myModBuilder = 330 myAsmBuilder.DefineDynamicModule(myAsmName.Name, myAsmName.Name + ".dll"); 331 //创建TypeBuilder。 332 TypeBuilder myTypeBuilder = myModBuilder.DefineType(classType.FullName, 333 TypeAttributes.Public); 334 335 //把lcpi中定义的属性加入到TypeBuilder。将清空其它的成员。其功能有待扩展,使其不影响其它成员。 336 AddPropertyToTypeBuilder(myTypeBuilder, lcpi); 337 338 //创建类型。 339 Type retval = myTypeBuilder.CreateType(); 340 341 //保存程序集,以便可以被Ildasm.exe解析,或被测试程序引用。 342 //myAsmBuilder.Save(myAsmName.Name + ".dll"); 343 return retval; 344 } 345 #endregion 346 347 #region 辅助类 348 /**/ 349 /// <summary> 350 /// 自定义的属性信息类型。 351 /// </summary> 352 public class CustPropertyInfo 353 { 354 private string propertyName; 355 private string type; 356 357 /**/ 358 /// <summary> 359 /// 空构造。 360 /// </summary> 361 public CustPropertyInfo() { } 362 363 /**/ 364 /// <summary> 365 /// 根据属性类型名称,属性名称构造实例。 366 /// </summary> 367 /// <param name="type">属性类型名称。</param> 368 /// <param name="propertyName">属性名称。</param> 369 public CustPropertyInfo(string type, string propertyName) 370 { 371 this.type = type; 372 this.propertyName = propertyName; 373 } 374 375 /**/ 376 /// <summary> 377 /// 获取或设置属性类型名称。 378 /// </summary> 379 public string Type 380 { 381 get { return type; } 382 set { type = value; } 383 } 384 385 /**/ 386 /// <summary> 387 /// 获取或设置属性名称。 388 /// </summary> 389 public string PropertyName 390 { 391 get { return propertyName; } 392 set { propertyName = value; } 393 } 394 395 /**/ 396 /// <summary> 397 /// 获取属性字段名称。 398 /// </summary> 399 public string FieldName 400 { 401 get 402 { 403 if (propertyName.Length < 1) 404 return ""; 405 return propertyName.Substring(0, 1).ToLower() + propertyName.Substring(1); 406 } 407 } 408 409 /**/ 410 /// <summary> 411 /// 获取属性在IL中的Set方法名。 412 /// </summary> 413 public string SetPropertyMethodName 414 { 415 get { return "set_" + PropertyName; } 416 } 417 418 /**/ 419 /// <summary> 420 /// 获取属性在IL中的Get方法名。 421 /// </summary> 422 public string GetPropertyMethodName 423 { 424 get { return "get_" + PropertyName; } 425 } 426 } 427 #endregion 428 } 429 }
非原创,亲测可用,但是添加到类型目前测试的结果看来,不能添加String和Guid,目前只有添加Int32成功了
其他人的更详细的