zoukankan      html  css  js  c++  java
  • CLR 学习笔记:程序集加载和反射(3)

           在获取一个Type之后,这个类型的成员可能包含字段,构造器,方法,属性,事件和嵌套类型。接下来就看说下如何查询一个类型的成员。

       1.发现类型的成员

       上一章提到了System.Reflection.MemberInfo类型,这是一个抽象基类,而我们的类型成员是从MemberInfo派生的一组类。具体的层次结构如下。

       

          可以调用GetMembers方法,传入BindingFlags参数,然后返回由MemberInfo派生对象构成的一个数组。

     1   Assembly assemblyFromPath = Assembly.LoadFile(@"E:StrongNameDLL.dll");
     2   const BindingFlags bf = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly;
     3   foreach (Type t in assemblyFromPath.GetExportedTypes())
     4   {
     5       foreach (MemberInfo mi in t.GetMembers(bf))
     6       {
     7           if (mi is FieldInfo)
     8           {
     9               //...
    10           }
    11           if (mi is MethodInfo)
    12           {
    13               //...
    14           }
    15       }
    16   }

            不仅如此,Type还提供了一些方法能够返回特定的成员类型,例如GetNestedTypes,GetFields, GetConstructors, GetMethods, GetProperties, GetEvents,返回的都是一个Info对象的数组;以及对应的GetNestedType,GetField,GetConstructor,GetMethod,GetProperty,GetEvent单数形式方法,返回Info对象。

        2.调用类型的成员

        Type类提供了一个InvokeMember方法,可通过它调用一个成员。  

    1 public object InvokeMember(string name, BindingFlags invokeAttr, Binder binder, object target, object[] args, CultureInfo culture)
    2 {
    3     //...
    4 }

            在内部,InvokeMember会执行两个操作。首先,它必须绑定要调用的成员;其次,必须调用成员。

        a.name参数传递一个String,指出希望绑定的成员的名称,而除了target参数,其他参数都是用于帮助InvokeMember方法确定要绑定的成员。

            b.BindingFlags标识了筛选种类以及具体操作。

            c.Binder封装了选在一个成员时的规则,例如BindToField, BindToMethod等。如果传入null,内部使用DefaultBinder对象。

            d.target参数是对想要调用其成员的一个对象的引用。如果要调用一个类型的静态成员,该参数应传递null值。

            e.args表示要传给方法的实参


            3.代码实现

        代码实现了几种不同的访问类型成员的方式,目的是希望大家体会到一次绑定,多次调用的好处。  

      1     class Program
      2     {
      3         private const BindingFlags c_bf = BindingFlags.DeclaredOnly | BindingFlags.Public| BindingFlags.NonPublic
      4             | BindingFlags.Instance;
      5 
      6         static void Main(string[] args)
      7         {
      8             Type t = typeof(SomeType);
      9             //利用Type的InvokeMember来绑定并调用一个成员
     10             UseInvokeMemberToBindAndInvokeTheMember(t);
     11             Console.WriteLine();
     12             //绑定成员,并在以后调用它
     13             BindToMemberThenInvokeTheMember(t);
     14             Console.WriteLine();
     15             //绑定一个对象或成员,然后创建委托来调用,速度快
     16             BindToMemberCreateDelegateToMemberThenInvokeTheMember(t);
     17             Console.WriteLine();
     18             //用dynamic基元类简化访问成员时的语法
     19             UseDynamicToBindAndInvokeTheMember(t);
     20             Console.WriteLine();
     21         }
     22 
     23         private static void UseInvokeMemberToBindAndInvokeTheMember(Type t)
     24         {
     25             Console.WriteLine("UseInvokeMemberToBindAndInvokeTheMember");
     26             //构造实例
     27             object[] args = new object[] { 12 };
     28             object obj = t.InvokeMember(null, c_bf | BindingFlags.CreateInstance, null, null, args);
     29             Console.WriteLine("Type:{0}, Value:{1}.", obj.GetType().ToString(), args[0]);
     30 
     31             //读写一个字段
     32             t.InvokeMember("m_someField", c_bf | BindingFlags.SetField, null, obj, new object[] { 5 });
     33             int field = (int)t.InvokeMember("m_someField", c_bf | BindingFlags.GetField, null, obj, null);
     34             Console.WriteLine("SomeField: " + field);
     35 
     36             //调用一个方法
     37             string toStringMethod = (string)t.InvokeMember("ToString", c_bf | BindingFlags.InvokeMethod, null, obj, null);
     38             Console.WriteLine("ToString: " + toStringMethod);
     39 
     40             //读写一个属性
     41             try
     42             {
     43                 t.InvokeMember("SomeProp", c_bf | BindingFlags.SetProperty, null, obj, new object[] { 0 });
     44             }
     45             catch (TargetInvocationException e)
     46             {
     47                 if (e.InnerException.GetType() != typeof(ArgumentOutOfRangeException)) throw;
     48                 Console.WriteLine("Property set catch");
     49             }
     50 
     51             t.InvokeMember("SomeProp", c_bf | BindingFlags.SetProperty, null, obj, new object[] { 2 });
     52             int property = (int)t.InvokeMember("SomeProp", c_bf | BindingFlags.GetProperty, null, obj, null);
     53             Console.WriteLine("SomeProp: " + property);
     54 
     55             //调用事件add/remove方法,为事件添加和删除一个委托
     56             EventHandler eh = new EventHandler(EventCallBack);
     57             t.InvokeMember("add_SomeEvent", c_bf | BindingFlags.InvokeMethod, null, obj, new object[] { eh });
     58             t.InvokeMember("remove_SomeEvent", c_bf | BindingFlags.InvokeMethod, null, obj, new object[] { eh });
     59         }
     60 
     61         private static void BindToMemberThenInvokeTheMember(Type t)
     62         {
     63             //构造一个实例
     64             ConstructorInfo ctor = t.GetConstructor(new Type[] { typeof(Int32).MakeByRefType() });
     65             //ConstructorInfo ctor = t.GetConstructor(new Type[] { Type.GetType("System.Int32&") });
     66             object[] args = new object[] { 12 };
     67             object obj = ctor.Invoke(args);
     68 
     69             //读写一个字段
     70             FieldInfo fi = obj.GetType().GetField("m_someField", c_bf);
     71             fi.SetValue(obj, 33);
     72             Console.WriteLine("SomeField: " + fi.GetValue(obj));
     73 
     74             //调用一个方法
     75             MethodInfo mi = obj.GetType().GetMethod("ToString", c_bf);
     76             string toString = (string)mi.Invoke(obj, null);
     77             Console.WriteLine("ToString: " + toString);
     78 
     79             //读写一个属性
     80             PropertyInfo pi = obj.GetType().GetProperty("SomeProp", typeof(Int32));
     81             try
     82             {
     83                 pi.SetValue(obj, 0, null);
     84             }
     85             catch (TargetInvocationException e)
     86             {
     87                 if (e.InnerException.GetType() != typeof(ArgumentOutOfRangeException)) throw;
     88                 Console.WriteLine("Property set catch");
     89             }
     90             pi.SetValue(obj, 2, null);
     91             Console.WriteLine("SomeProp: " + pi.GetValue(obj,null));
     92 
     93             //为事件添加删除一个委托
     94             EventInfo ei = obj.GetType().GetEvent("SomeEvent", c_bf);
     95             EventHandler eh = new EventHandler(EventCallBack);
     96             ei.AddEventHandler(obj,eh);
     97             ei.RemoveEventHandler(obj,eh);
     98         }
     99 
    100         private static void BindToMemberCreateDelegateToMemberThenInvokeTheMember(Type t)
    101         {
    102             //构造一个实例
    103             object[] args = new object[] { 12 };
    104             object obj = Activator.CreateInstance(t, args);
    105 
    106             //不能创建对一个字段的委托
    107 
    108             //调用一个方法
    109             MethodInfo mi = obj.GetType().GetMethod("ToString", c_bf);
    110             var toString = (Func<string>)Delegate.CreateDelegate(typeof(Func<string>), obj, mi);
    111             string s = toString();
    112             Console.WriteLine("ToString: " + s);
    113 
    114             //读写一个属性
    115             PropertyInfo pi = obj.GetType().GetProperty("SomeProp", c_bf);
    116             var setSomeProp = (Action<int>)Delegate.CreateDelegate(typeof(Action<int>), obj, pi.GetSetMethod());
    117             try
    118             {
    119                 setSomeProp(0);
    120             }
    121             catch (ArgumentOutOfRangeException e)
    122             {
    123                 Console.WriteLine("Property set catch");
    124             }
    125             setSomeProp(2);
    126             var getSomeProp = (Func<int>)Delegate.CreateDelegate(typeof(Func<int>), obj, pi.GetGetMethod());
    127             Console.WriteLine("SomeProp: " + getSomeProp);
    128 
    129             //从事件中添加删除一个委托
    130             EventInfo ei = obj.GetType().GetEvent("SomeEvent", c_bf);
    131             var addSomeEvent = (Action<EventHandler>)Delegate.CreateDelegate(typeof(Action<EventHandler>), obj, ei.GetAddMethod());
    132             addSomeEvent(EventCallBack);
    133             var removeSomeEvent = (Action<EventHandler>)Delegate.CreateDelegate(typeof(Action<EventHandler>), obj, ei.GetRemoveMethod());
    134             removeSomeEvent(EventCallBack);
    135         }
    136 
    137         private static void UseDynamicToBindAndInvokeTheMember(Type t)
    138         {
    139             //构造一个实例
    140             object[] args = new object[] { 12 };
    141             dynamic obj = Activator.CreateInstance(t, args);
    142 
    143             try
    144             {
    145                 obj.m_someField = 5;
    146                 int v = (int)obj.m_someField;
    147                 Console.WriteLine("someField: " + v);
    148             }
    149             catch (RuntimeBinderException e)
    150             {
    151                 //字段私有
    152                 Console.WriteLine("Failed to access field: " + e.Message);
    153             }
    154 
    155             //调用一个方法
    156             string toString = (string)obj.ToString();
    157             Console.WriteLine("ToString: " + toString);
    158 
    159             //读写一个属性
    160             try
    161             {
    162                 obj.SomeProp = 0;
    163             }
    164             catch (ArgumentOutOfRangeException e)
    165             {
    166                 Console.WriteLine("Property set catch");
    167             }
    168             obj.SomeProp = 2;
    169             int value = (int)obj.SomeProp;
    170             Console.WriteLine("SomeProp: " + value);
    171 
    172             //添加删除一个委托
    173             obj.SomeEvent += new EventHandler(EventCallBack);
    174             obj.SomeEvent -= new EventHandler(EventCallBack);
    175         }
    176 
    177         private static void EventCallBack(object sender, EventArgs e){ }
    178     }
    179 
    180     internal sealed class SomeType
    181     {
    182         private int m_someField;
    183         public SomeType(ref int x)
    184         {
    185             x *= 2;
    186         }
    187         public override string ToString()
    188         {
    189             return m_someField.ToString();
    190         }
    191         public int SomeProp
    192         {
    193             get { return m_someField; }
    194             set
    195             {
    196                 if (value < 1)
    197                 {
    198                     throw new ArgumentOutOfRangeException("value");
    199                 }
    200                 m_someField = value;
    201             }
    202         }
    203         public event EventHandler SomeEvent;
    204         private void NonCompilerWarning()
    205         {
    206             SomeEvent.ToString();
    207         }
    208     }

         4.使用绑定句柄减少内存耗用

         应用程序绑定一组类型或者类型成员到一个集合中,然后在某个时刻,应用程序会搜索这个集合,查找特定的对象,然后调用这个对象。这是个很好机制,只是有一个小问题:Type对象和MemberInfo派生对象需要大量的内存。如果应用程序容纳太多这样的对象,并且只是偶尔调用它们,那么内存耗用会很大,并对程序的性能产生影响。

         我们可以使用运行时句柄(runtime handles)来替代这些对象,从而减小占用的内存。FCL定义了3个运行时句柄类型:RuntimeTypeHandle, RuntimeFieldHandle和RuntimeMethodHandle。它们都是值类型,只包含一个IntPrt。Type或MemberInfo对象与运行时句柄之间的转换相当简单。下面通过具体代码演示。

     1     internal sealed class ExchangedDemo
     2     {
     3         private const BindingFlags c_bf = BindingFlags.FlattenHierarchy | BindingFlags.Public | BindingFlags.NonPublic |
     4              BindingFlags.Instance | BindingFlags.Static;
     5 
     6         public static void ShowExchangeMethod()
     7         {
     8             Show("Before doing anything.");
     9             List<MethodBase> methodInfos = new List<MethodBase>();
    10             foreach (Type t in typeof(Object).Assembly.GetExportedTypes())
    11             {
    12                 if (t.IsGenericTypeDefinition)
    13                 {
    14                     continue;
    15                 }
    16 
    17                 MethodBase[] mBase = t.GetMethods(c_bf);
    18                 methodInfos.AddRange(mBase);
    19             }
    20 
    21             Console.WriteLine("# of methods={0:###,###}",methodInfos.Count);
    22             Show("After building cache of MethodInfo objects");
    23 
    24             List<RuntimeMethodHandle> methodHandles = methodInfos.ConvertAll<RuntimeMethodHandle>(
    25                 mBase => mBase.MethodHandle);
    26             Show("Holding MethodInfo and RuntimeMethodHandl cache");
    27             GC.KeepAlive(methodInfos);
    28 
    29             methodInfos = null;
    30             Show("After freeing MethodInfo objects");
    31 
    32             methodInfos = methodHandles.ConvertAll<MethodBase>(rmh => MethodBase.GetMethodFromHandle(rmh));
    33             Show("Size of heap after re-creating MethodInfo objects");
    34 
    35             GC.KeepAlive(methodHandles);
    36             GC.KeepAlive(methodInfos);
    37 
    38             methodInfos = null;
    39             methodHandles = null;
    40             Show("After freeing MethodInfos and RuntimeMethodHandles");
    41         }
    42 
    43         private static void Show(string msg)
    44         {
    45             Console.WriteLine("Heap size = {0,12:##,###,###} - {1}",GC.GetTotalMemory(true),msg);
    46         }
    47     }
  • 相关阅读:
    Swap Nodes in Pairs
    Permutations(copy)
    Sort Colors
    Merge Two Sorted Lists
    Implement Queue using Stacks
    Best Time to Buy and Sell Stock
    Happy Number
    Gray Code
    springMVC初次搭建,产生错误
    JSP常用指令
  • 原文地址:https://www.cnblogs.com/ByronsHome/p/3526641.html
Copyright © 2011-2022 走看看