反射发送实战(-)InvokeMember

反射是.net中的高级功能之一,利用反射可以实现许多以前看来匪夷所思的功能,下面是我看了《Programming C# 》( O'Reilly )之后对于反射的一点实践,本想直接做个应用程序来说明问题,但苦于工作繁忙并考虑到以简单为主,故先对反射发送(reflection emit)的使用做一些介绍。文章最后再给出一个实例。

下面的程序在运行时生成了一个Test.cs文件,并调用csc编译成Test.dll文件,然后利用 Type.InvokeMember() 方法调用其中的 SayHello() 方法,然后和原始方法对比一下性能。

using System;
using System.Diagnostics;
using System.IO;
using System.Reflection;

namespace InvokeMember
{
///

1<summary>   
2///  Class1 的摘要说明。   
3///  </summary>

class Class1 { ///

1<summary>   
2///  应用程序的主入口点。   
3///  </summary>

[STAThread]
static void Main( string [] args)
{
// 循环次数
const int iterations = 100 ;
// 计算所用时间
DateTime startTime = DateTime.Now;
for ( int i = 0 ;i < iterations;i ++ ) { // 对照方法
Console.WriteLine( " Hello,World " );
}
TimeSpan elasped = DateTime.Now - startTime;
Console.WriteLine( " Looping Elapsed milliseconds: " + elasped.TotalMilliseconds + " for {0} iterations " ,iterations);

// 使用反射发送
ReflectionTest t = new ReflectionTest();
// 计算所用时间
startTime = DateTime.Now;
for ( int i = 0 ;i < iterations;i ++ )
{
t.DoOperation();
}

elasped = DateTime.Now - startTime;

Console.WriteLine( " Looping Elapsed milliseconds: " + elasped.TotalMilliseconds + " for {0} iterations " ,iterations);
Console.ReadLine();
}
}

///

1<summary>   
2///  Reflection 的摘要说明。   
3///  </summary>

public class ReflectionTest
{
// 保存动态生成并编译的类的type对象
Type theType = null ;
// 保存动态生成类的实例
object theClass = null ;

///

1<summary>   
2///  供Client调用的方法   
3///  </summary>

public void DoOperation()
{
// 未初始化
if (theType == null )
{
// 初始化
GenerateCode();
}
// 调用方法时的参数数组(此处为空)
object [] arguments = new object [ 0 ];
// 调用动态生成类的方法
theType.InvokeMember( " SayHello " , // 要调用的方法名
BindingFlags.Default | BindingFlags.InvokeMethod, // Binding标志,具体参看msdn
null , // 使用默认Binding对象
theClass, // 在theClass实例上调用此方法
arguments // 调用方法时的参数数组
);
}

///

1<summary>   
2///  运行时生成代码   
3///  </summary>

private void GenerateCode()
{
// 文件名
string fileName = " Test " ;
// 打开文件,如果不存在,则创建
Stream s = File.Open(fileName + " .cs " ,FileMode.Create);
// 创建一个StreamWriter来写入数据
StreamWriter wrtr = new StreamWriter(s);
// 写入动态创建类的源代码
wrtr.WriteLine( " // 动态创建Test类 " );

// 类名
string className = " TestClass " ;
wrtr.WriteLine( " using System; " );
wrtr.WriteLine( " class {0} " ,className);
wrtr.WriteLine( " { " );

wrtr.WriteLine( " \tpublic void SayHello() " );
wrtr.WriteLine( " \t{ " );

wrtr.WriteLine( " \t\tConsole.WriteLine("Hello,World"); " );
wrtr.WriteLine( " \t} " );
wrtr.WriteLine( " } " );

// 关闭StreamWriter和文件
wrtr.Close();
s.Close();

// 启动进程编译源文件
// 指定参数
ProcessStartInfo psi = new ProcessStartInfo();
// 启动cmd.exe
psi.FileName = " cmd.exe " ;
// cmd.exe的参数,/c-close,完成后关闭;后为参数,指定cmd.exe使用csc来编译刚才生成的源文件
string compileString = " /c C:\\WINNT\\Microsoft.NET\\Framework\\v1.1.4322\\csc.exe /optimize+ /target:library {0}.cs " ;
psi.Arguments = String.Format(compileString,fileName);
// 运行时的风格-最小化
psi.WindowStyle = ProcessWindowStyle.Minimized;

// 启动进程
Process proc = Process.Start(psi);
// 指定当前在此进程退出前等待
proc.WaitForExit();

// 从编译好的dll文件load一个Assembly
Assembly a = Assembly.LoadFrom(fileName + " .dll " );

// 创建类的实例
theClass = a.CreateInstance(className);
// 取得此类实例的类型
theType = a.GetType(className);
// 删除源文件
// File.Delete(flieName + ".cs");
}
}
}

Published At
Categories with Web编程
Tagged with
comments powered by Disqus