前言
大多数 程序 都要 处理 数据, 包括 读、 写、 操作 和 显示 数据。( 图形 也是 一种 数据 的 形式。) 然而, 对于 某些 程序 来说,它们 操作 的 数据 不是 数字、 文本 或 图形, 而是 程序 和 程序 类型 本身 的 信息。 有关 程序 及其 类型 的 数据 被称为 元 数据( metadata), 它们 保存 在 程序 的 程序 集中。 程序 在 运行时, 可以 查看 其他 程序 集 或 其 本身 的 元 数据。 一个 运行 的 程序 查看 本身 的 元 数据 或 其他 程序 的 元 数据 的 行为 叫做 反射( reflection)。
反射实践
一.制作程序集
打开vs新建一个类库
点下一步配置类库的路径和名字
创建好之后加入以下代码,代码中创建的一个Example类,加入一些字段、属性、和方法,并给他标记了自定义的特性MyAttribute,方便以后的测试
using System;
namespace MyDll
{
//指定自定义特性只能附加到类上
[AttributeUsage(AttributeTargets.Class)]
public sealed class MyAttributeAttribute : System.Attribute
{
public string Description;
public string Version;
public string ReviewId;
public MyAttributeAttribute(string desc, string ver)
{
Description = desc;
Version = ver;
}
}
[MyAttribute("MyClass", "1.0", ReviewId = "58946")]
public class Example
{
public int a = 567;
private int b = 555;
public int B
{
get
{
return b;
}
set
{
b = value;
}
}
public void HelloDll()
{
Console.WriteLine("HelloDll");
}
public void PrintOut(string s)
{
Console.WriteLine(s);
}
}
}
加入代码后 使用快捷键ctr + b 生成MyDll.dll文件,此时我们可以在项目中的MyDll\bin\Debug\netcoreapp3.1 文件夹下找到MyDll.dll文件,表示生成成功了
二.测试
新建C#控制台应用程序,运行测试代码如下
//加载程序集
Assembly assembly = Assembly.LoadFrom(@"D:\STu\csharp_-study\CSharp_Study\MyDll\bin\Debug\netcoreapp3.1\MyDll.dll");
Type type = assembly.GetType("MyDll.Example");
//创建类型实列
object obj = Activator.CreateInstance(type);
//调用方法
type.GetMethod("HelloDll").Invoke(obj,null);
//调用带参数的方法
type.GetMethod("PrintOut").Invoke(obj, new object[] { "DLLTEST" });
//获取属性
PropertyInfo propertyInfo = type.GetProperty("B");
//设置字段值
propertyInfo.SetValue(obj,444);
Console.WriteLine(propertyInfo.GetValue(obj, null));
//获取字段
FieldInfo fieldInfo = type.GetField("a");
//设置字段值
fieldInfo.SetValue(obj, 123);
Console.WriteLine(fieldInfo.GetValue(obj));
Console.WriteLine("================获取所有特性====================");
object[] typeAttributes = type.GetCustomAttributes(false); //获取Example类的特性
foreach (object attribute in typeAttributes)
{
Console.WriteLine("Attributes description is " + attribute.ToString());
//获取特性Description信息
Console.WriteLine($"Description:{attribute.GetType().GetField("Description").GetValue(attribute)}");
}
//获取所有成员
Console.WriteLine("================获取所有成员====================");
MemberInfo[] memberInfos = type.GetMembers();
foreach(var item in memberInfos)
{
Console.WriteLine(item.Name);
}
//获取所有字段(默认公有,可以设置BindingFlags)
Console.WriteLine("================获取所有字段====================");
FieldInfo[] fieldInfos = type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);
foreach (var item in fieldInfos)
{
Console.WriteLine(item.Name);
}
//获取所有属性
Console.WriteLine("================获取所有属性====================");
PropertyInfo[] properties = type.GetProperties();
foreach(var item in properties)
{
Console.WriteLine(item.Name);
}
输出如下图
注意事项
关与Assembly.LoadFrom 方法可参见MSDN
关于Type类:
1)对于 程序 中 用到 的 每一个 类型, CLR 都会 创建 一个 包含 这个 类型 信息 的 Type 类型 的 对象。
2)程序 中 用到 的 每一个 类型 都会 关联 到 独立 的 Type 类 的 对象。
3)不管 创建 的 类型 有 多少 个 实例, 只有 一个 Type 对象 会 关联 到 所有这些 实例。
摘要
Daniel M·Solis. C#图解教程(第4版)(图灵图书) (p. 481). 人民邮电出版社. Kindle 版本.