C# 反射(Reflection)

时间:2023-03-09 17:25:01
C# 反射(Reflection)

什么是反射

发射是 .net framework 提供的一个帮助类库,用于读取和使用元数据。

用到的类:System.Reflection,System.Type。System.Type 类对于反射起着核心的作用。 当反射请求加载的类型时,公共语言运行时将为它创建一个 Type。 您可以使用 Type 对象的方法、字段、属性和嵌套类来查找有关该类型的所有信息。

反射优缺点

优点:

  • 1、反射提高了程序的灵活性和扩展性。
  • 2、降低耦合性,提高自适应能力。
  • 3、它允许程序创建和控制任何类的对象,无需提前硬编码目标类。

缺点:

  • 1、性能问题:使用反射基本上是一种解释操作,用于字段和方法接入时要远慢于直接代码。因此反射机制主要应用在对灵活性和拓展性要求很高的系统框架上,普通程序不建议使用。
  • 2、使用反射会模糊程序内部逻辑;程序员希望在源代码中看到程序的逻辑,反射却绕过了源代码的技术,因而会带来维护的问题,反射代码比相应的直接代码更复杂。

反射的用途

  • 1、它允许在运行时查看特性(attribute)信息。
  • 2、它允许审查集合中的各种类型,以及实例化这些类型。
  • 3、它允许延迟绑定的方法和属性(property)。
  • 4、它允许在运行时创建新类型,然后使用这些类型执行一些任务。
  • 5、MVC的路由就是反射做的。访问的Global的时候,会加载一遍dll

查看元数据

1、获取当前实例的 System.Type 的两种方式

//使用对象 GetType()方法
Rectangle nc = new Rectangle();
Type type = nc.GetType(); //使用 C# typeof 运算符
Type type = typeof(Rectangle);

2、C# 反射(Reflection)查看类中的成员

MemberInfo[] minfos = type.GetMembers();
foreach (var i in minfos)
{
Console.WriteLine("成员: {0}", i.Name);
}

3、查看类中的构造方法

ConstructorInfo[] ci = type.GetConstructors();
foreach (var i in ci)
{
Console.WriteLine("构造函数: {0}", i.Name);
}

4、查看类中的属性

PropertyInfo[] pis = type.GetProperties();
foreach (var i in pis)
{
Console.WriteLine("属性: {0}", i.Name);
}

5、查看类中的字段

FieldInfo[] fis = type.GetFields();
foreach (var i in fis)
{
Console.WriteLine("字段: {0}", i.Name);
}

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

object obj = Activator.CreateInstance(type);// 创建实例
FieldInfo fi = type.GetField("hight");// 取得hight字段
fi.SetValue(obj, );// 给hight字段赋值
PropertyInfo pi1 = type.GetProperty("length");// 取得length属性
pi1.SetValue(obj, , null);// 给length属性赋值
PropertyInfo pi2 = type.GetProperty("width");// 取得width属性
pi2.SetValue(obj, , null);// 给width属性赋值
MethodInfo mi = type.GetMethod("GetVolume");// 取得GetVolume方法
mi.Invoke(obj, null);// 调用GetVolume方法

7、查看类中的特性、

Object[] attributes = type.GetCustomAttributes(false);
foreach (var i in attributes)
{
DeBugInfo dbi = i as DeBugInfo;
if (null != dbi)
{
Console.WriteLine("Bug no: {0}, Message: {1}", dbi.BugNo, dbi.Message);
}
}

8、完整代码

using System;
using System.Reflection;
namespace ConsoleTest
{
// 一个自定义特性 BugFix 被赋给类及其成员
[AttributeUsage(AttributeTargets.Class |
AttributeTargets.Constructor |
AttributeTargets.Field |
AttributeTargets.Method |
AttributeTargets.Property,
AllowMultiple = true)] public class DeBugInfo : System.Attribute
{
private int bugNo;
public string message; public DeBugInfo(int bg)
{
this.bugNo = bg;
} public int BugNo
{
get
{
return bugNo;
}
}
public string Message
{
get
{
return message;
}
set
{
message = value;
}
}
}
/// <summary>
/// 矩形
/// </summary>
[DeBugInfo(, Message = "Return type mismatch")]
[DeBugInfo(, Message = "Unused variable")]
public class Rectangle
{
public int hight = ;
public double length { get; set; }
public double width { get; set; }
public Rectangle()
{
}
public Rectangle(double l, double w)
{
length = l;
width = w;
}
// 计算面积
[DeBugInfo(, Message = "Return type mismatch")]
public void GetArea()
{
Console.WriteLine("面积: {0}", length * width);
}
//计算体积
[DeBugInfo()]
public void GetVolume()
{
Console.WriteLine("体积: {0}", length * width * hight);
}
} class ExecuteRectangle
{
public static void Main12()
{
//使用对象GetType()方法
//Rectangle nc = new Rectangle();
//Type type = nc.GetType(); //使用 C# typeof 运算符
Type type = typeof(Rectangle); // 获取 Rectangle 类的所有成员
Console.WriteLine("\n遍历 Rectangle 类的成员开始---------------");
MemberInfo[] minfos = type.GetMembers();
foreach (var i in minfos)
{
Console.WriteLine("成员: {0}", i.Name);
}
Console.WriteLine("-------------------结束-------------------"); // 获取 Rectangle 类的所有构造函数
Console.WriteLine("\n遍历 Rectangle 类的构造函数开始-----------");
ConstructorInfo[] ci = type.GetConstructors();
foreach (var i in ci)
{
Console.WriteLine("构造函数: {0}", i.Name);
}
Console.WriteLine("-------------------结束-------------------"); // 获取 Rectangle 类的所有属性
Console.WriteLine("\n遍历 Rectangle 类的属性开始---------------");
PropertyInfo[] pis = type.GetProperties();
foreach (var i in pis)
{
Console.WriteLine("属性: {0}", i.Name);
}
Console.WriteLine("-------------------结束-------------------"); // 获取 Rectangle 类的所有public字段
Console.WriteLine("\n遍历 Rectangle 类的字段开始---------------");
FieldInfo[] fis = type.GetFields();
foreach (var i in fis)
{
Console.WriteLine("字段: {0}", i.Name);
}
Console.WriteLine("-------------------结束-------------------"); //用反射生成对象,并调用属性、方法和字段进行操作
Console.WriteLine("\n用反射生成对象,并调用属性、方法和字段进行操作");
object obj = Activator.CreateInstance(type);// 创建实例
FieldInfo fi = type.GetField("hight");// 取得hight字段
fi.SetValue(obj, );// 给hight字段赋值
PropertyInfo pi1 = type.GetProperty("length");// 取得length属性
pi1.SetValue(obj, , null);// 给length属性赋值
PropertyInfo pi2 = type.GetProperty("width");// 取得width属性
pi2.SetValue(obj, , null);// 给width属性赋值
MethodInfo mi = type.GetMethod("GetVolume");// 取得GetVolume方法
mi.Invoke(obj, null);// 调用GetVolume方法
Console.WriteLine("-------------------结束-------------------"); // 遍历 Rectangle 类的特性
Console.WriteLine("\n遍历 Rectangle 类的特性开始---------------");
Object[] attributes = type.GetCustomAttributes(false);
foreach (var i in attributes)
{
DeBugInfo dbi = i as DeBugInfo;
if (null != dbi)
{
Console.WriteLine("Bug no: {0}, Message: {1}", dbi.BugNo, dbi.Message);
}
}
Console.WriteLine("-------------------结束-------------------"); // 遍历 Rectangle 类的方法上的特性(此处只遍历)
Console.WriteLine("\n遍历 Rectangle 类的方法上的特性开始-------");
MethodInfo[] m = type.GetMethods(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly);
foreach (var i in m )
{
foreach (Attribute a in i.GetCustomAttributes(true))
{
DeBugInfo dbi = a as DeBugInfo;
if (null != dbi)
{
Console.WriteLine("Bug no: {0}, for Method: {1}, Message: {2}", dbi.BugNo, i.Name, dbi.Message);
}
}
}
Console.WriteLine("-------------------结束-------------------"); Console.ReadLine();
}
}
} 反射的完整代码

反射的完整代码

运行结果:

C# 反射(Reflection)

System.Reflection.Assembly类

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

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

//通过程序集名称返回Assembly对象
Assembly ass = Assembly.Load("ConsoleTest"); //通过DLL、EXE文件名称返回Assembly对象
Assembly ass = Assembly.LoadFrom("ConsoleTest.exe"); //通过Assembly获取程序集中类
Type t = ass.GetType("ConsoleTest.Rectangle"); //参数必须是类的全名 //通过Assembly获取程序集中所有的类
Type[] types = ass.GetTypes();

相关文章:http://www.runoob.com/csharp/csharp-reflection.html

https://www.cnblogs.com/Kare/p/4601436.html

http://www.cnblogs.com/yaozhenfa/p/CSharp_Reflection_1.html#3826975