反射是程序可以访问、检测、修改它本身状态或行为一种能力。
程序集包括模块,模块包括类型,类型又包括成员。反射可以提供封装程序集、模块和类型的对象。
反射可以动态的创建类型的实例,把类型绑定在现有对象,或从现有对象中获取类型。然后,可以调用类型的方法或访问其字段和属性。

(1)反射dll得到类成员:

在一个未知的dll里面有一个Person类

public class Person
{
private string address;
private string email;

public string Name { set; get; }

public int Age { set; get; }

public void SayHello()
{
Console.WriteLine("你好");
}

public static string MystaticPro { set; get; }
public static void MyStatic()
{
Console.WriteLine("我是static方法");
}
}

通过反射dll得到Person类

static void Main(string[] args)
{
//反射dll
Type type = typeof(Person);
//默认得到类下面的所有public成员
var lstMembers = type.GetMembers();
foreach (var oMem in lstMembers)
{
Console.WriteLine("GetMembers()方法得到的成员名称:" + oMem.Name);
}
Console.WriteLine("");

//默认得到类下面的所有public属性
var lstProperty = type.GetProperties();
foreach (var oProp in lstProperty)
{
Console.WriteLine("GetProperties()方法得到的成员名称:" + oProp.Name);
}
Console.WriteLine("");

Console.ReadKey();
}

得到结果

C#数据结构--反射_封装

 

(2)反射对象的私有字段:

一般私有属性的用法比较少,我们就以私有字段为例来说明,还是上面的例子:

static void Main(string[] args)
{
Type type = typeof(Person);
//默认得到类下面的所有private字段
var lstField = type.GetFields(BindingFlags.NonPublic | BindingFlags.Instance);
foreach (var oField in lstField)
{
Console.WriteLine("GetFields()方法得到的私有字段名称:" + oField.Name);
}

Console.ReadKey();
}

C#数据结构--反射_封装_02

 

(3)反射对象的静态成员:

static void Main(string[] args)
{

Type type = typeof(Person);
//默认得到类下面的所有public成员
var lstMembers = type.GetMembers(BindingFlags.Public | BindingFlags.Static);
foreach (var oMem in lstMembers)
{
Console.WriteLine("GetMembers()方法得到的成员名称:" + oMem.Name);
}

Console.ReadKey();
}

C#数据结构--反射_程序集_03

还有枚举类型等等就不一一介绍了,基本上都是在BindingFlags这个上面做处理。

 

(4)反射得到对象以及对象的操作:

反射得到对象的方法

public static T GetModel<T>(T oModel)
{
var model = default(T) ;

model = (T)Activator.CreateInstance(typeof(T));

return model;
}

(5)反射调用方法

static void Main(string[] args)
{
Type type = typeof(Person);
//动态创建类型的实例
var typeInstance = Activator.CreateInstance(type);
var methodInfo = type.GetMethod("SayHello", BindingFlags.NonPublic | BindingFlags.Public
| BindingFlags.Instance | BindingFlags.InvokeMethod);
if (typeInstance != null)
{
if (methodInfo != null)
{
methodInfo.Invoke(typeInstance, null);
}
}

Console.ReadKey();
}

打印结果,调用SayHello方法

C#数据结构--反射_反射_04

实际项目中的应用

代码是在Unity中实现的,其实,在纯C#环境中,只要把Start方法中的代码放入Main方法中即可。

我们的代码运行在"运行时"为我们创建的AppDomain中,GetAssemblies获取已加载到应用程序域的程序集。

using UnityEngine;
using System;
using System.Reflection;

public class Reflection : MonoBehaviour
{
//反射是程序可以访问、检测、修改它本身状态或行为一种能力。
//程序集包括模块,模块包括类型,类型又包括成员。反射可以提供封装程序集、模块和类型的对象。
//反射可以动态的创建类型的实例,把类型绑定在现有对象,或从现有对象中获取类型。然后,可以调用类型的方法或访问其字段和属性。
void Start()
{
//我们的代码运行在"运行时"为我们创建的AppDomain中
//GetAssemblies获取已加载到应用程序域的程序集。
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
foreach (Assembly assembly in assemblies)
{
Type[] types = assembly.GetTypes();
foreach (Type type in types)
{
var customAttribute = type.GetCustomAttributes(typeof(ConvertToBinary), true);
foreach (var item in customAttribute)
{
var customClass = item as ConvertToBinary;
if (customClass == null)
{
continue;
}
Type typeC = customClass.m_Type;
string methodName = customClass.m_MethodName;
if (typeC == null)
{
Debug.Log("类型为空");
continue;
}
if (string.IsNullOrEmpty(methodName))
{
Debug.Log(typeC.Name + "方法名为空");
}
//动态创建类型的实例
var typeInstance = Activator.CreateInstance(typeC);
var methodInfo = typeC.GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Public
| BindingFlags.Instance | BindingFlags.InvokeMethod);
if (typeInstance != null)
{
if(methodInfo != null)
{
methodInfo.Invoke(typeInstance, null);
}
}
}
}
}
}
}

 创建一个预定义的特性类ConvertToBinary :

特性:描述运行时传递程序中的各种元素(类、方法、结构体等)行为信息的声明性标签一个特性,是放置在它应用元素的前面的方括号来描述的
预定义特性,AttributeUsage是来描述如何使用一个预定义特性类,第一个参数表示可以使用的语言元素,第二个参数表示多用的
[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)]

using System;

//特性:描述运行时传递程序中的各种元素(类、方法、结构体等)行为信息的声明性标签
//一个特性,是放置在它应用元素的前面的方括号来描述的
//预定义特性,AttributeUsage是来描述如何使用一个预定义特性类,第一个参数表示可以使用的语言元素,第二个参数表示多用的
[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)]
public class ConvertToBinary : Attribute
{
public Type m_Type;
public string m_MethodName;

public ConvertToBinary(Type type, string methodName)
{
m_Type = type;
m_MethodName = methodName;
}
}

给多个class元素应用特性:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[ConvertToBinary(typeof(SuitName), "Test1")]
public class SuitName
{
public List<int> nameList = new List<int>();
public string id;
public int num;

public void Test1()
{
Debug.Log("Test1");
}
}

[ConvertToBinary(typeof(UnityTest), "Test2")]
public class UnityTest
{
public List<int> list = new List<int>();
public string id;
public int num;

public void Test2()
{
Debug.Log("Test2");
}
}

输出结果,两个测试方法被调用: 

C#数据结构--反射_字段_05