using System;
using System.Collections.Generic;
using System.Reflection;
using System.Reflection.Emit;
using System.Threading; namespace DynamicTest
{
/// <summary>
/// 类帮助器,可以动态对类,类成员进行控制(添加,删除),目前只支持属性控制。
/// 注意,属性以外的其它成员会被清空,功能还有待完善,使其不影响其它成员。
/// </summary>
public class ClassHelper
{
#region 公有方法
/// <summary>
/// 防止实例化。
/// </summary>
private ClassHelper() { } /// <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="propertyName">要移除的属性。</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="ls">要移除的属性列表。</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)
{
foreach (PropertyInfo pi in t.GetProperties())
{
CustPropertyInfo cpi = new CustPropertyInfo(pi.PropertyType.FullName, pi.Name);
lcpi.Add(cpi);
}
} /// <summary>
/// 从类型的实例t的属性移除属性列表lcpi,返回的新属性列表在lcpi中。
/// </summary>
/// <param name="t">类型的实例t。</param>
/// <param name="ls">要移除的属性列表。</param>
private static List<CustPropertyInfo> SeparateProperty(Type t, List<string> ls)
{
List<CustPropertyInfo> ret = new List<CustPropertyInfo>();
foreach (PropertyInfo pi in t.GetProperties())
{
foreach (string s in ls)
{
if (pi.Name != s)
{
CustPropertyInfo 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)
{
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)
{
//定义字段。
FieldBuilder customerNameBldr = myTypeBuilder.DefineField(cpi.FieldName, Type.GetType(cpi.Type), FieldAttributes.Private);
customerNameBldr.SetConstant("11111111");
//定义属性。
//最后一个参数为null,因为属性没有参数。
custNamePropBldr = myTypeBuilder.DefineProperty(cpi.PropertyName, PropertyAttributes.HasDefault, Type.GetType(cpi.Type), null); custNamePropBldr.SetConstant("111111111");
//定义Get方法。
custNameGetPropMthdBldr = myTypeBuilder.DefineMethod(cpi.GetPropertyMethodName, getSetAttr, Type.GetType(cpi.Type), Type.EmptyTypes); custNameGetIL = custNameGetPropMthdBldr.GetILGenerator(); try
{
custNameGetIL.Emit(OpCodes.Ldarg_0);
//custNameGetIL.Emit(OpCodes.Ldfld, customerNameBldr);
custNameGetIL.Emit(OpCodes.Ldfld, customerNameBldr);
custNameGetIL.Emit(OpCodes.Ret);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
} //定义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);
//custNamePropBldr.SetConstant("ceshi");
//把创建的两个方法(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
{
if (propertyName.Length < 1) return "";
return propertyName.Substring(0, 1).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
}
}

C# ClassHelper动态创建程序集和类, 添加/删除类属性的更多相关文章

  1. JavaScript Dom基础-9-Dom查找方法; 设置DOM元素的样式; innerHTML属性的应用; className属性的应用; DOM元素上添加删除获取属性;

    JavaScript Dom基础 学习目标 1.掌握基本的Dom查找方法 domcument.getElementById() Domcument.getElementBy TagName() 2.掌 ...

  2. 用JQuery动态为选中元素添加/删除类

    在做一些tab页功能时,我们经常会见到如下样式: 即当选中一个元素时,在此元素下会添加相应的类,以示区别.今天就研究了一下如何用JQuery实现此效果. 1. HTML代码 <a id=&quo ...

  3. 022. ASP.NET为DataSet中数据集添加关系及动态创建主子表和添加主子表关系

    protected void Page_Load(object sender, EventArgs e) { string connectionString = "server=.;data ...

  4. javascript动态创建表格:新增、删除行和列

    转载:http://www.cnblogs.com/pato/archive/2009/09/02/1559068.html 利用js来动态创建表格有两种格式,appendChild()和insert ...

  5. Vue+iview实现添加删除类

    <style> .tab-warp{ border-bottom: solid 1px #e0e0e0; overflow: hidden; margin-top: 30px; posit ...

  6. DHTMLX 前端框架 建立你的一个应用程序 教程(十一)--添加/删除表格中的记录

    添加/删除表格中的记录 我们的最终功能是在表格中添加删除 我们通过单机工具栏上的按钮来实现添加删除 当我们单击添加按钮的时候, 表单中 第一行默认填写New contact 光标自动聚焦 当用户点击删 ...

  7. JavaScript学习 - 基础(八) - DOM 节点 添加/删除/修改/属性值操作

    html代码: <!--添加/删除/修改 --> <div id="a1"> <button id="a2" onclick=&q ...

  8. vim创建程序文件自动添加头部注释/自动文件头注释与模板定义

    Vim 自动文件头注释与模板定义 在vim的配置文件.vimrc添加一些配置可以实现创建新文件时自动添加文件头注释,输入特定命令可以生成模板. 使用方法 插入模式输入模式输入seqlogic[Ente ...

  9. MFC之RTTI与动态创建

    本人能力.精力有限,所言所感都基于自身的实践和有限的阅读.查阅,如有错误,欢迎拍砖,敬请赐教——博客园:钱智慧. 在说RTTI之前需要明白c++中类静态成员的初始化特点:类的静态数据成员需要在类体外显 ...

  10. MFC原理第四讲.动态创建机制

    MFC原理第四讲.动态创建机制 一丶要学习的知识点以及简介 动态创建是什么意思? 动态创建其实就是跟C++的new一样.都是创建对象.但是规避了C++语法的缺陷. 例如: char * ClassNa ...

随机推荐

  1. 鸿蒙HarmonyOS实战-Stage模型(线程模型)

    前言 线程是计算机中的一种执行单元,是操作系统进行调度的最小单位.它是进程中的实际运行单位,每个进程可以包含多个线程.线程可以理解为进程中的一个执行流,它独立运行,拥有独立的栈和寄存器,但共享进程的资 ...

  2. LeetCode 146. LRU CacheLRU缓存机制 (C++/Java)

    题目: Design and implement a data structure for Least Recently Used (LRU) cache. It should support the ...

  3. The sultion of P4959

    problem & blog 首先我们看到 \(x,y\) 有可能为负数,所以我们先把它旋转到第一象限. 然后我们发现如果 \(x_a \ge x_b\) 且 \(y_a \ge y_b\) ...

  4. vmware 和 hyper-v不兼容,此主机不支持64位客户机操作系统

    在控制面板中关闭hyper-v功能后,仍然提示此主机不支持64位客户机操作系统. 解决方法: 需要在开始按钮 - 右键  -打开Windows PowerShell(管理员). 输入: bcdedit ...

  5. Scrapy框架(八)--CrawlSpider

    CrawlSpider类,Spider的一个子类 - 全站数据爬取的方式 - 基于Spider:手动请求 - 基于CrawlSpider - CrawlSpider的使用: - 创建一个工程 - cd ...

  6. Bean Searcher v4.3.0 重大更新!

    往期阅读: 我这样写代码,比直接使用 MyBatis 效率提高了 100 倍 最近火起的 Bean Searcher 与 MyBatis Plus 倒底有啥区别? Bean Searcher v3.8 ...

  7. nordic——long range测试

    简介:本案例测试了long range,注意nrf52系列芯片中,部分硬件是不支持CADE的,也就是不支持long range,如nrf52832就不支持long range.同时协议栈也是部分支持, ...

  8. Java JSON组成和解析

    本框架JSON元素组成和分析,JsonElement分三大类型JsonArray,JsonObject,JsonString. JsonArray:数组和Collection子类,指定数组的话,使用A ...

  9. python重拾第十二天-sqlalchemy ORM

    本节内容 ORM介绍 sqlalchemy安装 sqlalchemy基本使用 多外键关联 多对多关系 表结构设计作业 1. ORM介绍 orm英文全称object relational mapping ...

  10. Linux修改dmesg 显示大小

    背景 由于在调试的时候没有串口,而通过dmesg打印的内容发现其中有截断的现象. 因此为了方便调试.将有关的缓冲区加大. 原理 Linux内核中打印内核消息时用到了一个环形缓冲区. 这个缓冲区的大小由 ...