C#基础--反射

这篇具有很好参考价值的文章主要介绍了C#基础--反射。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

反射

一、为什么学习反射

因为反射真的是无处不在,ORM、MVC、IOC、AOP、Attribute等等都会使用到反射。反射是程序员的快乐

二、什么是反射

C#基础--反射,C# .Net,c#,asp.net,后端

Ilspy:逆向工程,可以吧DLL/Exe文件反编译回来

C#基础--反射,C# .Net,c#,asp.net,后端

DLL/EXE 文件下包含Metadata和IL,IL是对标于C#代码的代码,属于中间语言,是标准的面向对象语言

C#基础--反射,C# .Net,c#,asp.net,后端

而Metadata(元数据)是一个清单数据,只是描述了类中有什么,而不是展示所有的实现。一般我们用F12查看元数据,可以发现只有方法体没有声明:

C#基础--反射,C# .Net,c#,asp.net,后端

反射是一种工具,命名空间为System.Reflection,可以读取metadata,并使用metadata。(是微软提供的一个帮助类库)

三、Type类

3.1 简介

​ BCL声明了一个叫做Type的抽象类,它被设计用来包含类型的特性,使用这个类的对象能让我们获取程序使用的类型的信息。

​ 由于Type是抽象类,因此它不能有实例,而是在运行时CLR创建从Type(RuntimeType)派生的类的实例。Type包含了类型信息,当我们要访问这些实例时,CLR不会返回派生类的引用而是返回Type基类的引用。为了简单起见,下面篇幅中我会把引用所指向的对象称为Type类型的对象。

Type类的重要事项:

​ ● 对于程序中用到的每一个类型,CLR都会创建一个包含这个类型信息的Type类型的对象

​ ● 程序中用到的每一个类型都会关联到独立的Type类型的对象

​ ● 不管创建的类型有多少个实例,只有一个Type对象会关联到所有这些实例

​ 如果你对C#中有哪些类型不是很了解,那么知识扩展: C#中的类型有:预定义的类型(int,long和string等),BCL中的类型(Console,IEnumerable等)以及用户自定义的类型(MyClass,MyDel等)

3.2 Type类的部分常见成员

成员 成员类型 描述
Name 属性 返回类型的名字
FullName 属性 返回数据类型的完全限定名(包括命名空间名)
NameSpace 属性 返回包含数据类型声明的命名空间
Assembly 属性 返回声明类型的程序集。如果类型是泛型的,返回定义这个类型的程序集
GetConstructor(), GetConstructors() 方法 返回ConstructorInfo类型,用于取得该类的构造函数的信息
GetEvent(), GetEvents() 方法 返回EventInfo类型,用于取得该类的事件的信息
GetField(), GetFields() 方法 返回FieldInfo类型,用于取得该类的字段(成员变量)的信息
GetInterface(), GetInterfaces() 方法 返回InterfaceInfo类型,用于取得该类实现的接口的信息
GetMember(), GetMembers() 方法 返回MemberInfo类型,用于取得该类的所有成员的信息
GetMethod(), GetMethods() 方法 返回MethodInfo类型,用于取得该类的方法的信息
GetProperty(), GetProperties() 方法 返回PropertyInfo类型,用于取得该类的属性的信息

3.3 获取Type对象

都是获取类的引用的数据类型 System.Type

  • GetType()方法继承自Object,所以C#中任何对象都具有GetType()方法,x.GetType(),其中x为变量名

  • typeof(x)中的x,必须是具体的类名、类型名称等,不可以是变量名称

  • System.Type.GetType(),有两个重载方法:

    • 比如有这样一个变量i,Int16 i = new Int16();使用GetType(),i.GetType()返回值是Int16的类型;但是无法使用typeof(i),因为i是一个变量
    • 使用typeof(),则只能:typeof(Int32),返回的同样是Int16的类型
    • 枚举类的转换,String——枚举类,以串口中Parity为例。objParity= (Parity)Enum.Parse(typeof(Parity), “9600”);

获取类的Type属性,除了上面的使用实例获取,或者typeof,还有一种提供类的完整信息字符串,根据类名来获取Type:

//取得当前方法命名空间
str += "命名空间名:" + System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Namespace + "\n";
//取得当前方法类全名 包括命名空间
str += "类名:" + System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.FullName + "\n";
//取得当前方法名
str += "方法名:" + System.Reflection.MethodBase.GetCurrentMethod().Name + "\n"; str += "\n";
//取得当前方法类全名 包括命名空间
string classname = System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.FullName; //得到的是 命名空间.类
Type type = Type.GetType(classname); //通过类名获取同名类

object obj = System.Activator.CreateInstance(type); //创建实例

四、反射基本操作

4.1 反射–动态加载dll

  1. 通过dll文件名称进行加载

    Assembly assembly = Assembly.Load("DB.SqlServer");// dll名称  默认到当前目录下查找
    
  2. 全名称= 全路径+dll名称 + 后缀

    Assembly assembly = Assembly.LoadFile(@"D:\软谋教育\Ruanmou\Advanced13Encrypt\20191010Advanced13Course3Reflection\20191010Advanced13Course3Reflection\MyReflection\MyReflection\bin\Debug\DB.SqlServer.dll");
    
  3. 全名称

    Assembly assembly = Assembly.LoadFrom("DB.SqlServer.dll");
    
  4. 全名称

    Assembly assembly = Assembly.LoadFrom(@"D:\软谋教育\Ruanmou\Advanced13Encrypt\20191010Advanced13Course3Reflection\20191010Advanced13Course3Reflection\MyReflection\MyReflection\bin\Debug\DB.SqlServer.dll");
    

4.2 常规玩法

//1.动态加载dll
Assembly assembly = Assembly.Load("DB.SqlServer");// dll名称  默认到当前目录下查找

//获取所有类型
//assembly.GetTypes() 
//2.通过类型名称获取指定类型
Type type = assembly.GetType("DB.SqlServer.SqlServerHelper");

//3.创建对象
object oDbHelper = Activator.CreateInstance(type);
//dynamic dDbHelper = Activator.CreateInstance(type);
//dDbHelper.Query();

//4.类型转换
IDBHelper iDBHelper = oDbHelper as IDBHelper;

//5.调用方法
iDBHelper.Query();

第二步获取类型时,形式 = 命名空间名称 + 类名

第三步创建对象,其实和IDBHelper dBHelper = new SqlServerHelper(); 实例化一个对象等价,会执行到SqlServerHelper的构造函数里

经过第三步创建对象之后并不能直接调用Query方法,因为编译器就不认可(c# 是强类型语言);dynamic 是一个动态类型,可以避开编译器的检查,运行时检查,但存在安全问题 。

4.3 进阶玩法

封装 Factory + config 代码可以不用编译发布

简单工厂:

public class SimlpFactory
{ 
    private static string IDBHelperConfig = ConfigurationManager.AppSettings["IDBHelperConfig"]; 
    private static string DllName = IDBHelperConfig.Split(',')[1];
    private static string TypeName = IDBHelperConfig.Split(',')[0]; 
    public static IDBHelper CreateInstentce()
    {
        Assembly assembly = Assembly.Load(DllName);
        Type type = assembly.GetType(TypeName);
        object oDbHelper = Activator.CreateInstance(type);
        return oDbHelper as IDBHelper;
    }
}

config文件:

<appSettings>
    <add key="IDBHelperConfig" value="DB.Orcale.OrcaleHelper,DB.Orcale"/>
</appSettings>

调用:

IDBHelper iDBHelper = SimlpFactory.CreateInstentce();
iDBHelper.Query(); 

4.4 反射–选择不同的构造函数创建对象

//1.动态加载
Assembly assembly = Assembly.Load("DB.SqlServer");
//2.获取类型
Type type = assembly.GetType("DB.SqlServer.ReflectionTest");
//3.创建对象
object oDbHelper = Activator.CreateInstance(type);	//public ReflectionTest()
object oDbHelper1 = Activator.CreateInstance(type, new object[] { "杰克" });	// public ReflectionTest(string name)
object oDbHelper3 = Activator.CreateInstance(type, new object[] { 123 });	//public ReflectionTest(int id)

五、反射调用方法

5.1 反射–非类型转换调用方法

Assembly assembly = Assembly.Load("DB.SqlServer");
Type type = assembly.GetType("DB.SqlServer.ReflectionTest");

object oTest = Activator.CreateInstance(type);

无参数方法

MethodInfo show1 = type.GetMethod("show1");
show1.Invoke(oTest, null); //反射调用方法

有参数方法

MethodInfo show2 = type.GetMethod("show2");
show2.Invoke(oTest, new object[] { 123 }); //反射调用方法

重载方法,方法名称一样,参数不同

MethodInfo show1 = type.GetMethod("show1", new Type[] { typeof(string), typeof(int) });
show1.Invoke(oTest, new object[] { 123, "陈贺章" });

私有方法:

MethodInfo show4 = type.GetMethod("show4", BindingFlags.NonPublic | BindingFlags.Instance);
show4.Invoke(oTest, new object[] { "私有方法" });

静态方法: 对象的实例可以传入,也可以不传入。如果像常规使用是不需要实例化对象就可以直接调用方法(反射传null),但是反射却可以传入对象的实例

MethodInfo show5 = type.GetMethod("show5");
show5.Invoke(oTest, new object[] { "我是静态方法" });
show5.Invoke(null, new object[] { "我是静态方法" });

5.2 反射–调用泛型方法

六、反射黑科技

假设我们存在一个单例模式,代码如下:

/// <summary>
/// 单例模式:类,能保证在整个进程中只有一个实例
/// </summary>
public sealed class Singleton
{
    private static Singleton _Singleton = null;
    private Singleton()
    {
        Console.WriteLine("Singleton被构造");
    }

    static Singleton()
    {
        _Singleton = new Singleton();
    }

    public static Singleton GetInstance()
    {
        return _Singleton;
    }
}

常规用法:

Singleton singleton1 = Singleton.GetInstance();
Singleton singleton2 = Singleton.GetInstance();
Console.WriteLine(singleton1.Equals(singleton2)); //结果为:true

反射应用: 两次对象不一致,Activator.CreateInstance完全等价于new Singleton(),每次都调用了私有构造函数。反射破坏了单例,其实就是反射调用了私有构造函数文章来源地址https://www.toymoban.com/news/detail-589832.html

Assembly assembly = Assembly.Load("DB.SqlServer");
Type type = assembly.GetType("DB.SqlServer.Singleton");
object oSingleton1 = Activator.CreateInstance(type, true);   //第二个参数为 NoPublic--是否为公有的,完全等价于new Singleton();
object oSingleton2 = Activator.CreateInstance(type, true);
Console.WriteLine(oSingleton1.Equals(oSingleton2)); //结果为:false

到了这里,关于C#基础--反射的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • asp.net core6 webapi 使用反射批量注入接口层和实现接口层的接口的类到ioc中

    IBLL接口层类库 BLL实现接口层类库 program中利用反射批量注入 在控制器中使用构造函数传参就可以调用已经注册的所有是是实现接口的类了的实列了

    2024年02月13日
    浏览(40)
  • C#使用Asp.Net创建Web Service接口并调用

    目录 一.创建Asp.net web应用以及Web Service服务 (1).运行环境 (2)创建项目 二.创建控制台应用来调用上面创建的Web Service 开发工具: Visual Studio 2022 Current (免费社区版) 框架版本: .net framework4.7.2,更高的.net 5 、net6貌似没有默认提供带web service的asp.net 应用模板了。 确保VS的工作负荷有

    2024年01月18日
    浏览(44)
  • 【服务器】ASP.Net Core(C#)创建Web站点

    简单几步实现本地ASP.Net.Core web 站点结合cpolar内网穿透工具实现远程访问 1. 创建站点 *环境搭建,这边测试,使用.NET 6.0 SDK,可以点击跳转到官网下载,下载后安装即可. 安装完成后,进入到某个文件夹,打开powershell执行下面命令,创建新的 Web 应用,名称叫:aspnetcoreapp 2. 运行站点 信任开

    2024年02月11日
    浏览(48)
  • RDLC报表使用教程(VS2019+Asp.Net(C#)+iframework)

    VS2019 开发环境配置 在vs环境中,菜单扩展=管理扩展 联机中搜索 RDLC,出现MicroSoft RDLC Report Designer,如下 安装完毕后,点击右键项目(Asp.Net Web应用程序)=添加=新建项,会出现 报表、报表精灵(报表向导),如下:   新建报表后,就直接可以进行RDLC报表开发。 Web.Config里面配

    2024年02月01日
    浏览(83)
  • C#面:列举ASP.NET页面之间传递值的几种方式

    查询字符串(Query String): 可以通过在URL中添加参数来传递值。 例如:http://example.com/page.aspx?id=123 在接收页面中可以通过Request.QueryString[“id”]来获取传递的值。 会话状态(Session State): 可以使用Session对象在不同页面之间存储和检索值。 在发送页面中可以使用Session[“k

    2024年02月19日
    浏览(47)
  • ASP.NET Core 8 基础

    2023年11月将发布发布.NET 8,基于.NET 8 的 ASP.NET Core 8.0也会一并发布,这是继ASP.NET Core 6.0之后,又一个重要版本,因为引入了nativeAOT,在性能上有很大提升,所以系统地学习一下这项技术。 ASP.NET Core 的几个主要优势: 跨平台,支持 Windows, macOS, Linux,Docker,Azure和AWS等云服务自

    2024年02月11日
    浏览(49)
  • Asp.Net 使用Log4Net (基础版)

    创建ASP.NET Web Forms项目 在Visual Studio中创建一个新的ASP.NET Web Forms项目。命名为\\\"Log4NetDemo\\\"。 打开NuGet包管理器控制台,并运行以下命令来安装Log4Net: 在Web.config文件中添加Log4Net的配置。将以下内容粘贴到Web.config文件中。 在Global.asax文件中,我们需要初始化Log4Net。在 Applicatio

    2024年02月15日
    浏览(46)
  • C# ASP.NET Core Web API 身份授权(JWT)验证(一)

    1.开发环境 VS2022,安装时记得勾选ASP.NET有关的都选上,建议全选,省的麻烦。          2.创建初始工程 TestApi (你自己的工程名称)。    这就创建工程成功了,按 F5 则可以进行调试了。 而在项目中,我们不仅仅会用到基础的api功能,我们一般还会用到  身份授权(J

    2024年02月02日
    浏览(61)
  • 【ASP.NET Core 基础知识】--最佳实践和进阶主题--设计模式在ASP.NET Core中的应用

    一、设计模式概述 1.1 什么是设计模式 设计模式是在软件设计过程中反复出现的、经过验证的、可重用的解决问题的方法。它们是针对特定问题的通用解决方案,提供了一种在软件开发中可靠的指导和标准化方法。设计模式通常描述了一种在特定情景下的解决方案,包括了问

    2024年02月21日
    浏览(160)
  • 在 C#和ASP.NET Core中创建 gRPC 客户端和服务器

    gRPC 是一种可以跨语言运行的现代高性能远程过程调用 (RPC) 框架。gRPC 实际上已经成为 RPC 框架的行业标准,Google 内外的组织都在使用它来从微服务到计算的“最后一英里”(移动、网络和物联网)的强大用例。 gRPC是一个高性能的开源的通用RPC框架,由Google公司开发,支持常

    2024年04月23日
    浏览(46)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包