`
tomhibolu
  • 浏览: 1375661 次
文章分类
社区版块
存档分类
最新评论

.NET内存中动态构造类并重载某函数

 
阅读更多

开发中,经常需要用到很多容器功能,而容器级别的功能大都是Reflection(类反射)所提供的,本文就是借这个名来看看如何在.NET 内存中动态构造类并重载某函数,具体的例子代码如下:

原类:TestClass

内存中动态生成类: TestClassEx

内存中动态生成类的工厂类:DynamicFactory

接口: ITest

复制以及重载的目标方法:TestMethod

调用集成采用Console方式进行,我们分别看看各个类的代码;

TestClass.cs

public class TestClass
{
private long m_lUsers = 0;
private int m_iUsers = 0;
private string m_strTest = null;
private object m_oTest = null;

public TestClass()
{
m_lUsers++;
m_iUsers++;
m_strTest = "aa";
m_oTest = new object();
}

public long Users
{
set
{
m_lUsers = value;
}
get
{
return m_lUsers;
}
}

public void TestMethod()
{
System.Console.WriteLine("TestMethod: Message output from Emit Console...");

m_lUsers = 50;
m_lUsers += 100;
System.Console.WriteLine("Users :" + Convert.ToString(m_lUsers) + " people in current context");
}

public void EndMethod()
{
System.Console.WriteLine("EndMethod:Ending message logic*****");
}

}

ITest.cs

public interface ITest
{
void TestMethod();
}

DynamicFactory.cs

public class DynamicFactory
{
private AssemblyBuilder assemblyBuilder = null;
private ModuleBuilder moduleBuilder = null;
private TypeBuilder typeBuilder = null;
private ILGenerator generator = null;

public DynamicFactory()
{
}

public Type GenerateClass(Type typeForMirror)
{
this.GenerateAssembly();

//build a type
this.typeBuilder = moduleBuilder.DefineType("TestClassEx",
TypeAttributes.Public | TypeAttributes.BeforeFieldInit,
typeForMirror, new Type[] { typeof(ITest) });

this.GenerateConstruct(typeBuilder);
this.BuildFields(typeForMirror);

this.BuildMethod(typeForMirror);

Type typeReturn = this.typeBuilder.CreateType(); //Close the type
assemblyBuilder.Save("ExtendingAssembly.dll");
return typeReturn;
}

private void BuildFields(Type typeForMirror)
{
FieldInfo[] fieldInfos = typeForMirror.GetFields(BindingFlags.NonPublic | BindingFlags.Public);
for (int i = 0; i < fieldInfos.Length; i++)
{
FieldInfo fi = fieldInfos[i];
typeBuilder.DefineField(fi.Name, fi.FieldType, fi.Attributes);
}
}

private void GenerateAssembly()
{
AppDomain currentDomain = Thread.GetDomain();
AssemblyName assemblyName = new AssemblyName();
assemblyName.Name = "Extending";
assemblyBuilder = currentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndSave);
this.moduleBuilder = assemblyBuilder.DefineDynamicModule(
"ExtendingAssembly",
"ExtendingAssembly.dll");
}

private void GenerateConstruct(TypeBuilder typeBuilder)
{
ConstructorBuilder constructorBuilder = typeBuilder.DefineConstructor(
MethodAttributes.Public,
CallingConventions.Standard,
System.Type.EmptyTypes);

this.generator = constructorBuilder.GetILGenerator();
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Call, typeBuilder.BaseType.GetConstructor(System.Type.EmptyTypes));
generator.Emit(OpCodes.Ret);
}

/// <summary>
/// Attention: here we need to overload the specified TestMethod function for our EmitConsole project.
/// So the MethodAttributes.Virtual is necessary when we rebuild this function in memory.
/// </summary>
/// <param name="typeForMirror"></param>
private void BuildMethod(Type typeForMirror)
{
// Now, let's build a method and add a custom attribute to it.
MethodBuilder methodBuilder = typeBuilder.DefineMethod("TestMethod",
MethodAttributes.Public | MethodAttributes.HideBySig |
MethodAttributes.Virtual | MethodAttributes.NewSlot,
null,
new Type[] {});

this.generator = methodBuilder.GetILGenerator();

generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Call, typeForMirror.GetMethod("TestMethod"));

generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Call, typeForMirror.GetMethod("EndMethod"));

generator.Emit(OpCodes.Ret);
}

}

console的集成类program.cs:

class Program
{
static void Main(string[] args)
{
DynamicFactory df = new DynamicFactory();

// type for mirroring testing method
Type typeMirror = df.GenerateClass(typeof(TestClass));

object o = Activator.CreateInstance(typeMirror);
TestClass tc = (TestClass)o;
tc.TestMethod();

ITest it = (ITest)Activator.CreateInstance(typeMirror);
it.TestMethod();

System.Console.WriteLine("Ending finally...");
}
}

从最后的运行效果大家可以分析看看,采用TestClass强转后的instance与不转使用interface来直接集成的program最后的结果不一样,自己可以分析看看是啥原因产生的。

本文中未提及到的Enum, Property等的复制产生可以参照:http://www.codeproject.com/KB/cs/DLR.aspx

能够在内存中动态重组类的作用非常大,可以实现基于AOP的拦截,实现基于标注的各类应用譬如自动组装Transaction、依赖注入等众多的高级应用,对于编写框架应用作用无疑巨大。

分享到:
评论

相关推荐

    利用反射动态创建对象在VS.Net中,有很多种方法动态调用对象的构造函数

    在VS.Net中,有很多种方法动态调用对象的构造函数。一是通过Activator类的CreateInstance()方法。这个方法我们在Remoting中也用过。它实际上是在本地或从远程创建对象类型,或获取对现有远程对象的引用。它的方法...

    Test源码(vb.net2012构造函数例)

    源码由Person派生Employee,再派生OfficeEmployee。...然后里面有重写、重载,包括构造。 注意的是,构造中因为对其值的重写,导致引用子类,而子类有New会出错。 所以应在方法或属性中用New才能避开这个矛盾

    深入.NET平台和C#编程

    2 添加带参构造函数 在构造函数中给成员赋值 通过构造函数创建对象 用run方法 3 重载run 方法 给run 传递一个int类型参数speed 最高车速 输出信息 车速通过参数传递"&gt;编写控制台程序 模拟小汽车 Car 奔跑 1 编写...

    .net数据访问类 SQL Helper 类

    您是否曾经将数据访问代码包装在 Helper 函数中,以便能够在一行中调用存储过程?如果是,那么 Microsoft? Data Access Application Block for .NET 正是为您设计的。 Data Access Application Block 将访问 ...

    delphi动态虚拟覆盖重载重定义的区别

    由于虚拟方法能被覆盖,在代码中调用一个指定的虚拟方法时编译器并不知道它的地址,因此,编译器通过建立虚拟方法表(VMT)来查找在运行时的函数地址。所有的虚拟方法在运行时通过VMT来高度,一个对象的VMT表中除了...

    VB.Net常用语法

    您可以在函数中调用,包括在API中(当然VB.Net不再使用winAPI). 甚至一些至关紧要的过程也不例外:如new过程(此方法王国荣文章中 有介绍) 如: class class1 Overloads Public Sub New() 。。。。。。 ...

    ASP.NET.4揭秘

    17.1.6 重载方法和构造函数564 17.1.7 声明命名空间565 17.1.8 创建部分类566 17.1.9 继承和abstract类567 17.1.10 声明接口569 17.1.11 使用访问修饰符570 17.1.12 智能提示和组件571 17.1.13 在组件中使用asp.net...

    C#与.NET3.5高级程序设计(第4版) 中文1

    5.2 类构造函数 111 5.3 this关键字的作用 114 5.4 static关键字 118 5.5 定义OOP的支柱 124 5.6 C#访问修饰符 127 5.7 第一个支柱:C#的封装支持 129 5.8 常量数据 136 5.9 只读字段 137 5.10 C#...

    .net技术资料大全(语言规范 源码教程 学习笔记 技术资料 .net代码生成器)

    如何:在VisualC#.NET中建立一个平滑的进度条.txt 如何得到网卡号.txt 如何调用WindowsAPI的要点.txt 如何控制输入法.txt 如何利用GDI作图解决异或问题.txt 如何取硬件标志.txt 如何让应用程序只有一个实例...

    ASP.NET 控件的使用

    15.1.6 重载方法和构造函数 473 15.1.7 声明命名空间 474 15.1.8 创建部分类 475 15.1.9 继承和MustInherit类 476 15.1.10 声明接口 478 15.1.11 使用访问修饰符 480 15.1.12 智能提示和组件 480 15.1.13 在组件中...

    Visual.Basic.2010.&.NET4.高级编程(第6版)-文字版.pdf

    2.11.2 重载构造函数方法 121 2.11.3 共享方法、变量和事件 122 2.11.4 运算符重载 127 2.11.5 委托 129 2.11.6 类和组件 133 2.11.7 lambda表达式 134 2.12 小结 135 第3章 定制对象 137 3.1 继承 ...

    asp.net面试题

    第三种:new 约束指定泛型类声明中的任何类型参数都必须有公共的无参数构造函数。 2.如何把一个array复制到arrayList里 foreach( object o in array )arrayList.Add(o); 3.datagrid.datasouse可以连接什么数据源 ...

    Visual C++ 2005入门经典.part08.rar (整理并添加所有书签)

    7.4.4 在构造函数中使用初始化列表 7.5 类的私有成员 7.5.1 访问私有类成员 7.5.2 类的友元函数 7.5.3 默认复制构造函数 7.6 this指针 7.7 类的const对象 7.7.1 类的const成员函数 7.7.2 类外部的成员函数定义 7.8 ...

    Visual C++ 2005入门经典.part04.rar (整理并添加所有书签)

    7.4.4 在构造函数中使用初始化列表 7.5 类的私有成员 7.5.1 访问私有类成员 7.5.2 类的友元函数 7.5.3 默认复制构造函数 7.6 this指针 7.7 类的const对象 7.7.1 类的const成员函数 7.7.2 类外部的成员函数定义 7.8 ...

    Visual C++开发经验技巧宝典(第1章)

    0071 如何在常量函数中修改数据成员 30 1.9 STL模板库 30 0072 为什么在程序中广泛使用STL 30 0073 如何在STL中使用容器 30 0074 STL算法的优点 31 0075 如何设计和使用STL迭代器 31 0076 使用STL需要...

Global site tag (gtag.js) - Google Analytics