zoukankan      html  css  js  c++  java
  • 反射手册笔记 3.使用对象

    本章是上一章的继续,再获取到对象类型后,接下来做的事情。

    第一部分 动态调用成员——调用方法,检索或更改属性,以及字段

        方法1:利用Info类调用类成员
           1.用MethodInfo类调用方法:
              object[] Invoke(object obj, Object[] parameters)
              其中,第1个参数obj,是对象的实例(静态方法相应参数为null);第2个参数parameters是要传递到方法中的参数数组;返回值为object类型,因此,要对结果进行强制类型转换。示例如下:
        public class MathClass
        {
            
    public int Multiply(int x, int y)
            {
                
    return x * y;
            }

            [STAThread]
            
    static void Main()
            {
                MathClass objMath 
    = new MathClass();
                
    object[] paramArray = { 45 };

                MethodInfo method 
    = objMath.GetType().GetMethod("Multiply");
                
                
    int result = (int)method.Invoke(objMath, paramArray);
            }
        }
    其中,objMath.GetType().GetMethod("Multiply")方法,默认搜索所有共有成员,可以使用其重载方法:
    objMath.GetType().GetMethod("Multiply", BindingFlag.NonPublic),从而获取非公有成员。

           2.用PropertyInfo类调用属性:
                GetValue(Object obj, object[] index)
                SetValue(Object obj, Object NewValue, object[] index)

                其中,index为索引器(静态设为null),obj为对象的实例(静态设为null),返回值同样为object类型。示例如下:
        public class Human
        {
            
    private string strName;

            
    private string Name
            {
                
    get { return strName; }
                
    set { strName = value; }
            }

            [STAThread]
            
    static void Main()
            {
                Human newHuman 
    = new Human();

                
    //得到私有属性Name类型对象
                PropertyInfo prop = newHuman.GetType().GetProperty("Name", BindingFlags.Instance | BindingFlags.NonPublic);

                
    //设置私有属性Name
                string param = "Jax.Bao";
                prop.SetValue(newHuman, param, 
    null);

                
    //获取私有属性Name
                Console.WriteLine(prop.GetValue(newHuman, null).ToString());
            }
        }

           3.用FieldInfo类调用字段:
                GetValue(Object obj)
                SetValue(Object obj, Object value)
               
    FieldInfo类使用同PropertyInfo,只是没有Index罢了。示例略。

        方法2:利用InvokeMember()方法调用类成员
           3个重载,最常用的如下:
            Object InvokeMember(
                
    string name,                    //要调用的对象名:可以是属性名/方法名/字段名
                BindingFlags invokeAttr,        //搜索成员的条件,以及如何处理第一个参数:
                                                //如BindingFlags.InvokeMethod表示第一个参数为方法名;
                                                                                                //BindingFlags.GetProperty或SetProperty表示第一个参数为属性名;
                                                //BindingFlags.SetField或
    GetField表示第一个参数为字段名;
                Binder binder,                  //一般设为null,则会使用默认的DefaultBinder,对提供的参数进行类型转换,从原类型转为目标类型
                Object target,                  //调用成员的类型的实例(静态成员为null)
                Object[] args                   //对方法而言,是方法参数数组;对字段/属性而言,获取时是null,设置时是NewValue
            );
          
           1.调用方法:
             MethodInfo类的Invoke()方法,不能直接处理重载方法,即无法判断使用哪个重载方法,而InvokeMember则可以自动找到匹配的重载方法。示例如下:
                Type mathType = typeof(System.Math);
                
    object[] paramArray = { 58 };

                
    int result = (int)mathType.InvokeMember("Max",
                                BindingFlags.Public 
    | BindingFlags.InvokeMethod | BindingFlags.Static,
                               
    nullnull, paramArray);

            当然,如果使用MethodInfo类的Invoke()方法处理重载方法,要辅助以SelectMethod()先找到对应的重载方法,然后才能调用。

           2.操纵属性
              得到属性用BindingFlags.GetProperty,同时参数数组为null;设置属性用BindingFlags.SetProperty,示例如下:
                Type humanType = typeof(Human);
                Human newHuman 
    = new Human();

                
    //设置私有属性Name
                object[] paramArray = { "Jax.Bao" };
                humanType.InvokeMember(
    "Name",
                                BindingFlags.NonPublic 
    | BindingFlags.Instance | BindingFlags.SetProperty, null, newHuman, paramArray);

                
    //得到私有属性Name类型对象
                string result = humanType.InvokeMember("get_Name",
                                BindingFlags.NonPublic 
    | BindingFlags.Instance | BindingFlags.InvokeMethod, null, newHuman, null);

              补注:
                在MSIL中属性其实就是方法,所以对属性的操纵也可以使用如下方式(以get为例):
                humanType.InvokeMember("get_Name",
                        BindingFlags.NonPublic 
    | BindingFlags.Instance | BindingFlags.InvokeMethod, null, newHuman, null);
                同理,可以使用MethodInfo.InvokeMethod()改写为:
                Human objHuman = new Human();
                Object[] paramArray 
    = { "Jax.Bao" };

                MethodInfo method 
    = objHuman.GetType().GetMethod("get_Name");

                
    string result = (string)method.Invoke(objHuman, paramArray);

           3.操纵字段
             基本上同于"操纵属性",不再多言。

        两种方法的比较:
          
    Type的InvokeMember()方法灵活且功能强大,应该优先使用;仅当需要处理元数据时,才使用info类。


    第二部分 用反射模拟委托功能
        之所以要模拟,是因为委托时类型安全的(编译期)——区别于反射(运行期),所以小型程序要尽量使用委托。
        委托不区分静态方法/实例方法——区别于反射。

        模拟代码如下:
        public class Invoker
        {
            
    private Type myType;
            
    private Object myObject;
            
    private String myMethod;


            
    public Invoker(Type targetType, String targetMethod)
            {
                myType 
    = targetType;
                myMethod 
    = targetMethod;
            }

            
    public Invoker(Object targetObject, String targetMethod)
            {
                myObject 
    = targetObject;
                myType 
    = targetObject.GetType();
                myMethod 
    = targetMethod;
            }

            
    public Object Invoke(Object[] args)
            {
                
    if (myType != null && myMethod != null)
                {
                    BindingFlags myBindingFlags 
    = BindingFlags.InvokeMethod | BindingFlags.Public;

                    
    if (myObject != null)
                    {
                        myBindingFlags 
    = myBindingFlags | BindingFlags.Static;
                    }
                    
    else
                    {
                        myBindingFlags 
    = myBindingFlags | BindingFlags.Instance;
                    }

                    
    return myType.InvokeMember(myMethod, myBindingFlags, null, myObject, args);
                }
                
    else
                {
                    
    throw new Exception("Valid");
                }
            }

        }

        
    public class MyMath
        {
            
    public static int Pow(int x, int y)
            { 
                
    return x ^ y;
            }

            
    public int Multiply(int x, int y)
            {
                
    return x * y;
            }

            
    static void Main()
            {
                
    try
                {
                    Object result;
                    Object[] args 
    = { 23 };
                    MyMath objMath 
    = new MyMath();

                    Invoker myDelegate 
    = new Invoker(objMath, "Multiply");
                    result 
    = myDelegate.Invoke(args);
                    Console.WriteLine(
    "The product of {0} and {1} is: {2}", args[0], args[1], result);

                    Invoker objDelegate 
    = new Invoker(typeof(MyMath), "Pow");
                    result 
    = objDelegate.Invoke(args);
                    Console.WriteLine(
    "The product of {0} and {1} is: {2}", args[0], args[1], result);
                }
                
    catch
                {
                    
    throw;
                }
            }

        }

        在模拟中,委托可以使用委托链实现"反射"重载方法。



  • 相关阅读:
    LeetCode. 476. Number Complement
    LeetCode 172.Factorial Trailing Zeroes
    原码,反码,补码笔记
    python3笔记
    django笔记(python web框架)
    mysql 8.0 主从复制配置
    centos 7系统安装mysql 8.0
    MobaXterm无法退格删除
    Oracle数据泵常用命令
    oracle查年度周末日期
  • 原文地址:https://www.cnblogs.com/Jax/p/877043.html
Copyright © 2011-2022 走看看