百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

第二十一章 反射机制

cac55 2024-11-20 12:53 12 浏览 0 评论

21.1 反射概述

反射是.NET中的重要机制,通过反射,可以在运行时获得程序或程序集中每一个类型(包括类、结构、委托、接口和枚举等)的成员和成员的信息。有了反射,即可对每一个类型了如指掌。另外我还可以直接创建对象,即使这个对象的类型在编译时还不知道。

为什么使用反射,而不直接引用它的dll或者类型呢?

例如你有个main.exe,需要使用say.dll,draw.dll,突然客户说我们要添加一个跑的功能,那么只需要按照我们约定的规则做一个run的dll,之前的main.exe不需要做任何修改(就是不需要再去导入run.dll,其中需要其他的设计来规范),在main.exe中就能直接使用run.dll了。

其实,我们已经在不自觉地使用它了,举个最简单的例子,当你在VS的设计器里拖入一个控件后,设计器会通过反射获取这个控件的属性,并提供你进行设置。那么,问题来了,为什么要用反射呢?因为设计器在做的时候,根本不可能预知将来有什么控件会被你拖入进去。

【反射用途】

(1)使用Assembly定义和加载程序集,加载在程序集清单中列出模块,以及从此程序集中查找类型并创建该类型的实例。

(2)使用Module了解包含模块的程序集以及模块中的类等,还可以获取在模块上定义的所有全局方法或其他特定的非全局方法。

(3)使用ConstructorInfo了解构造函数的名称、参数、访问修饰符(如pulic 或private)和实现详细信息(如abstract或virtual)等。

(4)使用MethodInfo了解方法的名称、返回类型、参数、访问修饰符(如pulic 或private)和实现详细信息(如abstract或virtual)等。

(5)使用FiedInfo了解字段的名称、访问修饰符(如public或private)和实现详细信息(如static)等,并获取或设置字段值。

(6)使用EventInfo了解事件的名称、事件处理程序数据类型、自定义属性、声明类型和反射类型等,添加或移除事件处理程序。

(7)使用PropertyInfo了解属性的名称、数据类型、声明类型、反射类型和只读或可写状态等,获取或设置属性值。

(8)使用ParameterInfo了解参数的名称、数据类型、是输入参数还是输出参数,以及参数在方法签名中的位置等。

【反射用到的命名空间】

System.Reflection

System.Type

System.Reflection.Assembly


【反射用到的主要类】

System.Type 类--通过这个类可以访问任何给定数据类型的信息。

System.Reflection.Assembly类--它可以用于访问给定程序集的信息,或者把这个程序集加载到程序中。

【System.Type类】

System.Type 类对于反射起着核心的作用。但它是一个抽象的基类,Type有与每种数据类型对应的派生类,我们使用这个派生类的对象的方法、字段、属性来查找有关该类型的所有信息。

获取给定类型的Type引用有3种常用方式:

●使用 C# typeof 运算符。

  Type t = typeof(string);

●使用对象GetType()方法。

 string s = "grayworm";
?
 Type t = s.GetType(); 

●还可以调用Type类的静态方法GetType()。

 Type t = Type.GetType("System.String");

上面三种方式都是获取string类型的Type,在取出string类型的Type引用t后,我们就可以通过t来探测string类型的结构了。

【Type类的属性】

Name 数据类型名

FullName 数据类型的完全限定名(包括命名空间名)

Namespace 定义数据类型的命名空间名

IsAbstract 指示该类型是否是抽象类型

IsArray 指示该类型是否是数组

IsClass 指示该类型是否是类

IsEnum 指示该类型是否是枚举

IsInterface 指示该类型是否是接口

IsPublic 指示该类型是否是公有的

IsSealed 指示该类型是否是密封类

IsValueType 指示该类型是否是值类型

【Type类的方法】

GetConstructor(), GetConstructors():返回ConstructorInfo类型,用于取得该类的构造函数的信息

GetEvent(), GetEvents():返回EventInfo类型,用于取得该类的事件的信息

GetField(), GetFields():返回FieldInfo类型,用于取得该类的字段(成员变量)的信息

GetInterface(), GetInterfaces():返回InterfaceInfo类型,用于取得该类实现的接口的信息

GetMember(), GetMembers():返回MemberInfo类型,用于取得该类的所有成员的信息

GetMethod(), GetMethods():返回MethodInfo类型,用于取得该类的方法的信息

GetProperty(), GetProperties():返回PropertyInfo类型,用于取得该类的属性的信息

可以调用这些成员,其方式是调用Type的InvokeMember()方法,或者调用MethodInfo, PropertyInfo和其他类的Invoke()方法。

21.2 反射应用

(1)我们首先定义一个类用来测试反射

// #region << 版 本 注 释 >>
// /*----------------------------------------------------------------
// // Copyright (C) 2019 极客部落
// // 版权所有。 
// //
// // 文件名:Program.cs
// // 文件功能描述:
// //
// // 
// // 创建者:GeekTribe
// // 时间:14:05
// //----------------------------------------------------------------*/
// #endregion
using System;
using System.Reflection;
?
namespace MSN
{
    public class NewClass
    {
        public string a;
        public int b;
        public int ID { get; set; }
        public int Age { set; get; }
        public NewClass(string m, int n)
        {
            a = m;
            b = n;
        }
?
        public NewClass()
        {
            Console.WriteLine("调用构造函数");
        }
?
        public void show()
        {
            Console.WriteLine("生成一个对象成功" + a + b + this.ID + this.Age);
        }
    }
?
    class MainClass
    {
        public static void Main(string[] args) {
            Console.WriteLine("Hello World");
        }
    }
}

(2)查看类中的构造方法

我们可以根据对象进而查看内部的构造函数以及参数。

NewClass nc = new NewClass();
Type t = nc.GetType();
ConstructorInfo[] ci = t.GetConstructors();
foreach (var c in ci)
{
    Console.WriteLine("count");
    ParameterInfo[] ps = c.GetParameters();
    foreach (ParameterInfo pi in ps)   //遍历并打印所该构造函数的所有参数
    {
?
        Console.Write(pi.ParameterType.ToString() + " " + pi.Name + ",");
    }
    Console.WriteLine();
}

(3)用构造函数动态生成对象

我们使用构造函数动态创建一个新的对象,如下代码所示:

Type t = typeof(NewClass);
?
//参数数组,第一个参数是string,第二个是int
Type[] pt = new Type[2];
?
pt[0] = typeof(string);
pt[1] = typeof(int);
?
//根据参数类型获取构造函数,有可能有多个构造函数
ConstructorInfo ci = t.GetConstructor (pt);
object[] obj = new object[2]{"5",6} ;
?
//调用构造函数,传递参数为obj
object o = ci.Invoke (obj);
?
//测试调用结果是否成功
((NewClass)o).show ();

(4) 用Activator生成对象

Type t = typeof(NewClass);
?
//用Activator的CreateInstance静态方法,生成新对象
object o = Activator.CreateInstance(t,"grayworm", 123);
?
//构造函数的参数
//object[] obj = new object[2] { "hello", 123 };
?
//object o=Activator.CreateInstance(t,obj);
//object o = Activator.CreateInstance (t);
?
((NewClass)o).show();

(5)查看类中的属性

NewClass nc = new NewClass();
?
Type t = nc.GetType();
?
//Type t = typeof(NewClass);
PropertyInfo[] pis = t.GetProperties();
?
foreach(PropertyInfo pi in pis){
  Console.WriteLine(pi.Name);
}

(6)查看类中的public方法

 NewClass nc = new NewClass();
?
Type t = nc.GetType();
?
MethodInfo[] mis = t.GetMethods();
?
foreach (MethodInfo mi in mis)
{
    Console.WriteLine(mi.ReturnType + " " + mi.Name);
}

(7)查看类中的public字段

 NewClass nc = new NewClass();
?
 Type t = nc.GetType();
?
 FieldInfo[] fis = t.GetFields();
?
 foreach (FieldInfo fi in fis){
     Console.WriteLine(fi.Name);
 }

(8)用反射生成对象,并调用属性、方法和字段进行操作

NewClass nc = new NewClass();
?
Type t = nc.GetType();
?
object obj = Activator.CreateInstance(t);
?
//取得ID字段
FieldInfo fi = t.GetField("a");
?
//给ID字段赋值
fi.SetValue(obj, "80");
?
//取得Name属性
PropertyInfo pi1 = t.GetProperty("ID");
?
//给Name属性赋值
pi1.SetValue(obj, 123, null);
PropertyInfo pi2 = t.GetProperty("Age");
pi2.SetValue(obj, 200, null);
?
//取得show方法
MethodInfo mi = t.GetMethod("show");
?
//调用show方法
mi.Invoke(obj, null);

(9)System.Reflection.Assembly介绍

Assembly类可以获得程序集的信息,也可以动态的加载程序集,以及在程序集中查找类型信息,并创建该类型的实例。

使用Assembly类可以降低程序集之间的耦合,有利于软件结构的合理化。

通过程序集名称返回Assembly对象

  Assembly ass = Assembly.Load("ClassLibrary831");

通过DLL文件名称返回Assembly对象

  Assembly ass = Assembly.LoadFrom("ClassLibrary831.dll");

通过Assembly获取程序集中类

  Type t = ass.GetType("ClassLibrary831.NewClass");     //参数必须是类的全名
//通过Assembly获取程序集中所有的类
?
Type[] t = ass.GetTypes();
?
?
//通过程序集的名称反射
Assembly ass = Assembly.Load("ClassLibrary831");
?
Type t = ass.GetType("ClassLibrary831.NewClass");
?
object o = Activator.CreateInstance(t, "grayworm", "http://hi.baidu.com/grayworm");
?
MethodInfo mi = t.GetMethod("show");
?
mi.Invoke(o, null);
?
//通过DLL文件全名反射其中的所有类型
Assembly assembly = Assembly.LoadFrom("xxx.dll的路径");
?
Type[] aa = a.GetTypes();
?
foreach(Type t in aa){
    if(t.FullName == "a.b.c"){
            object o = Activator.CreateInstance(t);
    }
}

(10)System.Reflection.Assembly使用

假设你要反射一个 DLL 中的类,并且没有引用它(即未知的类型),我们可以像下面那样操作:

Assembly assembly = Assembly.LoadFile("程序集路径,不能是相对路径"); //加载程序集(EXE 或 DLL) 
?
object obj = assembly.CreateInstance("类的完全限定名(即包括命名空间)"); //创建类的实例 

(11)反射当前项目中的类

Assembly assembly = Assembly.GetExecutingAssembly(); // 获取当前程序集     
object obj = assembly.CreateInstance("Reflection.MainClass");
((MainClass)obj).show ();

其中Reflection.MainClass是命名空间+类名的形式。

补充:

1)反射创建某个类的实例时,必须保证使用类的完全限定名(命名空间 + 类名)。Type.GetType 方法返回 null 则意味搜索元数据中的相关信息失败(反射失败),请确保反射时使用类的完全限定名。


相关推荐

正点原子开拓者FPGA开发板资料连载第四十章 SD卡图片显示实验

1)实验平台:正点原子开拓者FPGA开发板2)摘自《开拓者FPGA开发指南》关注官方微信号公众号,获取更多资料:正点原子3)全套实验源码+手册+视频下载地址:http://www.openedv.c...

东芝存储改名为铠侠了,铠侠microSD卡128GB全网首测

作为一个数码爱好者,平时总爱把玩各种科技数码产品,最近又迷上了口袋云台相机,大疆OsmoPocket、飞宇口袋相机、SnoppaVmate口袋相机什么的,不过这类产品由于设计的机身体积很小(毕竟为...

SD存储卡卡面上奇奇怪怪的图标,你知道几个?

现在对高像素照片、连拍、4K甚至8K的需求越来越多,对存储卡的传输速度、容量等,要求也越来越多了。但是,看到SD存储卡卡面上奇奇怪怪的图标,让人非常迷惑。这篇文章让你简单认识这些图标和奇奇怪怪的数字。...

拍摄4K视频上选!铠侠 EXCERIA PLUS microSD卡

大家好,我是波导终结者。今天跟大家分享的是铠侠的EXCERIAPLUS极至光速microSDXCUHS-1存储卡,名字有点长,但是不用担心,我会帮大家梳理好存储卡的选购建议。有不少刚入门的朋友...

高速稳定,一卡多用:铠侠极至光速microSD存储卡评测

Hello,大家好,我是小胖子。半个月前收到了KIOXIA铠侠寄来的一张256GB的TF卡,用了大半个月,让我们看看这款产品表现如何吧。其实很多人并不太了解铠侠,问我铠侠是什么品牌,好不好。其实,东芝...

读速205MB/s、V30规格,雷克沙SILVER系列存储卡再添新成员

IT之家6月19日消息,雷克沙今日推出3款SILVER系列SD/microSD存储卡新品,支持4K60fps录像。据介绍,该系列存储卡均符合V30标准,其中micr...

相机、无人机拍视频,选择SD存储卡有什么需要知道的?

本文章不涉及产品推荐导购行为,致力于给到小白带来基础知识。相机一般使用SD卡,无人机一般使用microSD卡(也叫TF卡),使用的标准和图标标识是一样的。相机、无人机拍视频,选择SD存储卡有什么需要知...

PNY推出适用Switch 2的microSD Express卡,读取速度高达890MB/s

任天堂Switch2开始预订,其比前代产品变得更加昂贵,各种配件的价格都高于预期,这也包括转向microSDExpress存储。此时,PNY推出了新款microSDExpress闪存卡。新款mi...

SD卡迎来25周年:全球售出120亿张,容量翻50万倍

IT之家5月21日消息,科技媒体betanews今天(5月21日)发布博文,报道称SD卡迎来了25周年的生日。自2000年首款SD存储卡问世以来,已走过25个年头...

微单相机买一款什么样的SD卡才够用?写入速度更为关键

最近,评价君朋友发现自己的卡拍摄视频时候总断流,于是感觉写入速度应该是不够的,打算换卡,评价君正好跟他说道说道。目前的SD存储卡,很多只标注读取速度,比如95MB/s,80MB/s等等,而没有写写入速...

金士顿Canvas Go!Plus 系列存储卡评测

前言2020年,金士顿推出了CanvasGo!Plus系列存储卡,凭借其优秀的读写速度和稳定性获得了广大用户的认可。时隔5年,金士顿推出了其全新升级产品:SDG4/SDCG4,可选容量覆盖64GB...

TF卡速度等级|MK米客方德(tf卡速度等级图)

TF卡(TransFlash卡,又称MicroSD卡)是一种常见的便携式存储媒体,广泛用于智能手机、相机、平板电脑等设备中。TF卡的性能通常由速度等级来衡量,这些等级反映了TF卡的数据传输速度。拓优星...

关于SD卡,看这张表就够了(sd卡的作用)

这里是溢图科技(原“相机笔记”)。这两天有不少存储产品促销,随之而来的就是关于SD卡的一些提问。文章以前已经写过很多了,这里主要给大家看一张表格:上面就是SD卡协会官方制作的“族谱”,明确给出了不同版...

轻量化储存的首选——凯侠极致光速256G microSD存储卡实测

对于摄影师而言,我们经常会接触到相关存储设备,像照片拍摄中给相机安装的SD卡,视频录制中外录高规格画面的SSD等,都属于专业的存储介质,被应用于商业拍摄、电影级别拍摄之中。而针对生活中我们日常用于拍摄...

首发1569元,读取速度可达250MB/s,闪迪推出最新2TB至尊超极速存储卡

近日,闪迪(SanDisk)正式发布了其最新的2TB至尊超极速microSDXCUHS-I存储卡。据悉,这款存储卡的读取速度可达250MB/s,写入速度则达到150MB/s。这意味着用户在处理高分辨...

取消回复欢迎 发表评论: