博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
《CLR via C#》读书笔记 之 程序集加载和反射
阅读量:6223 次
发布时间:2019-06-21

本文共 23481 字,大约阅读时间需要 78 分钟。

第二十三章 程序集加载和反射

2013-04-06

 
 
 
 
 
 
 
 

23.1 程序集加载


我们知道,JIT编译器将方法的IL代码编译成本地代码时,会查看IL代码中引用了哪些类型。在运行时,会利用程序集的TypeRef和AssemblyRef元数据表来确定哪一个程序集定义了所有引用类型。

在内部,CLR使用System.Reflection.Assembly类的静态方法Load来加载这个程序集。这个方法是CLR中与Win32 LoadLibrary函数等价的方法。以下是Load方法的几个重载版本:

View Code
1 public class Assembly2 {3   public static Assembly Load(AssemblyName assemblyRef);4   public static Assembly Load(String assemblyString);5 }

Load导致CLR向程序集应用一个版本绑定重定向策略,并在GAC(全局程序集缓存)中查看程序集。如果没找到,就去应用程序的基目录、私有路径子目录和codebase(参考3.9 高级管理控制)位置查找。如果调用Load时,传递的是一个弱命名的程序集,Load就不会向程序集应用一个版本绑定重定向策略,也不会去GAC中查找程序集。

在内部,CLR使用System.Reflection.Assembly类的另一个静态方法LoadFrom

View Code
1 public class Assembly2 {3   public static Assembly LoadFrom(String path);4 }

LoadFrom首先会调用System.Reflection.AssemblyName类的静态方法GetAssemblyName。该方法打开指定的文件,查找AssemblyRef元数据表的记录项,提取程序集标识信息,然后返回一个System.Reflection.AssemblyName对象。随后在LoadFrom内部调用上面的Load方法。若能找到,加载;若不能,用实参传递的路径加载程序集。

另外,LoadFrom方法允许传递一个URL作为实参

View Code
1 Assembly a=Assembly.LoadFrom(@"http://Wintellect.com/SomeAssembly.dll");

上面代码,CLR会下载文件,将他安装到用户的下载缓存中,再从那儿下载。

23.2 使用反射构建动态可扩展应用程序 


 

元数据是用一系列表来存储的。生成一个程序集或模块时,编译器会创建一个类型定义表、一个字段定义表、一个方法定义表及其他表。利用System.Reflection命名空间中包含的一些类型,可以写代码来反射(或者说”解析“)这些元数据表。

23.3 反射的性能 


 

 反射是相当强大的一个机制,它允许在运行时发现并使用编译器还不了解的类型及其成员。但是,它有以下两个缺点:

  • 反射回造成编译时无法保证 类型安全性。由于反射严重依赖字符串,所以会丧失编译时类型安全性。如代码 Type.GetType("Jef"); 要求反射在程序集中查找一名为”Jef“的类型,但程序集中实际包含的是”Jeff“,代码编译时可通过,但运行时会出错。
  • 反射速度慢。使用反射式,要用字符串标识每个类型及其成员,需要用它们来扫描程序集的元数据。用反射调用一个方法时,首先必须将参数打包成数组,再次将解包数组到线程栈上,此外,还要检验实参数据类型是否正确,最后,要确保调用者有安全权限调用被调用着。

基于上述原因,推荐用接口技术或基类技术代替反射:

  • 让类型从一个编译时已知的基类型派生。在运行时,构造派生类型的一个实例,将对它的引用放到基类的一个变量中(利用转型),再调用基类型定义的虚方法。
  • 让类型实现一个编译时已知的接口。将对它的引用放到接口的一个变量中(利用转型),再调用接口定义的方法。

在使用这两种技术时,强烈建议在接口或基类型自己的程序集中定义它们,这有助于缓解版本控制的问题。欲知详情,请参见节

23.3.1 发现程序集中定义的类型

View Code
1 internal static class DiscoverTypes { 2    public static void Go() { 3       String dataAssembly = "System.Data, version=4.0.0.0, " + 4          "culture=neutral, PublicKeyToken=b77a5c561934e089"; 5       LoadAssemAndShowPublicTypes(dataAssembly); 6    } 7  8    private static void LoadAssemAndShowPublicTypes(String assemId) { 9       // Explicitly load an assembly in to this AppDomain10       Assembly a = Assembly.Load(assemId);11 12       // Execute this loop once for each Type 13       // publicly-exported from the loaded assembly 14       foreach (Type t in a.GetExportedTypes()) {15          Console.WriteLine(t.FullName);16       }17    }18 }

23.3.2 类型对象的准确含义

一个类型在一个AppDomain1中被首次访问时,CLR会构造System.RuntimeType的一个实例,并初始化这个对象的字段,以反映这个类型的信息。我们知道,System.Object定义了一个公共非虚实例方法GetType。调用这个方法是,CLR会判断指定对象的类型,并返回对它的RuntimeType对象的一个引用。由于在一个AppDomain中,每个类型只有一个RuntimeType对象(类型对象,参考4.4 运行时相互关系)。

除了Object的GetType,FCL还提供了获得Type对象的其它方式:

  • System.Type类型提供了静态方法GetType的几个重载版本。这个方法所有版本都接受一个String参数(指定类型的全名)。调用时,它首先会检查调用程序集是否有该类型,有,则返回一个恰当的RunTimeType对象的引用;没有,则检查MSCorLib.dll;再没有,返回null或System.TypeLoadException。
  • C#还提供操作符typeof来获得对一个类型的引用,通常可用它来将晚期绑定的类型信息与早期绑定(编译时已知)的类型信息比较,如下代码:
View Code
1 private static void SomeMethod(Object o)2 {3     //GetType方法在运行时返回对象的类型(晚期绑定)4     //typeof方法返回指定类的类型(早期绑定)5     if(o.GetType()==typeof(FileInfo)){...}6     if(o.GetType()==typeof(DirecotryInfo)){...}7 }

23.3.3 构建Exception派生类型的一个层次结构

View Code
1    public static void Go() { 2       // Explicitly load the assemblies that we want to reflect over 3       Assembly[] assemblies= LoadAssemblies(); 4  5       // Recursively build the class hierarchy as a hyphen-separated string 6       Func
ClassNameAndBase = null; 7 ClassNameAndBase = t => "-" + t.FullName + 8 ((t.BaseType != typeof(Object)) ? ClassNameAndBase(t.BaseType) : String.Empty); 9 10 // Define our query to find all the public Exception-derived types in this AppDomain's assemblies11 var exceptionTree =12 (from a in assemblies13 from t in a.GetExportedTypes()14 where t.IsClass && t.IsPublic && typeof(Exception).IsAssignableFrom(t)15 let typeHierarchyTemp = ClassNameAndBase(t).Split('-').Reverse().ToArray()16 let typeHierarchy = String.Join("-", typeHierarchyTemp, 0, typeHierarchyTemp.Length - 1)17 orderby typeHierarchy18 select typeHierarchy).ToArray();19 20 // Display the Exception tree21 Console.WriteLine("{0} Exception types found.", exceptionTree.Length);22 foreach (String s in exceptionTree) {23 // For this Exception type, split its base types apart24 String[] x = s.Split('-');25 26 // Indent based on # of base types and show the most-derived type27 Console.WriteLine(new String(' ', 3 * (x.Length - 1)) + x[x.Length - 1]);28 }29 }30 31 32 private static Assembly[] LoadAssemblies() {33 String[] assemblies = {34 "System, PublicKeyToken={0}",35 "System.Core, PublicKeyToken={0}",36 "System.Data, PublicKeyToken={0}",37 "System.Design, PublicKeyToken={1}",38 "System.DirectoryServices, PublicKeyToken={1}",39 "System.Drawing, PublicKeyToken={1}",40 "System.Drawing.Design, PublicKeyToken={1}",41 "System.Management, PublicKeyToken={1}",42 "System.Messaging, PublicKeyToken={1}",43 "System.Runtime.Remoting, PublicKeyToken={0}",44 "System.Security, PublicKeyToken={1}",45 "System.ServiceProcess, PublicKeyToken={1}",46 "System.Web, PublicKeyToken={1}",47 "System.Web.RegularExpressions, PublicKeyToken={1}",48 "System.Web.Services, PublicKeyToken={1}",49 "System.Windows.Forms, PublicKeyToken={0}",50 "System.Xml, PublicKeyToken={0}",51 };52 53 String EcmaPublicKeyToken = "b77a5c561934e089";54 String MSPublicKeyToken = "b03f5f7f11d50a3a";55 56 // Get the version of the assembly containing System.Object57 // We'll assume the same version for all the other assemblies58 Version version = typeof(System.Object).Assembly.GetName().Version;59 60 List
lassems = new List
();61 62 // Explicitly load the assemblies that we want to reflect over63 foreach (String a in assemblies) 64 {65 String AssemblyIdentity =66 String.Format(a, EcmaPublicKeyToken, MSPublicKeyToken) +67 ", Culture=neutral, Version=" + version;68 lassems.Add(Assembly.Load(AssemblyIdentity)); 69 }70 return lassems.ToArray();71 }

23.3.4 构造类型的实例

System.Acitivator的静态方法CreateInstance ,调用该方法可构造类型的实例(除了数组和委托)。数组调用Array的静态方法CreateInstance;委托调用Delegate的静态方法CreateDelegate。

23.4 设计支持加载项的应用程序


 

构建可扩展的应用程序时,接口是中心。可用基类来代替接口,但接口通常是首选的,因为它允许加载项开发人员选择他们自己的基类。下面描述如何设计加载项应用程序:

  • 创建一个“宿主SDK(Host SDK),它定义一个接口,接口的方法作为宿主应用程序域加载项之间的通信机制。一旦搞定接口,可为这个程序集赋予一个强名称(参见第3章),然后打包并部署到合作伙伴那里。一旦发布,就要避免对该程序集中类型做任何重大修改,例如,接口。但对参数或返回值定义了自己的数据类型,可添加。对程序集的任何修改,可能需要使用一个发布策略来部署它(参见第3章)。
  • 加载项实现上面“宿主SDK”定义的接口。
  • 宿主应用程序通过”宿主SDK“的接口来调用加载项的实现。

代码如下:

1)”宿主SDK“程序集HostSDK.dll代码:

View Code
1 using System;2 3 namespace Wintellect.HostSDK {4    public interface IAddIn {5       String DoSomething(Int32 x);6    }7 }

2)加载项AddInTypes.dll引用并实现HostSDK定义的接口,代码如下:

View Code
1 using System; 2 using Wintellect.HostSDK; 3  4 public class AddIn_A : IAddIn { 5    public AddIn_A() { 6    } 7    public String DoSomething(Int32 x) { 8       return "AddIn_A: " + x.ToString(); 9    }10 }11 12 public class AddIn_B : IAddIn {13    public AddIn_B() {14    }15    public String DoSomething(Int32 x) {16       return "AddIn_B: " + (x * 2).ToString();17    }18 }

3)宿主应用程序Host.exe引用HostSDK.dll,并动态加载加载项AddInType.dll。为了简化代码,假定加载项已部署到宿主的exe文件相同的目录。强烈建议研究一下Microsoft的MEF(托管可扩展性框架:Managed Extensiblity Framework)。

View Code
1 using System; 2 using System.IO; 3 using System.Reflection; 4 using System.Collections.Generic; 5 using Wintellect.HostSDK; 6  7 public sealed class Program { 8    public static void Main() { 9       // Find the directory that contains the Host exe10       String AddInDir = Path.GetDirectoryName(11          Assembly.GetEntryAssembly().Location);12 13       // Assume AddIn assemblies are in same directory as host's EXE file14       String[] AddInAssemblies = Directory.GetFiles(AddInDir, "*.dll");15 16       // Create a collection of usable Add-In Types17       List
AddInTypes = new List
();18 19 // Load Add-In assemblies; discover which types are usable by the host20 foreach (String file in AddInAssemblies) {21 Assembly AddInAssembly = Assembly.LoadFrom(file);22 23 // Examine each publicly-exported type24 foreach (Type t in AddInAssembly.GetExportedTypes()) {25 // If the type is a class that implements the IAddIn 26 // interface, then the type is usable by the host27 if (t.IsClass && typeof(IAddIn).IsAssignableFrom(t)) {28 AddInTypes.Add(t);29 }30 }31 }32 33 // Initialization complete: the host has discovered the usable Add-Ins34 35 // Here's how the host can construct Add-In objects and use them36 foreach (Type t in AddInTypes) {37 IAddIn ai = (IAddIn) Activator.CreateInstance(t);38 Console.WriteLine(ai.DoSomething(5));39 }40 }41 }

23.5 使用反射发现类型的成员

图1 封装了类型成员的反射类型的层次结构 

 以下程序演示了如何查询一个类型的成员与它们相关的一些信息。

View Code
1 using System; 2 using System.Reflection; 3  4 internal static class Program 5 { 6    public static void Main()  7    { 8       // Loop through all assemblies loaded in this AppDomain 9       Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();10       foreach (Assembly a in assemblies) 11       {12          Show(0, "Assembly: {0}", a);13 14          // Find Types in the assembly15          foreach (Type t in a.GetExportedTypes()) 16          {17             Show(1, "Type: {0}", t);18 19             // Indicate the kinds of members we want to discover20             const BindingFlags bf = BindingFlags.DeclaredOnly |21                BindingFlags.NonPublic | BindingFlags.Public |22                BindingFlags.Instance | BindingFlags.Static;23 24             // Discover the type's members25             foreach (MemberInfo mi in t.GetMembers(bf)) 26             {27                String typeName = String.Empty;28                if (mi is Type)            typeName = "(Nested) Type";29                if (mi is FieldInfo)       typeName = "FieldInfo";30                if (mi is MethodInfo)      typeName = "MethodInfo";31                if (mi is ConstructorInfo) typeName = "ConstructoInfo";32                if (mi is PropertyInfo)    typeName = "PropertyInfo";33                if (mi is EventInfo)       typeName = "EventInfo";34 35                Show(2, "{0}: {1}", typeName, mi);36             }37          }38       }39    }40 41    private static void Show(Int32 indent, String format, params Object[] args) 42    {43       Console.WriteLine(new String(' ', 3 * indent) + format, args);44    }45 }

Type除了GetMembers方法返回类型的所有成员外,还提供了一些方法能返回特定的类型成员:GetnestedTypes,GetFields,GetConstructors,GetMethods,GetProperties以及GetEvents方法 。

23.5.2 BindingFlags: 筛选返回的成员类型

默认设置时BindingFlags.Public|BindingFlag.Instance|BindingFlags.Static。

23.5.3 发现类型的接口

为获得类型继承的接口,可调用type类型的FindInterfaces或GetInterfaces方法。这些方法返回接口的type对象。注意:这些方法扫描类型的继承层次结构,并返回在指定类型及其所有基类型上定义的所有接口。

判定一个类型那些成员实现了那个特定接口有点复杂,因为多个接口可能定义同一个方法。为获得特定接口的MethodInfo对象,可调用GetInterfaceMap实例方法,它返回System.Reflection.InterfaceMapping的一个实例,它定义了四个字段,见如下实例:

View Code
1 using System; 2 using System.Reflection; 3  4 internal static class InterfaceDiscover 5 { 6    // Define two interfaces for testing 7    private interface IBookRetailer : IDisposable { 8       void Purchase(); 9       void ApplyDiscount();10    }11 12    private interface IMusicRetailer {13       void Purchase();14    }15 16    // This class implements 2 interfaces defined by this assembly and 1 interface defined by another assembly17    private sealed class MyRetailer : IBookRetailer, IMusicRetailer, IDisposable {18       // IBookRetailer methods19       void IBookRetailer.Purchase() { }20       public void ApplyDiscount() { }21 22       // IMusicRetailer method23       void IMusicRetailer.Purchase() { }24 25       // IDisposable method26       public void Dispose() { }27 28       // MyRetailer method (not an interface method)29       public void Purchase() { }30    }31 32    public static void Go() {33       // Find interfaces implemented by MyRetailer where the interface is defined in our own assembly.34       // This is accomplished using a delegate to a filter method that we pass to FindInterfaces.35       Type t = typeof(MyRetailer);36       Type[] interfaces = t.FindInterfaces(TypeFilter, typeof(InterfaceDiscover).Assembly);37       Console.WriteLine("MyRetailer implements the following interfaces (defined in this assembly):\n");38 39       // Show information about each interface40       foreach (Type i in interfaces) {41          InterfaceMapping map = t.GetInterfaceMap(i);42          Console.WriteLine("  Interface '{0}' is implemented by class '{1}'", map.InterfaceType, map.TargetType);43 44          for (Int32 m = 0; m < map.InterfaceMethods.Length; m++) {45             // Display the interface method name and which type method implements the interface method.46             Console.WriteLine("    {0} is implemented by {1}",47                map.InterfaceMethods[m], map.TargetMethods[m]);48          }49       }50    }51 52    // Returns true if type matches filter criteria53    private static Boolean TypeFilter(Type t, Object filterCriteria) {54       // Return true if the interface is defined in the same assembly identified by filterCriteria55       return t.Assembly == (Assembly)filterCriteria;56    }57 }

结果:

 23.5.4 调用类型的成员

发现类型成员后,你可能想调用其中一个成员。”调用“(invoke)的含义取决于调用成员的种类。如下表所示:

成员类型

用于调用成员的方法

FieldInfo

调用GetValue获取字段的值

调用SetValue设置字段的值

PropertyInfo

调用GetValue调用属性的get访问器方法

调用SetValue调用属性的set访问器方法

EventInfo

调用AddEventHandler调用事件的add访问器方法

调用RemoveEventHandler调用事件的remove访问器方法

ConstructorInfo

调用Invoke构造类型的一个实例,并调用一个构造器

MethodInfo

调用Invoke调用类型的一个方法

Type  InvokeMember() 实例方法,可通过它调用一个成员。 该方法会执行两个操作:

1)绑定成员:选择要调用的一个恰当的成员

2)调用:实际调用成员

23.5.5 一次绑定,多次调用

Type的InvokeMember实例方法,通过内在的绑定和调用两步操作实现成员的调用。为了提高性能,可以实现一次绑定,多次调用。 看如下代码:

View Code
1 using System;  2 using System.Reflection;  3 using Microsoft.CSharp.RuntimeBinder;  4   5 internal static class Invoker {  6    // This class is used to demonstrate reflection  7    // It has a field, constructor, method, property, and an event  8    private sealed class SomeType {  9       private Int32 m_someField; 10       public SomeType(ref Int32 x) { x *= 2; } 11       public override String ToString() { return m_someField.ToString(); } 12       public Int32 SomeProp { 13          get { return m_someField; } 14          set { 15             if (value < 1) throw new ArgumentOutOfRangeException("value", "value must be > 0"); 16             m_someField = value; 17          } 18       } 19       public event EventHandler SomeEvent; 20       private void NoCompilerWarnings() { 21          SomeEvent.ToString(); 22       } 23    } 24  25    private const BindingFlags c_bf = BindingFlags.DeclaredOnly | BindingFlags.Public | 26       BindingFlags.NonPublic | BindingFlags.Instance; 27  28    public static void Go() { 29       Type t = typeof(SomeType); 30        //演示如何利用Type的InvokeMember来绑定并调用一个成员 31       UseInvokeMemberToBindAndInvokeTheMember(t); 32       Console.WriteLine(); 33        //演示绑定到一个成员然后调用它。适用于一次绑定,多次调用 34       BindToMemberThenInvokeTheMember(t); 35       Console.WriteLine(); 36        //演示绑定到一个成员,然后创建一个委托来引用该成员,通过委托调用之。速度比上一个更快 37       BindToMemberCreateDelegateToMemberThenInvokeTheMember(t); 38       Console.WriteLine(); 39        //演示使用C#的dynamic基本类型来简化访问成员时使用语法。 40       UseDynamicToBindAndInvokeTheMember(t); 41       Console.WriteLine(); 42    } 43  44    private static void UseInvokeMemberToBindAndInvokeTheMember(Type t) { 45       Console.WriteLine("UseInvokeMemberToBindAndInvokeTheMember"); 46  47       // Construct an instance of the Type 48       Object[] args = new Object[] { 12 };  // Constructor arguments 49       Console.WriteLine("x before constructor called: " + args[0]); 50       Object obj = t.InvokeMember(null, c_bf | BindingFlags.CreateInstance, null, null, args); 51       Console.WriteLine("Type: " + obj.GetType().ToString()); 52       Console.WriteLine("x after constructor returns: " + args[0]); 53  54       // Read and write to a field 55       t.InvokeMember("m_someField", c_bf | BindingFlags.SetField, null, obj, new Object[] { 5 }); 56       Int32 v = (Int32)t.InvokeMember("m_someField", c_bf | BindingFlags.GetField, null, obj, null); 57       Console.WriteLine("someField: " + v); 58  59       // Call a method 60       String s = (String)t.InvokeMember("ToString", c_bf | BindingFlags.InvokeMethod, null, obj, null); 61       Console.WriteLine("ToString: " + s); 62  63       // Read and write a property 64       try { 65          t.InvokeMember("SomeProp", c_bf | BindingFlags.SetProperty, null, obj, new Object[] { 0 }); 66       } 67       catch (TargetInvocationException e) { 68          if (e.InnerException.GetType() != typeof(ArgumentOutOfRangeException)) throw; 69          Console.WriteLine("Property set catch."); 70       } 71       t.InvokeMember("SomeProp", c_bf | BindingFlags.SetProperty, null, obj, new Object[] { 2 }); 72       v = (Int32)t.InvokeMember("SomeProp", c_bf | BindingFlags.GetProperty, null, obj, null); 73       Console.WriteLine("SomeProp: " + v); 74  75       // Add and remove a delegate from the event by invoking the event抯 add/remove methods 76       EventHandler eh = new EventHandler(EventCallback); 77       t.InvokeMember("add_SomeEvent", c_bf | BindingFlags.InvokeMethod, null, obj, new Object[] { eh }); 78       t.InvokeMember("remove_SomeEvent", c_bf | BindingFlags.InvokeMethod, null, obj, new Object[] { eh }); 79    } 80  81    private static void BindToMemberThenInvokeTheMember(Type t) { 82       Console.WriteLine("BindToMemberThenInvokeTheMember"); 83  84       // Construct an instance 85       // ConstructorInfo ctor = t.GetConstructor(new Type[] { Type.GetType("System.Int32&") }); 86       ConstructorInfo ctor = t.GetConstructor(new Type[] { typeof(Int32).MakeByRefType() }); 87       Object[] args = new Object[] { 12 };  // Constructor arguments 88       Console.WriteLine("x before constructor called: " + args[0]); 89       Object obj = ctor.Invoke(args); 90       Console.WriteLine("Type: " + obj.GetType().ToString()); 91       Console.WriteLine("x after constructor returns: " + args[0]); 92  93       // Read and write to a field 94       FieldInfo fi = obj.GetType().GetField("m_someField", c_bf); 95       fi.SetValue(obj, 33); 96       Console.WriteLine("someField: " + fi.GetValue(obj)); 97  98       // Call a method 99       MethodInfo mi = obj.GetType().GetMethod("ToString", c_bf);100       String s = (String)mi.Invoke(obj, null);101       Console.WriteLine("ToString: " + s);102 103       // Read and write a property104       PropertyInfo pi = obj.GetType().GetProperty("SomeProp", typeof(Int32));105       try {106          pi.SetValue(obj, 0, null);107       }108       catch (TargetInvocationException e) {109          if (e.InnerException.GetType() != typeof(ArgumentOutOfRangeException)) throw;110          Console.WriteLine("Property set catch.");111       }112       pi.SetValue(obj, 2, null);113       Console.WriteLine("SomeProp: " + pi.GetValue(obj, null));114 115       // Add and remove a delegate from the event116       EventInfo ei = obj.GetType().GetEvent("SomeEvent", c_bf);117       EventHandler eh = new EventHandler(EventCallback); // See ei.EventHandlerType118       ei.AddEventHandler(obj, eh);119       ei.RemoveEventHandler(obj, eh);120    }121 122    private static void BindToMemberCreateDelegateToMemberThenInvokeTheMember(Type t) {123       Console.WriteLine("BindToMemberCreateDelegateToMemberThenInvokeTheMember");124 125       // Construct an instance (You can't create a delegate to a constructor)126       Object[] args = new Object[] { 12 };  // Constructor arguments127       Console.WriteLine("x before constructor called: " + args[0]);128       Object obj = Activator.CreateInstance(t, args);129       Console.WriteLine("Type: " + obj.GetType().ToString());130       Console.WriteLine("x after constructor returns: " + args[0]);131 132       // NOTE: You can't create a delegate to a field133 134       // Call a method135       MethodInfo mi = obj.GetType().GetMethod("ToString", c_bf);136       var toString = (Func
) Delegate.CreateDelegate(typeof(Func
), obj, mi);137 String s = toString();138 Console.WriteLine("ToString: " + s);139 140 // Read and write a property141 PropertyInfo pi = obj.GetType().GetProperty("SomeProp", typeof(Int32));142 var setSomeProp = (Action
)Delegate.CreateDelegate(typeof(Action
), obj, pi.GetSetMethod());143 try {144 setSomeProp(0);145 }146 catch (ArgumentOutOfRangeException) {147 Console.WriteLine("Property set catch.");148 }149 setSomeProp(2);150 var getSomeProp = (Func
)Delegate.CreateDelegate(typeof(Func
), obj, pi.GetGetMethod());151 Console.WriteLine("SomeProp: " + getSomeProp());152 153 // Add and remove a delegate from the event154 EventInfo ei = obj.GetType().GetEvent("SomeEvent", c_bf);155 var addSomeEvent = (Action
)Delegate.CreateDelegate(typeof(Action
), obj, ei.GetAddMethod());156 addSomeEvent(EventCallback);157 var removeSomeEvent = (Action
)Delegate.CreateDelegate(typeof(Action
), obj, ei.GetRemoveMethod());158 removeSomeEvent(EventCallback); 159 }160 161 private static void UseDynamicToBindAndInvokeTheMember(Type t) {162 Console.WriteLine("UseDynamicToBindAndInvokeTheMember");163 164 // Construct an instance (You can't create a delegate to a constructor)165 Object[] args = new Object[] { 12 }; // Constructor arguments166 Console.WriteLine("x before constructor called: " + args[0]);167 dynamic obj = Activator.CreateInstance(t, args);168 Console.WriteLine("Type: " + obj.GetType().ToString());169 Console.WriteLine("x after constructor returns: " + args[0]);170 171 // Read and write to a field 172 try {173 obj.m_someField = 5;174 Int32 v = (Int32)obj.m_someField;175 Console.WriteLine("someField: " + v);176 }177 catch (RuntimeBinderException e) {178 // We get here because the field is private179 Console.WriteLine("Failed to access field: " + e.Message);180 }181 182 // Call a method183 String s = (String)obj.ToString();184 Console.WriteLine("ToString: " + s);185 186 // Read and write a property187 try {188 obj.SomeProp = 0;189 }190 catch (ArgumentOutOfRangeException) {191 Console.WriteLine("Property set catch.");192 }193 obj.SomeProp = 2;194 Int32 val = (Int32)obj.SomeProp;195 Console.WriteLine("SomeProp: " + val);196 197 // Add and remove a delegate from the event198 obj.SomeEvent += new EventHandler(EventCallback);199 obj.SomeEvent -= new EventHandler(EventCallback);200 }201 202 // Callback method added to the event203 private static void EventCallback(Object sender, EventArgs e) { }204 }

 

 

 

 

转载于:https://www.cnblogs.com/Ming8006/archive/2013/04/06/3002913.html

你可能感兴趣的文章
大数据计数原理1+0=1这你都不会算(一)
查看>>
艾普联手OPENSTACK 打造公众云
查看>>
从线上卖到线下,秘籍在这里|千牛头条双11直播
查看>>
李飞飞:为什么计算机视觉对机器人如此重要?
查看>>
数据的价值 删除无用数据可降低风险
查看>>
2017年五大关键云趋势:容器、AI等
查看>>
JedisPool资源池优化
查看>>
数据库安全专家指出数据库取证仍然落后
查看>>
5G新规范:个人网络速度不低于下行100兆 上行50兆
查看>>
TensorFlow博客翻译——DeepMind转向TensorFlow
查看>>
信息化治理与北京治堵:疏图同归
查看>>
专访Dan Kohn:阡陌交迭,云原生布局开源生态构建及深度应用
查看>>
在Linux中添加普通新用户
查看>>
beego小技巧两则:通过命令行自定义端口和环境,url中带有中划线处理
查看>>
跨国引入强势技术 安全行业又添生力军
查看>>
吸烟损害健康,电子烟损害电脑,分分钟让电脑变砖
查看>>
市场井喷 到家服务将颠覆在线教育模式
查看>>
阿里云发布高IO实例 存储性能比通用型提升300%
查看>>
专访声网CEO赵斌:实时互联网正深入影响垂直领域
查看>>
中国人工智能学会通讯——新一轮人工智能发展的三大特征及其展望 1.1 新一轮人工智能发展的三个特征...
查看>>