C# ClassHelper动态创建程序集和类, 添加/删除类属性
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动态创建程序集和类, 添加/删除类属性的更多相关文章
- JavaScript Dom基础-9-Dom查找方法; 设置DOM元素的样式; innerHTML属性的应用; className属性的应用; DOM元素上添加删除获取属性;
JavaScript Dom基础 学习目标 1.掌握基本的Dom查找方法 domcument.getElementById() Domcument.getElementBy TagName() 2.掌 ...
- 用JQuery动态为选中元素添加/删除类
在做一些tab页功能时,我们经常会见到如下样式: 即当选中一个元素时,在此元素下会添加相应的类,以示区别.今天就研究了一下如何用JQuery实现此效果. 1. HTML代码 <a id=&quo ...
- 022. ASP.NET为DataSet中数据集添加关系及动态创建主子表和添加主子表关系
protected void Page_Load(object sender, EventArgs e) { string connectionString = "server=.;data ...
- javascript动态创建表格:新增、删除行和列
转载:http://www.cnblogs.com/pato/archive/2009/09/02/1559068.html 利用js来动态创建表格有两种格式,appendChild()和insert ...
- Vue+iview实现添加删除类
<style> .tab-warp{ border-bottom: solid 1px #e0e0e0; overflow: hidden; margin-top: 30px; posit ...
- DHTMLX 前端框架 建立你的一个应用程序 教程(十一)--添加/删除表格中的记录
添加/删除表格中的记录 我们的最终功能是在表格中添加删除 我们通过单机工具栏上的按钮来实现添加删除 当我们单击添加按钮的时候, 表单中 第一行默认填写New contact 光标自动聚焦 当用户点击删 ...
- JavaScript学习 - 基础(八) - DOM 节点 添加/删除/修改/属性值操作
html代码: <!--添加/删除/修改 --> <div id="a1"> <button id="a2" onclick=&q ...
- vim创建程序文件自动添加头部注释/自动文件头注释与模板定义
Vim 自动文件头注释与模板定义 在vim的配置文件.vimrc添加一些配置可以实现创建新文件时自动添加文件头注释,输入特定命令可以生成模板. 使用方法 插入模式输入模式输入seqlogic[Ente ...
- MFC之RTTI与动态创建
本人能力.精力有限,所言所感都基于自身的实践和有限的阅读.查阅,如有错误,欢迎拍砖,敬请赐教——博客园:钱智慧. 在说RTTI之前需要明白c++中类静态成员的初始化特点:类的静态数据成员需要在类体外显 ...
- MFC原理第四讲.动态创建机制
MFC原理第四讲.动态创建机制 一丶要学习的知识点以及简介 动态创建是什么意思? 动态创建其实就是跟C++的new一样.都是创建对象.但是规避了C++语法的缺陷. 例如: char * ClassNa ...
随机推荐
- C# dynamic动态对象赋值
dynamic 如果接收的是匿名对象,是无法为属性赋值的,而如果是接收的定义对象,又无法扩展字段. 解决办法序列化为json字符串,然后用Dictionary反序列化,就能赋值了.也能扩展新的字段. ...
- 在Cocos2d中拖动组件并吸附到节点
最近在学习制作小游戏,要实现一个拖动吸附效果,这里简单实现一下 代码实现 定义节点和函数功能 在properties里新建一个对象,用来接收目标区域的节点 properties:{ sense: { ...
- 一文搞懂 Spring Bean 的生命周期
一. 前言 在学习Spring框架的IOC.AOP两大功能之前,首先需要了解这两个技术的基础--Bean.在Spring框架中,Bean无处不在,IOC容器管理的对象就是各种各样的Bean.理解Bea ...
- 从源码的角度弄懂MyBatis动态代理开发原理
MyBatis提供了一种动态代理实现SQL调用的功能,使用者只需要在映射文件中配置SQL语句与映射规则即可完成SQL调用和结果集封装.下面代码展示了动态代理调用的基本步骤: public void t ...
- itest(爱测试)开源接口测试&敏捷测试&极简项目管理 8.0.0 发布,测试重大升级
(一)itest 简介及更新说明 itest 开源敏捷测试管理,testOps 践行者,极简的任务管理,测试管理,缺陷管理,测试环境管理,接口测试,接口Mock 6合1,又有丰富的统计分析.可按测试包 ...
- Android应用程序启动流程浅析-(三万字长文慎点&Android14)
在Android桌面Launcher源码浅析中介绍了Android的桌面程序Launcher是如何响应用户点击事件并启动App的,这篇文章继续介绍App在Android系统层是的启动流程. 一.启动流 ...
- php简单登录
<?php // 1,php接收参数 $userName = $_POST['userName']; $userPwd = $_POST['userPwd']; // 2,PHP需要操作数据库 ...
- CF1184E1题解
CF11841E1 & blog 尽然想让第一条边最大且这条边在最小生成树中,那么这条边就需要尽量晚. 但是假如加上一条边 \(i\) 可以使 \(u_1\) 和 \(v_1\) 联通并且第 ...
- P7322
P7322 好神仙! \(\color{#5bc9}\text{提醒,本文有大量没有推到过程的式子,所以读者可以自己遮住先推一下}\) Inscription: 有一个长度为 \(k\) 的窗口,在一 ...
- HP惠普战66电源黄灯闪烁无法充电
HP惠普战66电源黄灯闪烁无法充电 TYPE-C PD 无法充电. 解决办法:关机状态下,拔除外部设备,长按电源键30秒以释放主板静电,再插电源线可以开机.