反射发送实战-InvokeMember
下面的程序在运行时生成了一个Test.cs文件,并调用csc编译成Test.dll文件,然后利用Type.InvokeMember()方法调用其中的SayHello()方法,然后和原始方法对比一下性能。
using System;
using System.Diagnostics;
using System.IO;
using System.Reflection;
namespace InvokeMember
{
///
/// Class1 的摘要说明。
///
class Class1 { ///
/// 应用程序的主入口点。
///
[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();
}
}
///
/// Reflection 的摘要说明。
///
public class ReflectionTest
{
//保存动态生成并编译的类的type对象
Type theType = null;
//保存动态生成类的实例
object theClass = null;
///
/// 供Client调用的方法
///
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//调用方法时的参数数组
);
}
///
/// 运行时生成代码
///
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");
}
}}
最后贴一个BindingFlags的Demo Share with EveryOne
-----------------------------------------------
using System;
using System.Reflection;
using System.IO;
namespace BindingFlagsSnippet
{
class EntryPoint
{
static void Main(string[] args)
{
Invoke.Go();
}
}
class Invoke
{
public static void Go()
{
// BindingFlags.InvokeMethod
// Call a static method.
Type t = typeof (TestClass);
Console.WriteLine();
Console.WriteLine("Invoking a static method.");
Console.WriteLine("-------------------------");
t.InvokeMember ("SayHello", BindingFlags.InvokeMethod, null, null, new object [] {});
// BindingFlags.InvokeMethod
// Call an instance method.
TestClass c = new TestClass ();
Console.WriteLine();
Console.WriteLine("Invoking an instance method.");
Console.WriteLine("----------------------------");
c.GetType().InvokeMember ("AddUp", BindingFlags.InvokeMethod, null, c, new object [] {});
c.GetType().InvokeMember ("AddUp", BindingFlags.InvokeMethod, null, c, new object [] {});
// BindingFlags.InvokeMethod
// Call a method with parameters.
object [] args = new object [] {100.09, 184.45};
object result;
Console.WriteLine();
Console.WriteLine("Invoking a method with parameters.");
Console.WriteLine("---------------------------------");
result = t.InvokeMember ("ComputeSum", BindingFlags.InvokeMethod, null, null, args);
Console.WriteLine ("{0} + {1} = {2}", args[0], args[1], result);
// BindingFlags.GetField, SetField
Console.WriteLine();
Console.WriteLine("Invoking a field (getting and setting.)");
Console.WriteLine("--------------------------------------");
// Get a field value.
result = t.InvokeMember ("Name", BindingFlags.GetField, null, c, new object [] {});
Console.WriteLine ("Name == {0}", result);
// Set a field.
t.InvokeMember ("Name", BindingFlags.SetField, null, c, new object [] {"NewName"});
result = t.InvokeMember ("Name", BindingFlags.GetField, null, c, new object [] {});
Console.WriteLine ("Name == {0}", result);
Console.WriteLine();
Console.WriteLine("Invoking an indexed property (getting and setting.)");
Console.WriteLine("--------------------------------------------------");
// BindingFlags.GetProperty
// Get an indexed property value.
int index = 3;
result = t.InvokeMember ("Item", BindingFlags.GetProperty, null, c, new object [] {index});
Console.WriteLine ("Item[{0}] == {1}", index, result);
// BindingFlags.SetProperty
// Set an indexed property value.
index = 3;
t.InvokeMember ("Item", BindingFlags.SetProperty, null, c, new object [] {index, "NewValue"});
result = t.InvokeMember ("Item", BindingFlags.GetProperty , null, c, new object [] {index});
Console.WriteLine ("Item[{0}] == {1}", index, result);
Console.WriteLine();
Console.WriteLine("Getting a field or property.");
Console.WriteLine("----------------------------");
// BindingFlags.GetField
// Get a field or property.
result = t.InvokeMember ("Name", BindingFlags.GetField | BindingFlags.GetProperty, null, c, new object [] {});
Console.WriteLine ("Name == {0}", result);
// BindingFlags.GetProperty
result = t.InvokeMember ("Value", BindingFlags.GetField | BindingFlags.GetProperty, null, c, new object [] {});
Console.WriteLine ("Value == {0}", result);
Console.WriteLine();
Console.WriteLine("Invoking a method with named parameters.");
Console.WriteLine("---------------------------------------");
// BindingFlags.InvokeMethod
// Call a method using named parameters.
object[] argValues = new object [] {"Mouse", "Micky"};
String [] argNames = new String [] {"lastName", "firstName"};
t.InvokeMember ("PrintName", BindingFlags.InvokeMethod, null, null, argValues, null, null, argNames);
Console.WriteLine();
Console.WriteLine("Invoking a default member of a type.");
Console.WriteLine("------------------------------------");
// BindingFlags.Default
// Call the default member of a type.
Type t3 = typeof (TestClass2);
t3.InvokeMember ("", BindingFlags.InvokeMethod | BindingFlags.Default, null, new TestClass2(), new object [] {});
// BindingFlags.Static, NonPublic, and Public
// Invoking a member by reference.
Console.WriteLine();
Console.WriteLine("Invoking a method by reference.");
Console.WriteLine("-------------------------------");
MethodInfo m = t.GetMethod("Swap");
args = new object[2];
args[0] = 1;
args[1] = 2;
m.Invoke(new TestClass(),args);
Console.WriteLine ("{0}, {1}", args[0], args[1]);
// The string is case-sensitive.
Type type = Type.GetType("System.String");
// Check to see if the value is valid. If the object is null, the type does not exist.
if (type == null)
{
Console.WriteLine("Please ensure that you specify only valid types in the type field.");
Console.WriteLine("The type name is case-sensitive.");
return;
}
// Declare and populate the arrays to hold the information.
// You must declare either NonPublic or Public with Static or the search will not work.
FieldInfo [] fi = type.GetFields (BindingFlags.Static |
BindingFlags.NonPublic | BindingFlags.Public);
// BindingFlags.NonPublic
MethodInfo [] miNonPublic = type.GetMethods (BindingFlags.Static |
BindingFlags.NonPublic);
// BindingFlags.Public
MethodInfo [] miPublic = type.GetMethods (BindingFlags.Static |
BindingFlags.Public);
// Iterate through all the nonpublic methods.
foreach (MethodInfo method in miNonPublic)
{
Console.WriteLine(method);
}
// Iterate through all the public methods.
foreach (MethodInfo method in miPublic)
{
Console.WriteLine(method);
}
// Iterate through all the fields.
foreach (FieldInfo f in fi)
{
Console.WriteLine(f);
}
// BindingFlags.Instance
// Call an instance method.
TestClass tc = new TestClass ();
Console.WriteLine();
Console.WriteLine("Invoking an Instance method.");
Console.WriteLine("----------------------------");
tc.GetType().InvokeMember ("AddUp", BindingFlags.Public |
BindingFlags.Instance | BindingFlags.CreateInstance,
null, tc, new object [] {});
// BindingFlags.CreateInstance
// Calling and creating an instance method.
Console.WriteLine();
Console.WriteLine("Invoking and creating an instance method.");
Console.WriteLine("-----------------------------------------");
tc.GetType().InvokeMember ("AddUp", BindingFlags.Public |
BindingFlags.Instance | BindingFlags.CreateInstance,
null, tc, new object [] {});
// BindingFlags.DeclaredOnly
TestClass tc2 = new TestClass();
Console.WriteLine();
Console.WriteLine("DeclaredOnly members");
Console.WriteLine("---------------------------------");
System.Reflection.MemberInfo[] memInfo =
tc2.GetType().GetMembers(BindingFlags.DeclaredOnly);
for(int i=0;i<memInfo.Length;i++)
{
Console.WriteLine(memInfo[i].Name);
}
// BindingFlags.SuppressChangeType
TestClass obj = new TestClass();
Console.WriteLine();
Console.WriteLine("Invoking static method - PrintName");
Console.WriteLine("---------------------------------");
System.Reflection.MethodInfo methInfo =
obj.GetType().GetMethod("PrintName");
methInfo.Invoke(obj,BindingFlags.SuppressChangeType |
BindingFlags.InvokeMethod, null,new object[]
{"Brad","Smith"},null);
// BindingFlags.IgnoreCase
Console.WriteLine();
Console.WriteLine("Using IgnoreCase and invoking the PrintName method.");
Console.WriteLine("---------------------------------------------------");
methInfo = obj.GetType().GetMethod("PrintName");
methInfo.Invoke(obj,BindingFlags.IgnoreCase |
BindingFlags.InvokeMethod, null,new object[]
{"brad","smith"},null);
// BindingFlags.IgnoreReturn
Console.WriteLine();
Console.WriteLine("Using IgnoreReturn and invoking the PrintName method.");
Console.WriteLine("-----------------------------------------------------");
methInfo = obj.GetType().GetMethod("PrintName");
methInfo.Invoke(obj,BindingFlags.IgnoreReturn |
BindingFlags.InvokeMethod, null,new object[]
{"Brad","Smith"},null);
// BindingFlags.OptionalParamBinding
Console.WriteLine();
Console.WriteLine("Using OptionalParamBinding and invoking the PrintName method.");
Console.WriteLine("-------------------------------------------------------------");
methInfo = obj.GetType().GetMethod("PrintName");
methInfo.Invoke(obj,BindingFlags.OptionalParamBinding |
BindingFlags.InvokeMethod, null,new object[]
{"Brad","Smith"},null);
// BindingFlags.ExactBinding
Console.WriteLine();
Console.WriteLine("Using ExactBinding and invoking the PrintName method.");
Console.WriteLine("-----------------------------------------------------");
methInfo = obj.GetType().GetMethod("PrintName");
methInfo.Invoke(obj,BindingFlags.ExactBinding |
BindingFlags.InvokeMethod, null,new object[]
{"Brad","Smith"},null);
// BindingFlags.FlattenHierarchy
Console.WriteLine();
Console.WriteLine("Using FlattenHierarchy and invoking the PrintName method.");
Console.WriteLine("---------------------------------------------------------");
methInfo = obj.GetType().GetMethod("PrintName");
methInfo.Invoke(obj,BindingFlags.FlattenHierarchy |
BindingFlags.InvokeMethod, null,new object[]
{"Brad","Smith"},null);
}
}
public class TestClass
{
public String Name;
private Object [] values = new Object [] {0, 1,2,3,4,5,6,7,8,9};
public Object this [int index]
{
get
{
return values[index];
}
set
{
values[index] = value;
}
}
public Object Value
{
get
{
return "the value";
}
}
public TestClass ()
{
Name = "initialName";
}
int methodCalled = 0;
public static void SayHello ()
{
Console.WriteLine ("Hello");
}
public void AddUp ()
{
methodCalled++;
Console.WriteLine ("AddUp Called {0} times", methodCalled);
}
public static double ComputeSum (double d1, double d2)
{
return d1 + d2;
}
public static void PrintName (String firstName, String lastName)
{
Console.WriteLine ("{0},{1}", lastName,firstName);
}
public void PrintTime ()
{
Console.WriteLine (DateTime.Now);
}
public void Swap(ref int a, ref int b)
{
int x = a;
a = b;
b = x;
}
}
[DefaultMemberAttribute ("PrintTime")]
public class TestClass2
{
public void PrintTime ()
{
Console.WriteLine (DateTime.Now);
}
}
}