C#4.0图解教程 - 第24章 反射和特性 - 1.反射
24.1 元数据和反射
有关程序及类型的数据被成为 元数据。他们保存在程序集中。
程序运行时,可以查看其他程序集或其本身的元数据。一个运行的程序查看本身元数据或其他程序的元数据的行为叫做 反射。

24.2 Type 类
| Name | 属性 | 返回类型的名字 |
| Namespace | 属性 | 返回包含类型的命名空间 |
| Assembly | 属性 | 返回声明类型的程序集。如果类型是泛型,返回定义这个类型的程序集 |
| GetFields | 方法 | 返回类型的字段列表 |
| GetProperties | 方法 | 返回类型的属性列表 |
| GetMethods | 方法 | 返回类型的方法列表 |
1.反射概念:
1.在程序运行时,
动态 获取 加载程序集
动态 获取 类型(如类、接口 等)
动态 获取 类型的成员 信息(如方法,字段,属性等);
2.在运行时,动态创建类型实例,以及 调用 和 访问 这些 实例 成员;
namespace _01反射
{
class Dog
{
public string name;
public int age;
private bool gender; public string ShoutHi()
{
return this.name + "," + this.age + "," + this.gender;
}
}
获取

调用

//6.相当于:d2.name=”小白”;
//7.相当于:d2.ShoutHi();
2.Assembly 程序集对象
获取程序集的方式:
2.1.获得当前 程序域中 所有的Assembly:
AppDomain.CurrentDomain.GetAssemblies()
Assembly[] ass = AppDomain.CurrentDomain.GetAssemblies();
ass调用的所有Assembly

2.2.获取当前 对象 所在的 Assembly:
this.GetType().Assembly
//1.获取当前正在运行的 程序集(Assembly)对象
Assembly ass = this.GetType().Assembly;

2.3.根据路径加载Assembly :
Assembly.LoadFrom(assPath)

3.Type 类型对象
Type类,程序运行时一个 class 对应一个 Type类的对象。
通过Type对象可以获得类的所有的定义信息,比如类有哪些属性、哪些方法等
获得Type对象的方式:
1.通过类 获得 对应 Type:Type t = typeof(Person)
2.通过对象 获得 Type:Type t = p.GetType()
3.根据类的全名称 获取程序集中定义的类:
Type type = Assembly.GetType("BLL.Person")
Type tDog = ass.GetType("_01反射.Dog"); //全名称(带命名空间)
4.获取程序集中定义的所有的public类:
Type [] types = assembly.GetExportedTypes()
5.获取程序集中定义的所有的类型:
Type [] types = assembly.GetTypes()
Assembly ass = this.GetType().Assembly;
//获取此程序集中定义的公共类型,这些公共(public)类型在程序集外可见. (ispublic = true)
Type[] types = ass.GetExportedTypes();
// 获取此程序集中定义的所有类型
Type[] tyoe = ass.GetTypes(); //1.通过类 直接过去 类型对象
Type t2 = typeof(Dog);
//2.通过对象 来获取 类型对象
Type t3 = this.GetType();

案例:笔记本插件开发

plugs文件夹

namespace C02记事本插件
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
} private void Form1_Load(object sender, EventArgs e)
{
makeBrntBll();
} //读取程序集,并生成插件
public void makeBrntBll()
{
//1.加载正在运行程序的物理路径
string strRunAss = this.GetType().Assembly.Location; //2.获取程序集坐在文件夹,并转换成插件文件夹路径
string AssPath = Path.GetDirectoryName(strRunAss)+"\\plugs"; //3.扫描插件文件夹里面的所有程序集文件
string[] strDrictoryPath = Directory.GetFiles(AssPath, "*.dll"); //4.遍历程序集文件 路径,并加载到内存中
foreach (var strItem in strDrictoryPath)
{
//4.1根据路径 加载到内存中
Assembly ass = Assembly.LoadFrom(strItem); //4.2判断程序集中是否有插件类 //4.3创建插件按钮
ToolStripMenuItem menuItem = new ToolStripMenuItem("发现一个插件");
this.插件扩展ToolStripMenuItem.DropDownItems.Add(menuItem);
}
}
}
}

结果:

4.Type 的成员
| 属性 | |
| type.Assembly |
获取type所在的程序集对象 |
| type.FullName |
获取type对象对应的类的全名称 |
| type.Name | 获取type对象对应类的 名称 |
| type.IsArray | 判断type是否为一个数组类 |
| type.IsEnum | 判断type是否为一个枚举类 |
| 方法 | |
| type.IsAssignableFrom(Type i) | 判断type是否实现了接口 i |
| type.IsSubclassOf(Type father) |
判断type是否继承了 father |
| type.IsInstanceOfType(object o) | 判断 o 是否为type类的实例 |
| type.GetFiled("gender") |
获取type中名为gender的字段对象 |
| type.GetMethod("SayHi") |
获取type中名为 SayHi 的方法对象 |
| type.GetProperty("Age") | 获取type中名为 Age 的属性对象 |
5.FieldInfo 字段对象
FieldInfo类 代表某个类中的一个成员字段(类的全局变量)
public class Dog
{
public string dogName;
public int dogAge;
}
操作 对象 的字段
Dog dObj = new Dog() { dogName = "小花", dogAge = 1 };
//dogName:小花,dogAge:1
Console.WriteLine(string.Format("dogName:{0},dogAge:{1}",dObj.dogName,dObj.dogAge));
Type dType = dObj.GetType();//获取类型
FieldInfo fiDN = dType.GetField("dogName"); //获取字段对象
//相当于string strName = dObj.dogName;
string strName = fiDN.GetValue(dObj).ToString(); //获取dObj的dogName字段值,strName=“小花”
fiDN.SetValue(dObj, "小白"); //设置dObj里的dogName字段值
//dogName:小白,dogAge:1
Console.WriteLine(string.Format("dogName:{0},dogAge:{1}", dObj.dogName, dObj.dogAge));
6.PropertyInfo 属性对象
PropertyInfo类 代表某个类中的一个属性
public class Dog
{
public string Name{get;set;}
public int Age{get;set;}
}
Dog dObj = new Dog() { Name = "小花", Age = 1 };
Console.WriteLine(string.Format("dogName:{0},dogAge:{1}", dObj.Name, dObj.Age));
Type dType = dObj.GetType();
PropertyInfo piN = dType.GetProperty("Name"); //获取属性对象
string strName = piN.GetValue(dObj, null).ToString(); //获取dObj的Name属性值
piN.SetValue(dObj, "小白", null); //设置dObj里的Name属性值
Console.WriteLine(string.Format("dogName:{0},dogAge:{1}", dObj.Name, dObj.Age));
public class Dog
{
public string Smile(string name)
{
return "一只会笑的狗:"+name;
}
}
调用 对象 的方法
Dog dObj = new Dog();
Type dType = dObj.GetType();
MethodInfo method = dType.GetMethod("Smile"); //获取方法对象 object res1 = dObj.Smile("小五~~");//*普通调用方法
object res2 = method.Invoke(dObj, new object[] { "小白" }); //*反射调用dObj的Smile方法
Console.WriteLine(string.Format("res1:{0},\r\nres2:{1}", res1, res2));
第一个参数是实例对象,第二个参数是方法的参数数组,如果没有参数设置为null
问:如果第一个参数传 null 呢?

8.动态创建对象

1.object res =Activator.CreateInstance(Type type)
会动态调用类的无参构造函数创建一个对象
返回值就是创建的对象,如果类没有无参构造函数就会报错。
2.使用 构造器 创建
//构造函数
//public Dog(){}
public Dog(string name, int age){
this.Name = name;
this.Age = age;
}
Type dType = typeof(Dog);//获取 Dog类 类型 对象
//获取 构造器 对象(根据 参数列表的 参数类型 数组 获取)
ConstructorInfo cotr = dType.GetConstructor(new Type[] { typeof(string), typeof(int) });
object resValue = cotr.Invoke(new object[] { "小白", 2 }); //调用指定参数的实例所反映的构造函数cotr
Console.WriteLine(string.Format("Name:{0},Age:{1}", ((Dog)(resValue)).Name, ((Dog)(resValue)).Age));

class Cat
{
public string name;
public int age;
//构造函数
public Cat(string name, int age)
{
this.name = name;
this.age = age;
}
}

9.调用对象私有成员
Person p1 = new Person();
Type type = p1.GetType();
//BindingFlags.Instance表示是实例方法,也就是不是static方法
MethodInfo mHaha = type.GetMethod("Haha",BindingFlags.NonPublic | BindingFlags.Instance);
mHaha.Invoke(p1, null);
作者:唐三三
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
C#4.0图解教程 - 第24章 反射和特性 - 1.反射的更多相关文章
- C#4.0图解教程 - 第24章 反射和特性 – 2.特性
1.特性 定义 Attribute用来对类.属性.方法等标注额外的信息,贴一个标签(附着物) 通俗:给 类 或 类成员 贴一个标签,就像航空部为你的行李贴一个标签一样 注意,特性 是 类 和 类的成员 ...
- 【读书笔记】关于《精通C#(第6版)》与《C#5.0图解教程》中的一点矛盾的地方
志铭-2020年2月8日 03:32:03 先说明,这是一个旧问题,很久很久以前大家就讨论了, 哈哈哈,而且先声明这是一个很无聊的问题,
- 【C#4.0图解教程】笔记(第19章~第25章)
第19章 泛型 1.泛型概念 泛型提供了一种更准确地使用有一种以上的类型的代码的方式. 泛型允许我们声明类型参数化的代码,我们可以用不同的类型进行实例化. 泛型不是类型,而是类型的模板. 2.声明 ...
- C#图解教程 第十一章 枚举
枚举 枚举 设置底层类型和显式值隐式成员编号 位标志 Flags特性使用位标志的示例 关于枚举的补充 枚举 枚举 枚举是由程序员定义的类型与类或结构一样. 与结构一样,枚举是值类型,因此直接存储它们的 ...
- 【C#4.0图解教程】笔记(第9章~第18章)
第9章 语句 1.标签语句 ①.标签语句由一个标识符后面跟着一个冒号再跟着一条语句组成 ②.标签语句的执行完全如同标签不存在一样,并仅执行冒号后的语句. ③.给语句添加一个标签允许控制从代码的另一部分 ...
- 【C#4.0图解教程】笔记(第1章~第8章)
第1章 C#和.NET框架 1..NET框架的组成 .NET框架由三部分组成(严格来说只有CLR和FCL(框架类库)两部分),如图 执行环境称为:CLR(公共语言运行库),它在运行期管理程序的执行. ...
- C#图解教程 第六章 深入理解类
深入理解类 类成员成员修饰符的顺序实例类成员静态字段从类的外部访问静态成员 静态字段示例静态成员的生存期 静态函数成员其他静态类成员类型成员常量常量与静态量属性 属性声明和访问器属性示例使用属性属性和 ...
- C# 图解教程 第五章 方法
方法的结构方法体内部代码的执行本地变量 类型推断和var关键字 嵌套块中的本地变量本地常量控制流方法调用返回值返回语句和void方法参数 形参 实参值参数引用参数引用类型作为值 ...
- C#图解教程 第七章 类和继承
类和继承 类继承访问继承的成员所有类都派生自object类屏蔽基类的成员基类访问使用基类的引用 虚方法和覆写方法覆写标记为override的方法覆盖其他成员类型 构造函数的执行 构造函数初始化语句类访 ...
随机推荐
- osx xcode 创建python项目
http://stackoverflow.com/questions/5276967/python-in-xcode-7
- angularjs入门基础一
app.controller('firstController',function($scope,$rootScope){ $scope.name='张三'; $rootScope.age='30'; ...
- HTTP头部详解
因为之后的HTTP头注入要学习这些所以就看了.觉得很不错,算是学习前的科普. <HTTP头部详解>转载自:http://www.cnblogs.com/lcamry/p/5763040.h ...
- metasploit连接数据库
表示一直出问题.不造哪里出错.望有知情人与本人取得联系! test
- Sound Generator 原理
Sound Generator 原理 旨在简单的阐述声音如何通过单片机模块来产生. 声音 声音的种类有千千万,但归根到底还是属于波.在对声音进行模拟转数字的时候,采样越高, 声音被还原的越逼真. 声音 ...
- 前端之js的常用用法
js生成标签 // 将标签添加到i1里面 var tag = document.createElement('input'); tag.setAttribute('type', 'text'); ta ...
- 跨域解决方案二:使用JSONP实现跨域
跨域的实现方式有多种,除了 上篇文章 提到的CORS外,常见的还有JSONP.HTML5.Flash.iframe.xhr2等. 这篇文章对JSONP的跨域原理进行了探索,并将我的心得记录在这里和大家 ...
- LUA+resty 搭建验证码服务器
使用Lua和OpenResty搭建验证码服务器 雨客 2016-04-08 16:38:11 浏览2525 评论0 云数据库Redis版 摘要: Lua下有个Lua-GD图形库,通过简单的Lua语句就 ...
- 在Py文件中引入django环境
复制manage.py中的相关代码即可并将文件置于Project文件夹(与manage.py同位置)下 示例: #! /usr/bin/env python # -*- coding:utf- -*- ...
- docker -v挂载数据卷网络异常的问题
docker 删除容器并重新运行容器时报如下异常: docker: Error response from daemon: failed to create endpoint tomcat001 on ...