欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 财经 > 创投人物 > C# 反射

C# 反射

2025/5/6 14:16:10 来源:https://blog.csdn.net/qq_44809934/article/details/147237148  浏览:    关键词: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、使用反射会模糊程序内部逻辑;程序员希望在源代码中看到程序的逻辑,反射却绕过了源代码的技术,因而会带来维护的问题,反射代码比相应的直接代码更复杂。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词