• 通过反射动态创建对象、方法


    之前做的都是获取特性对象,都是查元数据的信息,现在我们可以通过反射开始动态的去创建对象和方法

    1.两种调用无参构造函数的方法:

    创建一个DemoClass,里面有无参构造函数和有参构造函数

     public class DemoClass
        {
            public string Name { get; set; }
    
            public  int Age { get; set; }
    
            public DemoClass()
            {
                Console.WriteLine("无参构造函数被调用啦");
            }
    
            public DemoClass(string name,int age)
            {
                this.Name = name;
                this.Age = age;
                Console.WriteLine("有参构造函数被调用了");
            }
        }

    (1)通过Assembly无参构造函数创建对象

    Assembly assembly= Assembly.GetExecutingAssembly();
    object o =assembly.CreateInstance("使用构造函数创建对象.DemoClass");
    CreateInstance方法的第一个参数代表了要创建的类型实例的字符串名称(命名空间+类名)。注意到CreateInstance方法返回的是一个Object对象,如果使用还要强制转换一下。
    (2)通过用Activator创建对象
    object o2 = Activator.CreateInstance(null, "使用构造函数创建对象.DemoClass");

    其中CreateInstance的第一个参数是程序集的名称,为null时表示当前程序集;第二个参数是要创建的类型名称。Activator.CreateInstance返回的是一个ObjectHandle对象,必须执行一次Unwrap()才能返回Object类型,进而可以强制转换成其实际类型。ObjectHandle包含在System.Runtime.Remoting命名空间中,可见它是Remoting相关的,实际上ObjectHandle类只是一个对原类型进行了一个包装以便进行封送
    运行结果如下:

    3.调用带参构造函数创建对象

    使用Assembly的createInstance函数进行对象的创建

     public class Program
        {
            static void Main(string[] args)
            {
               Assembly assembly= Assembly.GetExecutingAssembly();
                object[]paramers=new object[2];//创建参数数组,以便传入
                paramers[0] = ".net";
                paramers[1] = 14;
                object o =assembly.CreateInstance("使用构造函数创建对象.DemoClass",true,BindingFlags.Default,null,paramers,null,null);
                DemoClass demo = (DemoClass)o;
                Console.WriteLine("输出对象的信息:Name"+demo.Name+"     Age"+demo.Age);
                Console.ReadKey();
            }
        }

    BindingFlags.Default不使用任何类型搜索策略。执行结果:

    4.动态调用方法

    在上面的DemoClass中添加两个方法

            public int Add(int x, int y)
            {
                Console.WriteLine("实例方法被调用");
                return x + y;
            }
    
            public static void Add(double x, double y)
            {
                Console.WriteLine("静态函数被调用");
            }

    (1)Type.InvokeMember调用实例方法

       public class Program
        {
            static void Main(string[] args)
            {
                Type t = typeof(DemoClass);
                DemoClass demo=new DemoClass();
                object[]parameters={1,2};
                object result=t.InvokeMember("Add", BindingFlags.InvokeMethod, null, demo, parameters);
                Console.WriteLine("调用实例方法返回的结果:"+result);
                Console.ReadKey();
            }
        }

    第一个参数是指要调用的方法名,第二个参数是要调用方法,第三个Bingder几乎永远传null,第四个是指要在哪个实例上操作,咱们新建的对象demo,最后一个参数是方法的传入参数。InvokeMember方法被调用后返回执行结果。

    (2)使用Type.InvokeMember调用静态方法

        public class Program
        {
            static void Main(string[] args)
            {
                Type t = typeof(DemoClass);
                object[]parameters={1.0,2.0};
                object result=t.InvokeMember("Add", BindingFlags.InvokeMethod, null, t, parameters);
                Console.ReadKey();
            }
        }

    调用静态方法时与调实例方法差别在第四个参数上,调静态方法只需要传递类型就可以。

    5.使用MethodInfo.Invoke调用方法

    先获取一个MethodInfo实例,然后调用该实例的Invoke方法

    (1)调用实例方法

        public class Program
        {
            private static void Main(string[] args)
            {
                Type t = typeof(DemoClass);
                object[] parameters = { 1, 2 };
                DemoClass demo = new DemoClass();
                MethodInfo info = t.GetMethod("Add", BindingFlags.Instance | BindingFlags.Public);
                info.Invoke(demo, parameters);
                Console.ReadKey();
            }
        }

    因为方法中存在多个“Add”方法,所以在GetMethod中加BindingFlags中是必要的,Invoke方法第一个参数是要在那个实例上调用该方法,第二个参数时参数列表。Invoke返回方法执行结果。

    (2)调用静态方法

        public class Program
        {
            private static void Main(string[] args)
            {
                Type t = typeof(DemoClass);
                object[] parameters = { 1, 2 };
                MethodInfo info = t.GetMethod("Add", BindingFlags.Static | BindingFlags.Public);
                info.Invoke(null, parameters);
                Console.ReadKey();
            }
        }

    调用静态方法与实例方法的区别在于在用BingdingFlags进行搜索时要指定搜索Static,另外Invoke的时候不需要再传入类型的实例了。

    6.迟绑定

    在我们项目中,各个插件实现了同一个插件接口,再运行时动态的去加载哪个插件,如果不使用反射动态调用的情况下,只能去写多个if else了。编译器在运行前根本不知道去执行哪个方法,称为迟绑定。

  • 相关阅读:
    C++指针
    Linux Ubuntu常用终端命令
    java-JDBC-Oracle数据库连接
    HDU 1890 区间反转
    Hdu-3487 Splay树,删除,添加,Lazy延迟标记操作
    UVa 10088
    UVa10025-The ? 1 ? 2 ? ... ? n = k problem
    UVa10023手动开大数平方算法
    UVa 10007
    点的双联通+二分图的判定(poj2942)
  • 原文地址:https://www.cnblogs.com/yanglaosan/p/6692505.html
Copyright © 2020-2023  润新知