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=123Model.Person.Id=OliverModel.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));//设置 属性的值。输出 自律给我自由

转载于:https://www.cnblogs.com/haowuji/p/9446118.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/451695.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

jsp中的%@ ...%

主要用来提供整个JSP 网页相关的信息&#xff0c;并且用来设定JSP网页的相关属性

37--计算一个字符串中每个字符出现次数

1.问题描述 需求&#xff1a;计算一个字符串中每个字符出现次数。 2.解题思路 获取一个字符串对象&#xff1b;创建一个Map集合&#xff0c;键代表字符&#xff0c;值代表次数&#xff1b;遍历字符串得到每个字符&#xff1b;判断Map中是否有该键&#xff1b;如果没有&#…

oracle thin和oci 区别

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 Features of Oracle JDBC Drivers&#xff1a; 1.JDBC Oci 此驱动类似于传统的ODBC 驱动。因为它需要Oracle Call Interface and Net8&…

从拿到班车手册.xls到搜索附近班车地点

起因 七月份要去某厂报道了&#xff0c;异地租房的时候发现想租一个有公司班车的地方&#xff0c;却不知道哪里有班车。辗转流传出班车手册后发现搜索实在是太不方便了&#xff0c;于是有了一个主义&#xff0c;想做一个可以搜索房子地址&#xff0c;找出附近班车点&#xff08…

2018.08.09洛谷P3959 宝藏(随机化贪心)

传送门 回想起了自己赛场上乱搜的20分。 好吧现在也就是写了一个随机化贪心就水过去了&#xff0c;不得不说随机化贪心大法好。 代码&#xff1a; #include<bits/stdc.h> using namespace std; inline int read(){int ans0;char chgetchar();while(!isdigit(ch))chget…

AWT和Swing

AWT 是Abstract Window ToolKit (抽象窗口工具包)的缩写&#xff0c;这个工具包提供了一套与本地图形界面进行交互的接口。AWT 中的图形函数与操作系统所提供的图形函数之间有着一一对应的关系&#xff0c;我们把它称为peers。 也就是说&#xff0c;当我们利用 AWT 来构件图形用…

解决 : Apache Tomcat/8.0.0-RC1 - Error report ... HTTP Status 404

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 1.报错&#xff1a; Apache Tomcat/8.0.0-RC1 - Error report HTTP Status 404 - /richer/getOnLineRicherCount The requested resour…

py 5.24

#面向对象 #类&#xff1a;模子。Person&#xff0c;不具体。 #实例/对象&#xff1a;依托于类产生的具体的带有属性的。alex #实例化&#xff1a;产生对象的过程。 alex Person() #类&#xff1a; #分为静态属性&#xff08;一般的变量&#xff09;。动态属性(函数&#xff0…

多线程原理实例应用详解

从单进程单线程到多进程多线程是操作系统发展的一种必然趋势&#xff0c;当年的DOS系统属于单任务操作系统&#xff0c;最优秀的程序员也只能通过驻留内存的方式实现所谓的"多任务"&#xff0c;而如今的Win32操作系统却可以一边听音乐&#xff0c;一边编程&#xff0…

git中使用fork

在git中使用fork相当于你在原项目的主分支上又建立了一个分支&#xff0c;你可以在该分支上任意修改。如果想将你的修改合并到原项目中时&#xff0c;可以pull request&#xff0c;这样原项目的作者如果认同你的修改&#xff0c;就可以将你修改的东西合并到原项目的主分支上去。…

一、【Collection、泛型】

主要内容 Collection集合迭代器增强for泛型 教学目标 能够说出集合与数组的区别 说出Collection集合的常用功能 能够使用迭代器对集合进行取元素 能够说出集合的使用细节 能够使用集合存储自定义类型 能够使用foreach循环遍历集合 能够使用泛型定义集合对象 能够理解泛型上下…

字符装换

2019独角兽企业重金招聘Python工程师标准>>> 字母大小写转换 a →A char toUpperCase( char ch){ if((ch >a) && (ch <z)){ return (char)(ch - 32); // 主要 这里(char)是必要的&#xff0c;因为char -32是返回的数值&#xff0c;必须转换成对应的字…

解决 Unable to translate SQLException with Error code ‘17059‘, will now try the fallback translator

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 1.报错&#xff1a; Unable to translate SQLException with Error code 17059, will now try the fallback translator 报错如下&…

企业使用开源软件的风险

很多时候&#xff0c;我们过高地估计了开源软件面临的版权威胁&#xff0c;开源软件并非天生就比专有软件存在更多风险。虽然在企业中开源软件越来越普及&#xff0c;但开源软件始终难以摆脱知识产权带来的阴影。2007年&#xff0c;微软声称开源软件侵犯了它235项专利&#xff…

杭电多校 Harvest of Apples 莫队

问题 B: Harvest of Apples 时间限制: 1 Sec 内存限制: 128 MB 提交: 78 解决: 35 [提交] [状态] [讨论版] [命题人:admin] 题目描述 There are n apples on a tree, numbered from 1 to n. Count the number of ways to pick at most m apples. 输入 The first line of the …

linux和GNU之间的关系

Linux只是一个操作系统内核而已&#xff0c;而GNU提供了大量的自由软件来丰富在其之上各种应用程序。 因此&#xff0c;严格来讲&#xff0c;Linux这个词本身只表示Linux内核&#xff0c;但在实际上人们已经习惯了用Linux来形容整个基于Linux内核&#xff0c;并且使用GNU 工程各…

二、【List、Set、数据结构、Collections】

主要内容 数据结构List集合Set集合Collections 教学目标 能够说出List集合特点 能够说出常见的数据结构 能够说出数组结构特点 能够说出栈结构特点 能够说出队列结构特点 能够说出单向链表结构特点 能够说出Set集合的特点 能够说出哈希表的特点 使用HashSet集合存储自定义元素…

@Java | Thread synchronized - [ 线程同步锁 基本使用]

对实现了Runnable或者Callable接口类&#xff0c;可以通过多线程执行同一实例的run或call方法&#xff0c;那么对于同一实例中的局部变量&#xff08;非方法变量&#xff09;就会有多个线程进行更改或读取&#xff0c;这就会导致数据不一致&#xff0c;synchronized(关键字)可以…

解决bad SQL grammar []; nested exception is java.sql.SQLSyntaxErrorException: ORA-00911: 无效字符

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 1. 报错&#xff1a; ### Cause: java.sql.SQLSyntaxErrorException: ORA-00911: 无效字符; bad SQL grammar []; nested exception is …

开源代码的使用 二次开发

开源开发&#xff0c;就我的理解&#xff0c;有三种。 1、当作底层基础&#xff0c;使用。例如大家使用mysql就算。有人会认为我说错了。但我认为&#xff0c;开发不代表就是要同一个语言&#xff0c;甚至修改代码。例如我们使用动态库&#xff0c;原先的动态库是什么写的并不重…