C# · 12月 22, 2021

反射发送实战-InvokeMember 转

<span style=”font-size: 10pt”>反射是.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
{
///
/// 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);
<table height=”18″ cellspacing=”0″ cellpadding=”0″ width=”470″ border=”0″>@H_502_5@<tr>
<td align=”center”><span style=”font-size: 10pt”></td>
</tr></table>
<span style=”font-size: 10pt”>//使用反射发送
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,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”,c,new object [] {});            c.GetType().InvokeMember (“AddUp”,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”,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,new object [] {});            Console.WriteLine (“Name == {0}”,result);            // Set a field.            t.InvokeMember (“Name”,BindingFlags.SetField,new object [] {“NewName”});            result = t.InvokeMember (“Name”,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,new object [] {index});            Console.WriteLine (“Item[{0}] == {1}”,index,result);            // BindingFlags.SetProperty            // Set an indexed property value.            index = 3;            t.InvokeMember (“Item”,BindingFlags.SetProperty,new object [] {index,”NewValue”});            result = t.InvokeMember (“Item”,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,result);            // BindingFlags.GetProperty            result = t.InvokeMember (“Value”,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”,argValues,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,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[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”,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,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,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);

            // 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);

            // 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);             // 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);        }    }

    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},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);        }    }}