当前位置: 首页 > news >正文

C# 反射

概述

        System.Reflection 命名空间中的类与 System.Type 使你能够获取相关加载的程序集和其中定义的类型的信息,如类、接口和值类型等。可以使用反射在运行时创建、调用和访问类型实例。可以调用类型的方法或访问其字段和属性。

知识点

public class Cat
{//无参无返回值public void SayHello(){Console.WriteLine("Hello World!");}//重载方法一:有参有返回值public int Sum(int a,int b){return a + b;   }//重载方法二public int Sum(int a, int b, int c){return a + b + c;}//私有方法private void OnSerect(){Console.WriteLine("私有方法");}//静态方法public static void Speak(){Console.WriteLine("喵喵喵");}//泛型方法public void GenericsMethod<T>(T parm){Console.WriteLine($"类型: {typeof(T)},值: {parm}");}// 包含 ref 参数的方法public void MethodWithRef(ref int value){value *= 2;}// 包含 out 参数的方法public void MethodWithOut(out string result){result = "Hello from out parameter";}// 同时包含 ref 和 out 参数的方法public bool TryParse(string input, ref int value, out string error){if (int.TryParse(input, out value)){error = null;return true;}error = "Invalid number";return false;}
}

加载程序集

        程序集是.NET应用程序的基本构建块,是CLR(公共语言运行时)执行代码的基本单元。在C#中,程序集是编译后的代码和资源的集合,通常以.dll(类库)或.exe(可执行文件)形式在。

方法

描述

Load(String)

通过程序集名称加载Assembly对象

LoadFrom(String)

通过DLL文件名称加载Assembly对象

GetType(String)

通过Assembly获取程序集中类,参数必须是类的全名

GetTypes

通过Assembly获取程序集中所有的类

// 通过程序集名称加载Assembly对象
Assembly assembly = Assembly.Load("First");
// 通过DLL文件名称加载Assembly对象
Assembly assembly = Assembly.LoadFrom("First.dll");
// 通过Assembly获取程序集中的类
Type type = assembly.GetType("First.Cat");
// 通过Assembly获取程序集中所有的类
Type[] t = assembly.GetTypes();

根据类名获取类型并创建实例对象

//第一种方法 使用Type.GetType
Type type = Type.GetType("First.Cat");//第二种方法 使用Assembly.GetType
Assembly assembly = Assembly.Load("First");
Type type = assembly.GetType("First.Cat");var instance = Activator.CreateInstance(type) as Cat;
if (instance == null)
{Console.WriteLine("NO");
}
else
{Console.WriteLine("OK");
}//初始化构造函数
//Cat instance = Activator.CreateInstance(type,666,"旺财") as Cat;

构造函数 

Type type = Type.GetType("First.Cat");//获取类类型
// 根据参数类型获取构造函数 
ConstructorInfo constructor = type.GetConstructor(new Type[] {typeof(int), typeof(string) });
// 构造Object数组,作为构造函数的输入参数 
object[] obj = new object[2] { 666,"旺财" };
// 调用构造函数生成对象 
object animal = constructor.Invoke(obj);
((Cat)animal).SayHello();

方法调用

公共方法

无参方法

Type type = Type.GetType("First.Cat");//获取类类型
Cat instance = Activator.CreateInstance(type) as Cat;//实例化类对象
if (instance != null)
{MethodInfo method = type.GetMethod("SayHello");//获取类中方法Console.WriteLine($"方法名:{method.Name}");Console.WriteLine($"返回值:{method.ReturnType}");method.Invoke(instance, null);
}

有参有返回值方法

Type type = Type.GetType("First.Cat");//获取类类型
Cat instance = Activator.CreateInstance(type) as Cat;//实例化类对象
if (instance != null)
{MethodInfo method = type.GetMethod("Sum");//获取类中方法ParameterInfo[] parameters = method.GetParameters();//获取参数列表foreach (var item in parameters){Console.WriteLine($"参数名:{item.Name}");Console.WriteLine($"参数类型:{item.ParameterType}");}object sum = method.Invoke(instance, new object[] { 1, 2 });Console.WriteLine(sum);
}

私有方法

Type type = Type.GetType("First.Cat");//获取类类型
Cat instance = Activator.CreateInstance(type) as Cat;//实例化类对象
if (instance != null)
{MethodInfo method = type.GetMethod("OnSerect",BindingFlags.NonPublic|BindingFlags.Instance);method.Invoke(instance, null);
}

重载方法

Type type = Type.GetType("First.Cat");//获取类类型
Cat instance = Activator.CreateInstance(type) as Cat;//实例化类对象
if (instance != null)
{// 指定要调用的重载方法的参数类型Type[] paramTypes1 = { typeof(int), typeof(int) };Type[] paramTypes2 = { typeof(int), typeof(int), typeof(int) };MethodInfo method1 = type.GetMethod("Sum", paramTypes1);MethodInfo method2 = type.GetMethod("Sum", paramTypes2);// 调用重载方法var result1 = method1.Invoke(instance, new object[] { 1, 2 });var result2 = method2.Invoke(instance, new object[] { 1,2,3 });Console.WriteLine($"1 + 2 = {result1}");Console.WriteLine($"1 + 2 + 3 = {result2}");
}

静态方法

Type type = Type.GetType("First.Cat");//获取类类型
MethodInfo method = type.GetMethod("Speak");//获取静态方法
// 调用静态方法(第一个参数传null)
method.Invoke(null, null);

泛型方法


Type type = Type.GetType("First.Cat");//获取类类型
Cat instance = Activator.CreateInstance(type) as Cat;//实例化类对象// 获取泛型方法定义
MethodInfo echoMethod = type.GetMethod("GenericsMethod");// 指定具体类型参数
MethodInfo genericEcho = echoMethod.MakeGenericMethod(typeof(string));// 调用方法
genericEcho.Invoke(instance, new object[] { "好好学习" });

包含ref/out参数的方法

Type type = Type.GetType("First.Cat");//获取类类型
Cat instance = Activator.CreateInstance(type) as Cat;//实例化类对象//*************************调用包含ref参数方法*************************
MethodInfo methodWithRef = type.GetMethod("MethodWithRef");
// 准备参数 - ref参数需要是对象数组中的实际变量
int refValue = 5;
object[] refParams = new object[] { refValue };
// 调用方法
methodWithRef.Invoke(instance, refParams);
// 获取修改后的值
int modifiedValue = (int)refParams[0];
Console.WriteLine($"Ref value after call: {modifiedValue}"); // 输出: 10//*************************调用包含out参数方法*************************
MethodInfo methodWithOut = type.GetMethod("MethodWithOut");
// 对于out参数,初始值不重要,但必须提供变量
object[] outParams = new object[] { null }; // out参数初始化为null
// 调用方法
methodWithOut.Invoke(instance, outParams);
// 获取输出值
string outResult = (string)outParams[0];
Console.WriteLine($"Out result: {outResult}"); // 输出: Hello from out parameter//*************************调用包含ref和out参数方法*************************
MethodInfo tryParseMethod = type.GetMethod("TryParse");// 准备参数
string input = "123";
int refValue1 = 0;  // ref参数初始值
string outError = null;  // out参数初始值
object[] parameters = new object[] { input, refValue1, outError };// 调用方法
bool success = (bool)tryParseMethod.Invoke(instance, parameters);// 获取结果
refValue1 = (int)parameters[1];  // ref参数在索引1位置
outError = (string)parameters[2];  // out参数在索引2位置Console.WriteLine($"Success: {success}, Value: {refValue1}, Error: {outError ?? "null"}");
// 输出: Success: True, Value: 123, Error: null

BindingFlags 

         BindingFlags 是 System.Reflection 命名空间中的一个枚举类型,用于精确控制反射操作如何搜索和返回成员(方法、属性、字段等)。

注意事项

1、必须组合至少一个可见性标志(Public/NonPublic)和一个作用域标志(Instance/Static),否则可能返回空结果。

❌ 错误示例:GetMembers(BindingFlags.Instance)(缺少 PublicNonPublic

✅ 正确示例:GetMembers(BindingFlags.Public | BindingFlags.Instance)

2、默认行为:如果不传递 BindingFlagsGetMembers() 默认只返回公共实例成员(等效于 Public | Instance)。

枚举说明

标志

分类

说明

Public

成员可见性控制

包含公共(public)成员

NonPublic

包含非公共成员(privateprotectedinternalprotected internal

Instance

成员作用域控制

包含实例成员(非静态成员)

Static

包含静态成员(static

DeclaredOnly

成员搜索行为控制

仅返回当前类型直接定义的成员(不包括继承的成员)

FlattenHierarchy

返回继承链中所有层级的静态成员(仅对 Static 成员有效)

IgnoreCase

忽略成员名称的大小写(如 "name" 可以匹配 "Name"

ExactBinding

要求参数类型严格匹配(用于方法调用时)

GetField

其他

表示获取字段

SetField

表示设置字段

GetProperty

表示获取属性

SetProperty

表示设置属性

InvokeMethod

表示调用方法

CreateInstance

表示创建实例

Default

默认绑定行为

常见组合示例

(1) 获取所有公共实例成员

var flags = BindingFlags.Public | BindingFlags.Instance;
var members = typeof(MyClass).GetMembers(flags);

(2) 获取私有实例字段

var flags = BindingFlags.NonPublic | BindingFlags.Instance;
var fields = typeof(MyClass).GetFields(flags);

(3) 获取静态成员(包括继承的静态成员)

var flags = BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy;
var members = typeof(DerivedClass).GetMembers(flags);

(4) 获取当前类定义的所有成员(不包含继承的成员)

var flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly;
var members = typeof(MyClass).GetMembers(flags);

(5) 调用私有方法

var flags = BindingFlags.NonPublic | BindingFlags.Instance;
var method = typeof(MyClass).GetMethod("PrivateMethod", flags);
method.Invoke(instance, null);

获取/修改字段和属性

using System;
using System.Reflection;public class DemoClass
{public string PublicField = "Public Field";private int _privateField = 42;public string PublicProperty { get; set; } = "Public Property";private bool PrivateProperty { get; set; } = true;public static string StaticField = "Static Field";private static DateTime StaticProperty { get; set; } = DateTime.Now;
}class Program
{static void Main(){DemoClass instance = new DemoClass();Type type = typeof(DemoClass);// 访问公共字段FieldInfo publicField = type.GetField("PublicField");Console.WriteLine($"PublicField: {publicField.GetValue(instance)}");// 修改私有字段FieldInfo privateField = type.GetField("_privateField", BindingFlags.NonPublic | BindingFlags.Instance);privateField.SetValue(instance, 100);Console.WriteLine($"_privateField: {privateField.GetValue(instance)}");// 访问公共属性PropertyInfo publicProp = type.GetProperty("PublicProperty");publicProp.SetValue(instance, "Modified Value");Console.WriteLine($"PublicProperty: {publicProp.GetValue(instance)}");// 修改私有属性PropertyInfo privateProp = type.GetProperty("PrivateProperty", BindingFlags.NonPublic | BindingFlags.Instance);privateProp.SetValue(instance, false);Console.WriteLine($"PrivateProperty: {privateProp.GetValue(instance)}");// 静态成员访问FieldInfo staticField = type.GetField("StaticField", BindingFlags.Public | BindingFlags.Static);Console.WriteLine($"StaticField: {staticField.GetValue(null)}");PropertyInfo staticProp = type.GetProperty("StaticProperty", BindingFlags.NonPublic | BindingFlags.Static);Console.WriteLine($"StaticProperty: {staticProp.GetValue(null)}");}
}

优缺点

        反射是C#中非常强大的功能,但也需要谨慎使用,因为它会带来性能开销和安全风险。合理使用反射可以极大地提高程序的灵活性和扩展性。

优点:

1、反射提高了程序的灵活性和扩展性。

2、降低耦合性,提高自适应能力。

3、它允许程序创建和控制任何类的对象,无需提前硬编码目标类。

缺点:

1、性能问题:使用反射基本上是一种解释操作,用于字段和方法接入时要远慢于直接代码。因此反射机制主要应用在对灵活性和拓展性要求很高的系统框架上,普通程序不建议使用。

2、使用反射会模糊程序内部逻辑;程序员希望在源代码中看到程序的逻辑,反射却绕过了源代码的技术,因而会带来维护的问题,反射代码比相应的直接代码更复杂。

相关文章:

  • SpringMVC——第7章:HttpMessageConverter
  • 数学复习笔记 2
  • GoogleTest:GMock初识
  • AVL树 和 红黑树 的插入算法
  • 政务服务智能化改造方案和案例分析
  • 浔川AI测试版内测报告
  • 无重复字符的最长子串(3)
  • 第三章 - 软件质量工程体系
  • JAVA在线考试系统考试管理题库管理成绩查询重复考试学生管理教师管理源码
  • QTtricks
  • 神经网络开发实战:从零基础到企业级应用(含CNN、RNN、BP网络代码详解)
  • 开源PDF解析工具Marker深度解析
  • Python-numpy中ndarray对象创建,数据类型,基本属性
  • 2025年企业Radius认证服务器市场深度调研:中小企业身份安全投入产出比最优解
  • 基于CBOW模型的词向量训练实战:从原理到PyTorch实现
  • MySQL基础关键_008_DDL 和 DML(一)
  • 杰理-AC696音箱linein无法插入检测
  • 【C++】grpc(一):安装
  • 探索神经符号系统:医疗AI的范式化进程分析
  • Cursor报错Your request has been blocked解决方案
  • 市场监管总局通报民用“三表”专项检查结果
  • 交通运输部、水利部同日召开会议,深刻汲取贵州游船倾覆事故教训
  • 17家城商行去年年报盘点:西安银行营收增速领跑,青岛银行净利增速领跑
  • 跳水世界杯总决赛陈佳获得女子3米板冠军,陈艺文获得亚军
  • 魔都眼|咖啡节上小孩儿忍不住尝了咖啡香,母亲乐了
  • 5月1日,全社会跨区域人员流动量完成33271.4万人次