c# 写的一个类帮助器(动态生成类 动态类 动态属性)

转载 2011年01月20日 11:07:00

写的一个类帮助器,思路是,可以使用这个帮助器对类动态地控制(在运行时),如添加,删除其成员。

最近要用到这个,在网上找了点资料,也不全面,就自己查msdn帮助文件。自己写了一个,功能还不是很完善,如果大家有兴趣扩展下功能的话,就再好不过了。现在只能控制属性,还不能控制其它成员,如事件,方法等等。

演示一:动态生成类。
演示二:动态添加属性到类。
演示三:动态从类里删除属性。
演示四:动态获取和设置属性值。

类帮助器代码:


// --------------------------------------------------------
// 作者:李剑 msn:newshadowk@hotmail.com qq:50248291
// --------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection.Emit;
using System.Reflection;
using System.Threading;

/// <summary>
/// 类帮助器,可以动态对类,类成员进行控制(添加,删除),目前只支持属性控制。
/// 注意,属性以外的其它成员会被清空,功能还有待完善,使其不影响其它成员。
/// </summary>

public class ClassHelper
{
    
#region 公有方法
    
/// <summary>
    
/// 根据类的类型型创建类实例。
    
/// </summary>
    
/// <param name="t">将要创建的类型。</param>
    
/// <returns>返回创建的类实例。</returns>

    public static object CreateInstance(Type t)
    
{
        
return Activator.CreateInstance(t);
    }


    
/// <summary>
    
/// 根据类的名称,属性列表创建型实例。
    
/// </summary>
    
/// <param name="className">将要创建的类的名称。</param>
    
/// <param name="lcpi">将要创建的类的属性列表。</param>
    
/// <returns>返回创建的类实例</returns>

    public static object CreateInstance(string className, List<CustPropertyInfo> lcpi)
    
{
        Type t 
= BuildType(className);
        t 
= AddProperty(t, lcpi);
        
return Activator.CreateInstance(t);
    }


    
/// <summary>
    
/// 根据属性列表创建类的实例,默认类名为DefaultClass,由于生成的类不是强类型,所以类名可以忽略。
    
/// </summary>
    
/// <param name="lcpi">将要创建的类的属性列表</param>
    
/// <returns>返回创建的类的实例。</returns>

    public static object CreateInstance(List<CustPropertyInfo> lcpi)
    
{
        
return CreateInstance("DefaultClass", lcpi);
    }


    
/// <summary>
    
/// 根据类的实例设置类的属性。
    
/// </summary>
    
/// <param name="classInstance">将要设置的类的实例。</param>
    
/// <param name="propertyName">将要设置属性名。</param>
    
/// <param name="propertSetValue">将要设置属性值。</param>

    public static void SetPropertyValue(object classInstance, string propertyName, object propertSetValue)
    
{
        classInstance.GetType().InvokeMember(propertyName, BindingFlags.SetProperty,
                                      
null, classInstance, new object[] { Convert.ChangeType(propertSetValue, propertSetValue.GetType()) });
    }


    
/// <summary>
    
/// 根据类的实例获取类的属性。
    
/// </summary>
    
/// <param name="classInstance">将要获取的类的实例</param>
    
/// <param name="propertyName">将要设置的属性名。</param>
    
/// <returns>返回获取的类的属性。</returns>

    public static object GetPropertyValue(object classInstance, string propertyName)
    
{
        
return classInstance.GetType().InvokeMember(propertyName, BindingFlags.GetProperty,
                                                      
null, classInstance, new object[] { });
    }


    
/// <summary>
    
/// 创建一个没有成员的类型的实例,类名为"DefaultClass"。
    
/// </summary>
    
/// <returns>返回创建的类型的实例。</returns>

    public static Type BuildType()
    
{
        
return BuildType("DefaultClass");
    }


    
/// <summary>
    
/// 根据类名创建一个没有成员的类型的实例。
    
/// </summary>
    
/// <param name="className">将要创建的类型的实例的类名。</param>
    
/// <returns>返回创建的类型的实例。</returns>

    public static Type BuildType(string className)
    
{

        AppDomain myDomain 
= Thread.GetDomain();
        AssemblyName myAsmName 
= new AssemblyName();
        myAsmName.Name 
= "MyDynamicAssembly";

        
//创建一个永久程序集,设置为AssemblyBuilderAccess.RunAndSave。
        AssemblyBuilder myAsmBuilder = myDomain.DefineDynamicAssembly(myAsmName,
                                                        AssemblyBuilderAccess.RunAndSave);

        
//创建一个永久单模程序块。
        ModuleBuilder myModBuilder =
            myAsmBuilder.DefineDynamicModule(myAsmName.Name, myAsmName.Name 
+ ".dll");
        
//创建TypeBuilder。
        TypeBuilder myTypeBuilder = myModBuilder.DefineType(className,
                                                        TypeAttributes.Public);

        
//创建类型。
        Type retval = myTypeBuilder.CreateType();

        
//保存程序集,以便可以被Ildasm.exe解析,或被测试程序引用。
        myAsmBuilder.Save(myAsmName.Name + ".dll");
        
return retval;
    }


    
/// <summary>
    
/// 添加属性到类型的实例,注意:该操作会将其它成员清除掉,其功能有待完善。
    
/// </summary>
    
/// <param name="classType">指定类型的实例。</param>
    
/// <param name="lcpi">表示属性的一个列表。</param>
    
/// <returns>返回处理过的类型的实例。</returns>

    public static Type AddProperty(Type classType, List<CustPropertyInfo> lcpi)
    
{
        
//合并先前的属性,以便一起在下一步进行处理。
        MergeProperty(classType, lcpi);
        
//把属性加入到Type。
        return AddPropertyToType(classType, lcpi);
    }


    
/// <summary>
    
/// 添加属性到类型的实例,注意:该操作会将其它成员清除掉,其功能有待完善。
    
/// </summary>
    
/// <param name="classType">指定类型的实例。</param>
    
/// <param name="cpi">表示一个属性。</param>
    
/// <returns>返回处理过的类型的实例。</returns>

    public static Type AddProperty(Type classType, CustPropertyInfo cpi)
    
{
        List
<CustPropertyInfo> lcpi = new List<CustPropertyInfo>();
        lcpi.Add(cpi);
        
//合并先前的属性,以便一起在下一步进行处理。
        MergeProperty(classType, lcpi);
        
//把属性加入到Type。
        return AddPropertyToType(classType, lcpi);
    }


    
/// <summary>
    
/// 从类型的实例中移除属性,注意:该操作会将其它成员清除掉,其功能有待完善。
    
/// </summary>
    
/// <param name="classType">指定类型的实例。</param>
    
/// <param name="cpi">要移除的属性。</param>
    
/// <returns>返回处理过的类型的实例。</returns>

    public static Type DeleteProperty(Type classType, string propertyName)
    
{
        List
<string> ls = new List<string>();
        ls.Add(propertyName);

        
//合并先前的属性,以便一起在下一步进行处理。
        List<CustPropertyInfo> lcpi = SeparateProperty(classType, ls);
        
//把属性加入到Type。
        return AddPropertyToType(classType, lcpi);
    }


    
/// <summary>
    
/// 从类型的实例中移除属性,注意:该操作会将其它成员清除掉,其功能有待完善。
    
/// </summary>
    
/// <param name="classType">指定类型的实例。</param>
    
/// <param name="lcpi">要移除的属性列表。</param>
    
/// <returns>返回处理过的类型的实例。</returns>

    public static Type DeleteProperty(Type classType, List<string> ls)
    
{
        
//合并先前的属性,以便一起在下一步进行处理。
        List<CustPropertyInfo> lcpi = SeparateProperty(classType, ls);
        
//把属性加入到Type。
        return AddPropertyToType(classType, lcpi);
    }

    
#endregion


    
#region 私有方法
    
/// <summary>
    
/// 把类型的实例t和lcpi参数里的属性进行合并。
    
/// </summary>
    
/// <param name="t">实例t</param>
    
/// <param name="lcpi">里面包含属性列表的信息。</param>

    private static void MergeProperty(Type t, List<CustPropertyInfo> lcpi)
    
{
        CustPropertyInfo cpi;
        
foreach (PropertyInfo pi in t.GetProperties())
        
{
            cpi 
= new CustPropertyInfo(pi.PropertyType.FullName, pi.Name);
            lcpi.Add(cpi);
        }

    }


    
/// <summary>
    
/// 从类型的实例t的属性移除属性列表lcpi,返回的新属性列表在lcpi中。
    
/// </summary>
    
/// <param name="t">类型的实例t。</param>
    
/// <param name="lcpi">要移除的属性列表。</param>

    private static List<CustPropertyInfo> SeparateProperty(Type t, List<string> ls)
    
{
        List
<CustPropertyInfo> ret = new List<CustPropertyInfo>();
        CustPropertyInfo cpi;
        
foreach (PropertyInfo pi in t.GetProperties())
        
{
            
foreach (string s in ls)
            
{
                
if (pi.Name != s)
                
{
                    cpi 
= new CustPropertyInfo(pi.PropertyType.FullName, pi.Name);
                    ret.Add(cpi);
                }

            }

        }


        
return ret;
    }


    
/// <summary>
    
/// 把lcpi参数里的属性加入到myTypeBuilder中。注意:该操作会将其它成员清除掉,其功能有待完善。
    
/// </summary>
    
/// <param name="myTypeBuilder">类型构造器的实例。</param>
    
/// <param name="lcpi">里面包含属性列表的信息。</param>

    private static void AddPropertyToTypeBuilder(TypeBuilder myTypeBuilder, List<CustPropertyInfo> lcpi)
    
{
        FieldBuilder customerNameBldr;
        PropertyBuilder custNamePropBldr;
        MethodBuilder custNameGetPropMthdBldr;
        MethodBuilder custNameSetPropMthdBldr;
        MethodAttributes getSetAttr;
        ILGenerator custNameGetIL;
        ILGenerator custNameSetIL;

        
// 属性Set和Get方法要一个专门的属性。这里设置为Public。
        getSetAttr =
            MethodAttributes.Public 
| MethodAttributes.SpecialName |
                MethodAttributes.HideBySig;

        
// 添加属性到myTypeBuilder。
        foreach (CustPropertyInfo cpi in lcpi)
        
{
            
//定义字段。
            customerNameBldr = myTypeBuilder.DefineField(cpi.FieldName,
                                                             Type.GetType(cpi.Type),
                                                             FieldAttributes.Private);

            
//定义属性。
            
//最后一个参数为null,因为属性没有参数。
            custNamePropBldr = myTypeBuilder.DefineProperty(cpi.PropertyName,
                                                             PropertyAttributes.HasDefault,
                                                             Type.GetType(cpi.Type),
                                                             
null);


            
//定义Get方法。
            custNameGetPropMthdBldr =
                myTypeBuilder.DefineMethod(cpi.GetPropertyMethodName,
                                           getSetAttr,
                                           Type.GetType(cpi.Type),
                                           Type.EmptyTypes);

            custNameGetIL 
= custNameGetPropMthdBldr.GetILGenerator();

            custNameGetIL.Emit(OpCodes.Ldarg_0);
            custNameGetIL.Emit(OpCodes.Ldfld, customerNameBldr);
            custNameGetIL.Emit(OpCodes.Ret);

            
//定义Set方法。
            custNameSetPropMthdBldr =
                myTypeBuilder.DefineMethod(cpi.SetPropertyMethodName,
                                           getSetAttr,
                                           
null,
                                           
new Type[] { Type.GetType(cpi.Type) });

            custNameSetIL 
= custNameSetPropMthdBldr.GetILGenerator();

            custNameSetIL.Emit(OpCodes.Ldarg_0);
            custNameSetIL.Emit(OpCodes.Ldarg_1);
            custNameSetIL.Emit(OpCodes.Stfld, customerNameBldr);
            custNameSetIL.Emit(OpCodes.Ret);

            
//把创建的两个方法(Get,Set)加入到PropertyBuilder中。
            custNamePropBldr.SetGetMethod(custNameGetPropMthdBldr);
            custNamePropBldr.SetSetMethod(custNameSetPropMthdBldr);
        }

    }


    
/// <summary>
    
/// 把属性加入到类型的实例。
    
/// </summary>
    
/// <param name="classType">类型的实例。</param>
    
/// <param name="lcpi">要加入的属性列表。</param>
    
/// <returns>返回处理过的类型的实例。</returns>

    public static Type AddPropertyToType(Type classType, List<CustPropertyInfo> lcpi)
    
{
        AppDomain myDomain 
= Thread.GetDomain();
        AssemblyName myAsmName 
= new AssemblyName();
        myAsmName.Name 
= "MyDynamicAssembly";

        
//创建一个永久程序集,设置为AssemblyBuilderAccess.RunAndSave。
        AssemblyBuilder myAsmBuilder = myDomain.DefineDynamicAssembly(myAsmName,
                                                        AssemblyBuilderAccess.RunAndSave);

        
//创建一个永久单模程序块。
        ModuleBuilder myModBuilder =
            myAsmBuilder.DefineDynamicModule(myAsmName.Name, myAsmName.Name 
+ ".dll");
        
//创建TypeBuilder。
        TypeBuilder myTypeBuilder = myModBuilder.DefineType(classType.FullName,
                                                        TypeAttributes.Public);

        
//把lcpi中定义的属性加入到TypeBuilder。将清空其它的成员。其功能有待扩展,使其不影响其它成员。
        AddPropertyToTypeBuilder(myTypeBuilder, lcpi);

        
//创建类型。
        Type retval = myTypeBuilder.CreateType();

        
//保存程序集,以便可以被Ildasm.exe解析,或被测试程序引用。
        myAsmBuilder.Save(myAsmName.Name + ".dll");
        
return retval;
    }

    
#endregion


    
#region 辅助类
    
/// <summary>
    
/// 自定义的属性信息类型。
    
/// </summary>

    public class CustPropertyInfo
    
{
        
private string propertyName;
        
private string type;

        
/// <summary>
        
/// 空构造。
        
/// </summary>

        public CustPropertyInfo() { }

        
/// <summary>
        
/// 根据属性类型名称,属性名称构造实例。
        
/// </summary>
        
/// <param name="type">属性类型名称。</param>
        
/// <param name="propertyName">属性名称。</param>

        public CustPropertyInfo(string type, string propertyName)
        
{
            
this.type = type;
            
this.propertyName = propertyName;
        }


        
/// <summary>
        
/// 获取或设置属性类型名称。
        
/// </summary>

        public string Type
        
{
            
get return type; }
            
set { type = value; }
        }


        
/// <summary>
        
/// 获取或设置属性名称。
        
/// </summary>

        public string PropertyName
        
{
            
get return propertyName; }
            
set { propertyName = value; }
        }


        
/// <summary>
        
/// 获取属性字段名称。
        
/// </summary>

        public string FieldName
        
{
            
get return propertyName.Substring(01).ToLower() + propertyName.Substring(1); }
        }


        
/// <summary>
        
/// 获取属性在IL中的Set方法名。
        
/// </summary>

        public string SetPropertyMethodName
        
{
            
get return "set_" + PropertyName; }
        }


        
/// <summary>
        
///  获取属性在IL中的Get方法名。
        
/// </summary>

        public string GetPropertyMethodName
        
{
            
get return "get_" + PropertyName; }
        }

    }

    
#endregion

}


 显示程序代码:


// --------------------------------------------------------
// 作者:李剑 msn:newshadowk@hotmail.com qq:50248291
// --------------------------------------------------------
using System;
using System.Threading;
using System.Reflection;
using System.Collections.Generic;

class ClassHelperDemo
{
    
public static void Main()
    
{
        
#region 演示一:动态生成类。
        
//生成一个类t。
        Type t = ClassHelper.BuildType("MyClass");
        
#endregion


        
#region 演示二:动态添加属性到类。
        
//先定义两个属性。
        List<ClassHelper.CustPropertyInfo> lcpi = new List<ClassHelper.CustPropertyInfo>();
        ClassHelper.CustPropertyInfo cpi;

        cpi 
= new ClassHelper.CustPropertyInfo("System.String""S1");
        lcpi.Add(cpi);
        cpi 
= new ClassHelper.CustPropertyInfo("System.String""S2");
        lcpi.Add(cpi);



        
//再加入上面定义的两个属性到我们生成的类t。
        t = ClassHelper.AddProperty(t, lcpi);

        
//把它显示出来。
        DispProperty(t);

        
//再定义两个属性。
        lcpi.Clear();
        cpi 
= new ClassHelper.CustPropertyInfo("System.Int32""I1");
        lcpi.Add(cpi);
        cpi 
= new ClassHelper.CustPropertyInfo("System.Int32""I2");
        lcpi.Add(cpi);

        
//再加入上面定义的两个属性到我们生成的类t。
        t = ClassHelper.AddProperty(t, lcpi);

        
//再把它显示出来,看看有没有增加到4个属性。
        DispProperty(t);
        
#endregion


        
#region 演示三:动态从类里删除属性。
        
//把'S1'属性从类t中删除。
        t = ClassHelper.DeleteProperty(t, "S1");
        
//显示出来,可以看到'S1'不见了。
        DispProperty(t);

        
#endregion

        
        
#region 演示四:动态获取和设置属性值。
        
//先生成一个类t的实例o。
        object o = ClassHelper.CreateInstance(t);

        
//给S2,I2属性赋值。
        ClassHelper.SetPropertyValue(o, "S2""abcd");
        ClassHelper.SetPropertyValue(o, 
"I2"1234);

        
//再把S2,I2的属性值显示出来。
        Console.WriteLine("S2 = {0}", ClassHelper.GetPropertyValue(o, "S2"));
        Console.WriteLine(
"I2 = {0}", ClassHelper.GetPropertyValue(o, "I2"));
        
#endregion


        Console.Read();
    }


    
public static void DispProperty(Type t)
    
{
        Console.WriteLine(
"ClassName '{0}'", t.Name);
        
foreach (PropertyInfo pInfo in t.GetProperties())
        
{
            Console.WriteLine(
"Has Property '{0}'", pInfo.ToString());
        }

        Console.WriteLine(
"");
    }

}


输出:

ClassName 'MyClass'
Has Property 'System.String S1'
Has Property 'System.String S2'

ClassName 'MyClass'
Has Property 'Int32 I1'
Has Property 'Int32 I2'
Has Property 'System.String S1'
Has Property 'System.String S2'

ClassName 'MyClass'
Has Property 'Int32 I1'
Has Property 'Int32 I2'
Has Property 'System.String S2'

S2 = abcd
I2 = 1234

相关文章推荐

.net dynamic动态加属性

class Test : System.Dynamic.DynamicObject { public override bool TryGetMember(Sy...
  • cqims21
  • cqims21
  • 2013年12月27日 16:10
  • 3647

c# 对象运行时动态添加属性、方法

using System.Dynamic; namespace Test {      public class Test     {         public static void ...

c# 配置类属性动态显示值(Linq)

  • 2015年05月26日 11:40
  • 36KB
  • 下载

C#类动态添加属性

动态类实现 using System; using System.Collections.Generic; using System.Reflection.Emit; using Sys...

在ATL中使用动态访问器的一个类

  • 2010年07月21日 11:08
  • 994B
  • 下载

C# 类动态添加属性、方法

问题:   需要动态为WPF中的DataGrid添加列,并动态绑定相应数据.(此处仅实现动态属性的添加和使用,关于动态方法的添加和使用详见推荐阅读) 实现关键点:   目标类继承DynamicO...

python实现在类中动态添加属性和生成对象

程序的主要功能现在有个存储用户信息的像表格一样的文档:第一行是属性,各个属性用逗号(,)分隔,从第二行开始每行是各个属性对应的值,每行代表一个用户。如何实现读入这个文档,每行输出一个用户对象呢? 另...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:c# 写的一个类帮助器(动态生成类 动态类 动态属性)
举报原因:
原因补充:

(最多只允许输入30个字)