上篇文章讲述了C#异常处理知识点,本文将介绍C#反射的知识点。反射(Reflection)是C#中一个强大而复杂的特性,它允许开发人员在运行时获取和操作程序集、类型和对象的信息。本文将介绍C#反射的一些知识点,希望对大家开发有一定的帮助。
1、 什么是反射?
首先了解一下概念,官方介绍“System.Reflection 命名空间中的类与 System.Type 使你能够获取有关加载的程序集和其中定义的类型的信息,如类、接口和值类型(即结构和枚举)。可以使用反射在运行时创建、调用和访问类型实例“。通俗的讲反射是C#中的一项技术,允许开发人员在运行时访问和操作程序集、类型和对象的信息。通过反射,您可以动态加载程序集、创建对象实例、调用方法、访问属性和字段,甚至在不知道类型的情况下操作对象。
2、使用反射获取类型信息
使用反射可以获取有关类型的各种信息,例如名称、命名空间、基类、属性、方法和字段。获取类的信息可以做扩展开发,比如ORM的EF框架里就用了大量的反射来获取类的信息(早前版本)。以下是一些常用的反射方法:
Type type = typeof(TestClass); // 获取类型
string typeName = type.FullName; // 获取类型的完整名称
Type baseType = type.BaseType; // 获取基类类型
PropertyInfo[] properties = type.GetProperties(); // 获取属性信息
MethodInfo[] methods = type.GetMethods(); // 获取方法信息
FieldInfo[] fields = type.GetFields(); // 获取字段信息
Console.WriteLine($"获取类型的完整名称:{ typeName}");
Console.WriteLine($"获取基类类型:{baseType.Name}");
Console.WriteLine("获取第一个属性信息:"+properties.FirstOrDefault());
Console.WriteLine("获取第一个方法信息:" + methods.FirstOrDefault());
Console.WriteLine("获取第一个字段信息:" + fields.FirstOrDefault());
//下面是这个类
public class TestClass
{
public static string TestName;
public string Name { get; set; }
public string Description { get; set; }
public string Get()
{
return "DOTNET开发跳槽";
}
}
输出结果如下:
为啥第一个方法是get_Name()不是Get(),因为属性底层也是方法,只不过C#给简化了而已。
3、创建对象实例、调用方法和访问属性
通过反射,您可以在代码运行时创建对象的实例。这对于在不知道类型的情况下实例化对象非常有用。
//TestClass案例跟第一个的类相同
Type type = typeof(TestClass);
object instance = Activator.CreateInstance(type);
// 调用无参数方法
MethodInfo methodInfo1 = types.GetMethod("Get");
string result = methodInfo1.Invoke(instance, null).ToString();
Console.WriteLine($"方法打印结果:{result}");
// 调用有参数方法,大家自己研究一下
//获取属性值
PropertyInfo property = type.GetProperty("Name");
object value = property.GetValue(instance);
//由于未赋值,结果是null,这里就不打印了。
效果如下:
4、获取当前程序集信息
反射还允许您获取程序集的信息,包括版本号、公共密钥令牌和引用的其他程序集。通过获取程序集,你可以分析当前程序的调用情况等信息。
Assembly assembly = Assembly.GetExecutingAssembly(); // 获取当前程序集
string assemblyName = assembly.GetName().Name; // 获取程序集名称
Version version = assembly.GetName().Version; // 获取程序集版本
byte[] publicKeyToken = assembly.GetName().GetPublicKeyToken(); // 获取公共密钥令牌
var referencedAssemblies = assembly.GetReferencedAssemblies(); // 获取引用的程序集列表
//大家可以自行打印出来,比如上面的程序集assemblyName输出为Test8
5、 使用反射处理自定义特性
反射允许您检查和处理在代码中定义的自定义特性。特性是元数据,它可以用于为类型、方法、属性等添加元信息。
//Main里的调用 类和自定义特性在下面
Type type = typeof(TestClass);
MyCustomAttribute attribute = (MyCustomAttribute)Attribute.GetCustomAttribute(type, typeof(MyCustomAttribute));
if (attribute != null)
{
// 处理特性信息,这里打印特性
Console.WriteLine("特性的值: " + attribute.Description);
}
//自定义特性
sealed class MyCustomAttribute : Attribute
{
public string Description { get; }
public MyCustomAttribute(string description)
{
Description = description;
}
}
//使用特性
[MyCustomAttribute("输入名字!!")]
public class TestClass
{
public string Name { get; set; }
}
输出结果:
当然也可以获得方法的特性,需要通过反射后的GetMethods获取所有方法,然后遍历方法并通过上面的方式获取特性的值或者执行处理逻辑。
6、 泛型反射
泛型反射是一种用于操作泛型类型和方法的反射技术。通过泛型反射,您可以动态地创建和操作泛型类型的实例,调用泛型方法,以及检查泛型类型的参数。这是泛型的高级用法,使用频率不是很高。
// 获取泛型类型 List<> 的类型信息
Type genericType = typeof(List<>);
// 定义泛型类型的类型参数(这里是 int)
Type[] typeArgs = { typeof(int) };
// 使用 MakeGenericType 方法创建泛型类型的实例
Type constructedType = genericType.MakeGenericType(typeArgs);
// 使用 Activator.CreateInstance 方法创建泛型类型的对象实例
object instance = Activator.CreateInstance(constructedType);
// 向列表添加数据
dynamic list = instance; // 使用 dynamic 类型来调用泛型列表的 Add 方法
list.Add(2);
list.Add(3);
list.Add(7);
// 使用泛型列表进行数据处理
int sum = 0;
foreach (int item in list)
{
sum += item;
}
Console.WriteLine("求和值: " + sum );
//输出结果:12
7、 程序集加载
程序集加载是反射中的一个关键概念,它涉及将程序集加载到应用程序域中以供使用。您可以使用Assembly.Load系列方法来加载程序集,还可以实现自定义的程序集加载逻辑。通常来获得引用类库项目和引用的dll序集文件。
Assembly assembly = Assembly.Load("MyAssembly");
Type type = assembly.GetType("MyNamespace.MyClass");
//接下来就可以调用以上类的方法了,调用方法跟前面的调用方法一致
8、反射注意事项
性能和安全问题:尽管反射功能非常强大,性能和安全也是它的诟病。反射操作通常比直接调用代码要慢,并且可能导致性能下降。此外,反射可以访问私有成员和执行敏感操作,因此必须谨慎使用,并且需要足够的权限。对于性能和安全要求高的项目尽量不使用反射。
避免滥用反射:反射是一把双刃剑。尽管它可以解决某些问题,但滥用反射可能导致代码的可读性下降,并增加调试和维护的难度。在编写代码时,应仔细考虑是否真的需要使用反射来解决问题,是否有更好的替代方案。比如.NET的AOT打包发布方式也不支持反射代码,因为反射是运行时编译。
了解性能优化技巧:如果您必须使用反射,可以采取一些性能优化措施,例如缓存类型信息以减少反射调用的开销,或使用委托来加速方法调用。
结语
本文讲述了C#反射的一些知识点,比如获取类型、获取程序集,这些知识点都是.NET开发应该掌握的。反射不仅可以帮助您实现某些动态和通用的编程任务,还可以加强您的调试和开发技能。
希望本文提供的C#反射知识对每个.NET开发者都有所帮助,对于C#反射的知识点,你还知道哪些?欢迎留言讨论或者吐槽本文。
参考:
1、微软官网:
learn.microsoft.com/zh-cn/dotnet/framework/reflection-and-codedom/reflection
2、AI查询
推荐阅读
来源公众号:DotNet开发跳槽❀