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     }
  • 相关阅读:
    1052 Linked List Sorting (25 分)
    1051 Pop Sequence (25 分)
    1050 String Subtraction (20 分)
    1049 Counting Ones (30 分)
    1048 Find Coins (25 分)
    1047 Student List for Course (25 分)
    1046 Shortest Distance (20 分)
    1045 Favorite Color Stripe (30 分)
    1044 Shopping in Mars (25 分)
    1055 The World's Richest (25 分)
  • 原文地址:https://www.cnblogs.com/ByronsHome/p/3526641.html
Copyright © 2011-2022 走看看