• C# 反射 (Reflect)


    C# 反射 (Reflect)


    1.基本内容

    我们可以使用反射动态地创建类型的实例,将类型绑定到现有对象,或从现有对象中获取类型。然后,可以调用类型的方法或访问其字段和属性。

    最基本的调用:

    Assembly assembly = Assembly.Load("DB.SqlServer");//将加载dll 
    Type type = assembly.GetType("DB.SqlServer.SqlServerHelper");//得到DLL 中的SqlServerHelper 类
    object obj = Activator.CreateInstance(type);//创建类的实例
    SqlServerHelper helper = (SqlServerHelper)obj;//将创建的Object 对象转换为SqlServerHelper对象
    helper.Query();//调用对象的方法
    

    2.创建对象

    工厂方法

    反射的一个应用场景是,当我们开发的程序的数据库是可能变化时,就会用到反射,入下述代码:

    //这是一个DB接口层
    namespace DB.Interface
    {
        public interface IDBHelper
        {
            void Query();
        }
    }
    
    
    //这是SqlServer数据库的操作层
    namespace DB.SqlServer
    {
        public class SqlServerHelper : IDBHelper//继承自DB接口层
        {
            public void Query()
            {
                Console.WriteLine("我是{0}", typeof(SqlServerHelper));
            }
        }
    }
    
    //这是MySql数据库的操作层
    namespace DB.MySql
    {
        public class MySqlHelper : IDBHelper//继承自DB接口层
        {
            public void Query()
            {
                Console.WriteLine("我是{0}", typeof(MySqlHelper));
            }
        }
    }
    

    然后我们会建造一个工厂类,专门用于生产对象:

    //这是工厂层
    public class Factory
    {
        static string IDBHelperConfig = System.Configuration.ConfigurationManager.AppSettings["IDBHelperConfig"];
        static string DllName = IDBHelperConfig.Split(',')[0];
        static string TypeName = IDBHelperConfig.Split(',')[1];
        public static IDBHelper CreateDBHelper()
        {
            Assembly assembly = Assembly.Load(DllName);//将加载dll 
            Type type = assembly.GetType(TypeName);//得到DLL 中的SqlServerHelper 类
            object obj = Activator.CreateInstance(type);//创建类的实例
            return (IDBHelper)obj;//将创建的Object 对象转换为IDBHelper对象 并返回
        }
    }
    

    然后在app.config 文件中添加配置:

    <appSettings>
        <!--这是配置字符串-->
        <add key="IDBHelperConfig" value="DB.SqlServer,DB.SqlServer.SqlServerHelper"/>
    </appSettings>
    

    最后在调用层面调用:

    //这是调用
    IDBHelper dbHelper = Factory.CreateDBHelper();
    dbHelper.Query();
    

    这样当数据库从SqlServer 修改为 MySql 时,我们只需要修改app.config中的配置字符串即可,而不需要修改源代码,这样有利于我们程序的维护,与稳定。

    带参数对象创建

    基础类

    namespace Model
    {
        public class Person
        {
            public int Id { get; set; }
            public string Name { get; set; }
            public DateTime CreateDate { get; set; }
            public Person(int id)
            {
                Console.WriteLine("我是有1个参数的构造函数!");
                this.Id = id;
            }
            public Person(int id, string name)
            {
                Console.WriteLine("我是有2个参数的构造函数!");
                this.Id = id;
                this.Name = name;
            }
            public Person(int id, string name, DateTime createDate)
            {
                Console.WriteLine("我是有3个参数的构造函数!");
                this.Id = id;
                this.Name = name;
                this.CreateDate = createDate;
            }
            private Person()
            {
                Console.WriteLine("我是私有的,无参数构造函数");
            }
        }
    }
    

    有参数的构造函数调用方式:

    Assembly assembly = Assembly.Load("Model");
    Type personType = assembly.GetType("Model.Person");
    //调用带1个参数的构造函数
    object obj = Activator.CreateInstance(personType, new object[] { 123 });
    //调用带2个参数的构造函数
    object obj2 = Activator.CreateInstance(personType, new object[] { 123, "Oliver" });
    //调用带3个参数的构造函数
    object obj3 = Activator.CreateInstance(personType, new object[] { 123, "Oliver", DateTime.Now });
    

    调用私有构造函数

    Assembly assembly = Assembly.Load("Model");
    Type personType = assembly.GetType("Model.Person");
    //调用私有函数
    object obj4 = Activator.CreateInstance(personType,true);
    

    泛型类创建

    基础类

    namespace Model
    {
        //添加泛型类
        public class GenericClass<T>
        {
            public GenericClass()
            {
                Console.WriteLine("我是泛型类的构造函数!");
            }
    
            public T GetT()
            {
                return default(T);
            }
        }
    }
    

    通过反射的方法创建泛型对象

    Assembly assembly = Assembly.Load("Model");
    Type gennericClassType = assembly.GetType("Model.GenericClass`1");//如果是一个泛型需要在后面添加`1,否则取出来的时NULL
    Type newGennericClassType = gennericClassType.MakeGenericType(new Type[] { typeof(int) });
    var obj = Activator.CreateInstance(newGennericClassType);
    

    注意反射泛型类的时候GetType方法传入的类名称,需要在后面添加相应的泛型个数。下面这句代码也相应的说明这个情况。

    //输出的值也会有一个`1
    Console.WriteLine(typeof(GenericClass<int>));//输出:Model.GenericClass`1[System.Int32]
    

    3.调用方法

    基础类

    namespace Model
    {
        public class Person
        {
            public int Id { get; set; }
            public string Name { get; set; }
            public DateTime CreateDate { get; set; }
            public string Memo;//字段
            public Person(int id)
            {
                Console.WriteLine("我是有1个参数的构造函数!");
                this.Id = id;
            }
            public Person(int id, string name)
            {
                Console.WriteLine("我是有2个参数的构造函数!");
                this.Id = id;
                this.Name = name;
            }
            public Person(int id, string name, DateTime createDate)
            {
                Console.WriteLine("我是有3个参数的构造函数!");
                this.Id = id;
                this.Name = name;
                this.CreateDate = createDate;
            }
    
            private Person()
            {
                Console.WriteLine("我是私有的,无参数构造函数");
            }
    
            //带有返回值的无参方法
            public DateTime Show()
            {
                Console.WriteLine("我是带有返回值的无参方法。");
                return DateTime.Now;
            }
    
            //带有参数的方法
            public void Show2(int i)
            {
                Console.WriteLine("我是Show2(int i).i=" + i);
            }
    
            //重载方法
            public void Show3(int i)
            {
                Console.WriteLine("我是Show3(int i).i=" + i);
            }
            //重载方法
            public void Show3(string s)
            {
                Console.WriteLine("我是Show3(string s).s=" + s);
            }
    
            //私有方法
            private void Show4()
            {
                Console.WriteLine("我是私有方法");
            }
    
            //静态方法
            public static void Show5()
            {
                Console.WriteLine("我是静态方法");
            }
        }
    }
    

    无参方法

    Assembly assembly = Assembly.Load("Model");//加载dll
    Type personType = assembly.GetType("Model.Person");//得到类
    object objPerson = Activator.CreateInstance(personType, true);//创建对象
    //调用 有返回值 无参数的方法
    MethodInfo show = personType.GetMethod("Show");//找到方法
    DateTime dt = (DateTime)(show.Invoke(objPerson, new object[] { }));//调用,并接收返回值
    

    带参数方法

    //调用 带有参数的方法
    MethodInfo show2 = personType.GetMethod("Show2");
    show2.Invoke(objPerson, new object[] { 123 });
    

    重载方法

    //调用 重载方法1
    MethodInfo show3 = personType.GetMethod("Show3", new Type[] { typeof(int) });
    show3.Invoke(objPerson, new object[] { 234 });
    
    //调用 重载方法2
    MethodInfo show3_1 = personType.GetMethod("Show3", new Type[] { typeof(string) });
    show3_1.Invoke(objPerson, new object[] { "ABC" });
    

    私有方法

    //调用私有方法
    MethodInfo show4 = personType.GetMethod("Show4", BindingFlags.Instance | BindingFlags.NonPublic);
    show4.Invoke(objPerson, new object[] { });
    

    静态方法(两种形式)

    //调用静态方法
    MethodInfo show5 = personType.GetMethod("Show5");
    show5.Invoke(objPerson, new object[] { });//类似于 实例调用
    show5.Invoke(null, new object[] { });//类似于直接通过类名称调用
    

    调用泛型类的泛型方法

    基础类

    namespace Model
    {
        //添加泛型类
        public class GenericClass<T>
        {
            public GenericClass()
            {
                Console.WriteLine("我是泛型类的构造函数!");
            }
    
    
            public T GetT<S>(T t, S s)
            {
                Console.WriteLine("我是泛型类中的泛型方法!t_type:{0}, t_value:{1}	s_type:{2}, s_value:{3}", typeof(T), t, typeof(S), s);
                return t;
            }
        }
    }
    

    调用GenericClass类的GetT方法

    Assembly assembly = Assembly.Load("Model");
    Type genericClassType = assembly.GetType("Model.GenericClass`1");//`1 千万别忘记
    Type newGenericClassType = genericClassType.MakeGenericType(new Type[] { typeof(int) });
    object obj= Activator.CreateInstance(newGenericClassType);//创建对象
    MethodInfo methodInfo = newGenericClassType.GetMethod("GetT");
    MethodInfo newMethodInfo = methodInfo.MakeGenericMethod(new Type[] {  typeof(string) });
    newMethodInfo.Invoke(obj, new object[] { 123, "Oliver" });//输出:我是泛型类中的泛型方法!t_type:System.Int32, t_value:123       s_type:System.String, s_value:Oliver
    

    4.get set 属性、字段

    属性操作

    Person p = new Person(1, "Oliver", DateTime.Now);
    Type t = p.GetType();
    PropertyInfo propertyInfo = t.GetProperty("Id");
    Console.WriteLine(propertyInfo.GetValue(p));//获取 属性的值。输出 1
    propertyInfo.SetValue(p,123);//获取 属性的值
    Console.WriteLine(propertyInfo.GetValue(p));//设置 属性的值。输出 123
    
    //遍历属性
    foreach (var prop in t.GetProperties())
    {
        Console.WriteLine("{0}.{1}={2}", typeof(Person), propertyInfo.Name, prop.GetValue(p));
        /*输出:
            Model.Person.Id=123
            Model.Person.Id=Oliver
            Model.Person.Id=2018/8/8 22:15:09
         */
    }
    

    字段操作

    Person p = new Person(1, "Oliver", DateTime.Now);
    Type t = p.GetType();
    FieldInfo fieldInfo = t.GetField("Memo");
    Console.WriteLine(fieldInfo.GetValue(p));//获取 属性的值。输出 空字符串
    fieldInfo.SetValue(p, "自律给我自由");//获取 属性的值
    Console.WriteLine(fieldInfo.GetValue(p));//设置 属性的值。输出 自律给我自由
    
  • 相关阅读:
    线程中断总结
    线程的基本协作和生产者消费者
    synchronized总结
    线程基础总结
    Java集合总结(三):堆与优先级队列
    Java集合总结(二):Map和Set
    Java集合总结(一):列表和队列
    java枚举类型总结
    java 内部类简单总结
    java Integer包装类装箱的一个细节
  • 原文地址:https://www.cnblogs.com/haowuji/p/9446118.html
Copyright © 2020-2023  润新知