第二十一章 反射机制
cac55 2024-11-20 12:53 11 浏览 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 则意味搜索元数据中的相关信息失败(反射失败),请确保反射时使用类的完全限定名。
- 上一篇:就问你酷不酷 定制自己的动态壁纸
- 下一篇:如何开机自动登录windows8系统
相关推荐
- 终于,你可以在 iPhone 上玩《饥荒》了
-
继七月登陆iPad平台后,冒险生存游戏《饥荒》(Don'tStarve)经过两个月时间终于更新并适配了iPhone,此前我已就游戏在iPad上的表现写过详尽评测和上手攻略,故本文不再对游...
- 2025年最适合Macbook新手掌握的5个免费工具,效率立马飙升!
-
刚入手Macbook是否觉得操作不熟?担心新手期过长难以熟练提高效率?别担心!本文精选五款国区AppStore免费可下载的官方认证工具,所有选择均基于新手核心痛点与迁移成本考量,解决「系统维护」「操作...
- 苹果iOS 13.4和iPadOS 13.4正式更新,支持鼠标、键盘操作
-
智东西(公众号:zhidxcom)编|王颖智东西3月25日消息,苹果今天向用户推送了iOS13.4和iPadOS13.4系统更新通知。iPadOS13.4增加了对iPad鼠标和触控板的支持,...
- 苹果即将发布macOS 15 用户界面将迎来重大革新
-
苹果公司计划于6月举行的全球开发者大会(WWDC)上,震撼发布全新的macOS15操作系统。据CNMO最新报道,此次更新将彻底革新“菜单和应用程序用户界面”的排列方式,为用户带来全新的使用体验。ma...
- **Bartender 5:菜单栏管理神器**(菜单栏工具)
-
提供免费下载网站Mavom.cn**Bartender**让你可以隐藏、重新排列或移动菜单栏应用,保持桌面整洁。**主要功能:*****整理菜单栏应用**:随心所欲地隐藏或显示应用。***更新提醒...
- Mac用户必备!12款最实用的高效App,绝对值得收藏
-
作为一名数码博主,日常的工作不仅包括写文章,还涉及到大量的内容创作、视频编辑和资料管理。随着使用Mac的时间越来越长,我发现一台强大的Mac电脑,若没有合适的App加持,效果往往大打折扣。因此,我深入...
- 苹果电脑死机了按什么键(mac卡死按哪三个键)
-
苹果电脑以其卓越的性能和稳定的系统而闻名,但在使用过程中,偶尔也会遇到死机或应用程序无响应的情况。这时,掌握一些有效的强制重启或关闭方法就显得尤为重要。本文将详细介绍苹果电脑在死机时可以采取的几种处理...
- 怎么查看macbook硬盘是不是原装的
-
要查看MacBook的硬盘是否是原装的,可以采取以下几种方法:###通过系统信息检查1.**查看设备信息**:打开苹果菜单栏中的“关于本机”选项,然后选择“存储”或“磁盘工具”。这将显示你电脑上已...
- 苹果MacBook一定要进行的6个设置|新手必备省电技巧
-
一、MacBook省电设置技巧1、电池偏好设置打开“系统偏好设置”,选择“电池”,选择第二项“电池”,不同的系统版本和机型在这个界面会有所差别。勾选“使用电池电源时使显示屏略暗一些”,勾选“优化电池充...
- 在 Mac 菜单栏也能控制 HomeKit 家居设备
-
想要控制家里的HomeKit设备,我们可以利用Apple官方的家庭App。但在Mac上,家庭App不能算得上好用,不像iOS可以从控制中心直接操作,在Mac上必须打开家庭A...
- 苹果手机里这个图标是什么意思?原来这是个监听器!一直都不知道
-
不知道大家最近都有没有关注iPhone的新消息呢?iPhone11出来之后,不少小伙伴都被圈粉啦!小编不得不说绿色的那款是真好看啊!当然不仅是好看,用过苹果手机的小伙伴都知道,苹果手机里有很多超好用的...
- 如何解决苹果电脑弹出本地项目钥匙串提示?
-
Mac电脑使用的时候,因为通过iCloud同步钥匙串,或者是修改本地账户密码,会反复弹出某项目想要登录使用“钥匙串”的提示,且无法关闭的现象。那我们该如何解决呢?快和小编一起来看看吧!具体方法如下1....
- MAC小技巧:如何快速调整Dock栏的大小
-
苹果mac系统dock栏怎么缩小?想要自己调节一下dock栏的大小,该怎么调节呢?下面我们就来看看详细的苹果Mac电脑如何快速调整Dock栏的大小样式教程,需要的朋友可以参考下。1、在Dock栏右侧,...
- 新买了苹果电脑不会用?给小白的使用手册,MacOS入门必备
-
咱们很多小伙伴都是十几年甚至二十几年的Windows老用户了,如果换成苹果电脑,可能会一脸懵逼,一时间不知道怎么使用。毕竟苹果电脑搭载的是MacOS操作系统,除了系统界面和操作上有区别外,电脑键盘上有...
- 苹果macOS 15设置界面将迎来重大更新 更智能更美观
-
【CNMO科技消息】苹果计划在6月WWDC全球开发者大会上震撼发布macOS15。据CNMO了解,此次更新将彻底革新“菜单和应用程序用户界面”的排列方式。macOSVentura系统中的“系统设置...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- 如何绘制折线图 (52)
- javaabstract (48)
- 新浪微博头像 (53)
- grub4dos (66)
- s扫描器 (51)
- httpfile dll (48)
- ps实例教程 (55)
- taskmgr (51)
- s spline (61)
- vnc远程控制 (47)
- 数据丢失 (47)
- wbem (57)
- flac文件 (72)
- 网页制作基础教程 (53)
- 镜像文件刻录 (61)
- ug5 0软件免费下载 (78)
- debian下载 (53)
- ubuntu10 04 (60)
- web qq登录 (59)
- 笔记本变成无线路由 (52)
- flash player 11 4 (50)
- 右键菜单清理 (78)
- cuteftp 注册码 (57)
- ospf协议 (53)
- ms17 010 下载 (60)