首页 > 代码库 > 通过反射动态创建对象、方法

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

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

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了。编译器在运行前根本不知道去执行哪个方法,称为迟绑定。

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