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}\ts_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));//设置 属性的值。输出 自律给我自由
posted @ 2018-08-08 22:27  下-个路口  阅读(284)  评论(0编辑  收藏  举报