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

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

http://www.xdnf.cn/news/4194.html

相关文章:

  • [特殊字符] 大模型(LLMs)RAG 版面分析——文本分块面
  • 农经权二轮延包软件—摸底申请表生成
  • 数据库的并发控制
  • nats v2.11.3全新上线!MQTT支持增强、JetStream性能优化、关键BUG修复,构建高效可信消息中间件新时代
  • NV287NV291美光固态闪存NV293NV294
  • Deepseek基础-api key申请及应用(java)、硅基流动api key申请及应用(dify)
  • ThreadLocal源码深度剖析:内存管理与哈希机制
  • Lora原理介绍并用Macbook air超快实现本地微调小模型
  • AI日报 · 2025年5月05日|雅诗兰黛与微软合作成立 AI 创新实验室,加速美妆产品研发与营销
  • 【言语理解】片段阅读之下文推断(6)
  • 设计模式每日硬核训练 Day 18:备忘录模式(Memento Pattern)完整讲解与实战应用
  • 全球化电商平台AWS云架构设计
  • 矩阵置零(中等)
  • 设计模式-基础概念学习总结(继承、多态、虚方法、方法重写)
  • 深入理解块级格式化上下文(BFC)
  • 文本三剑客
  • 字符串匹配 之 拓展 KMP算法(Z算法)
  • 数据集-目标检测系列- 印度人脸 检测数据集 indian face >> DataBall
  • 深度解析:从 GPT-4o“谄媚”到 Deepseek“物理腔”,透视大模型行为模式的底层逻辑与挑战
  • Unity:AddTorque()(增加旋转力矩)
  • uniapp 云开发全集 云数据库
  • JavaScript 笔记 --- part7 --- JS进阶 (part2)
  • 【信息系统项目管理师-论文真题】2008上半年论文详解(包括解题思路和写作要点)
  • Python生活手册-NumPy数组创建:从快递分拣到智能家居的数据容器
  • 互联网大厂Java求职面试:AI大模型与云原生架构设计深度解析
  • 【学习心得】Xtuner模型qlora微调时错误记录
  • 【嘉立创EDA】FPCB(Flexible-PCB)柔性软板设计如何增加补强层
  • 反常积分(广义积分)
  • Redis总结(六)redis持久化
  • C++ 适配器模式详解