C#中的反射(Reflection)使用经典案例

这篇具有很好参考价值的文章主要介绍了C#中的反射(Reflection)使用经典案例。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


C#中的反射(Reflection)是.NET框架提供的一种强大的运行时元编程机制,它允许程序在运行时获取类型信息、创建对象实例、调用方法、访问字段和属性等,而这些操作在编译时可能是未知的。以下是几个使用反射的典型场景:

1. 动态加载和调用类的方法

假设有一个库包含多个实现了同一接口的类,用户可以通过配置文件指定要使用的具体类名和方法名。通过反射,可以在运行时根据配置加载相应的类型,并调用指定的方法。

// 假设有个接口和其实现类
public interface ICalculator
{
    int Calculate(int a, int b);
}

public class Adder : ICalculator
{
    public int Calculate(int a, int b) => a + b;
}

// 配置中读取类名
string className = "Adder";
Type calculatorType = Type.GetType(className);

// 创建实例并调用方法
ICalculator calculator = (ICalculator)Activator.CreateInstance(calculatorType);
int result = calculator.Calculate(3, 5);

2. 记录用户修改行为

如您提到的应用场景,系统需要记录用户修改了哪个实体类的哪些字段。通过反射,可以遍历实体类的所有属性,在用户修改后记录下变化的属性名和新旧值。

public class User
{
    public string Name { get; set; }
    public int Age { get; set; }
    // 其他属性...
}

// 用户更新了一个User实例
var user = new User { Name = "OldName", Age = 30 };

foreach (var property in properties)
{
    // 获取旧值(假设这是更改前的值)
    var oldValue = property.GetValue(user);

    // 模拟用户更改属性值
    if (property.Name == "Name")
    {
        user.Name = "NewName";
    }

    // 再次获取新值
    var currentValue = property.GetValue(user);

    // 如果旧值与当前值不相等,则记录变更
    if (!object.Equals(oldValue, currentValue) && property.CanRead && property.CanWrite)
    {
        LogChange(property.Name, oldValue, currentValue);
    }
}

3. 调用私有构造函数

反射还可以用来调用非公开的构造函数,比如破坏单例模式时可能会用到:

public sealed class Singleton
{
    private static readonly Singleton instance = new Singleton();

    private Singleton() { }

    public static Singleton Instance => instance;

    // 通过反射破坏单例模式
    public static Singleton CreateAnotherInstance()
    {
        ConstructorInfo ctor = typeof(Singleton).GetConstructor(
            BindingFlags.Instance | BindingFlags.NonPublic,
            null, Type.EmptyTypes, null);
        return (Singleton)ctor.Invoke(null);
    }
}

4. 泛型类型的动态创建和使用

反射结合泛型,可以实现在不知道具体类型参数的情况下动态创建泛型类型实例:

public class GenericClass<T>
{
    public T Value { get; set; }
}

Type genericType = typeof(GenericClass<>).MakeGenericType(typeof(string));
dynamic instance = Activator.CreateInstance(genericType);
instance.Value = "Hello, World!";

C#反射除了上述提到的几个典型应用场景外,还有以下一些常见的用途:

5. 动态类型转换与检查

  • 判断一个对象是否实现了某个接口或继承自某个类。
  • 在不知道具体类型的情况下,将对象动态转换为指定类型。
object obj = new MyDerivedClass();
Type type = obj.GetType();

// 检查类型是否实现了某个接口
bool isDisposable = typeof(IDisposable).IsAssignableFrom(type);

// 动态转换
if (type == typeof(MyDerivedClass))
{
    MyDerivedClass derivedObj = (MyDerivedClass)obj;
    // 使用转换后的对象...
}

6. 获取和设置私有、受保护成员

  • 反射可以访问私有字段、属性和方法,这在测试框架中特别有用,可以模拟对私有成员的调用或者验证其值。
public class MyClass
{
    private int myPrivateField;
    
    public void SetPrivateValue(int value)
    {
        this.myPrivateField = value;
    }
}

var instance = new MyClass();
FieldInfo field = typeof(MyClass).GetField("myPrivateField", BindingFlags.NonPublic | BindingFlags.Instance);
field.SetValue(instance, 42);  // 设置私有字段值

int fieldValue = (int)field.GetValue(instance);  // 获取私有字段值

7. 枚举程序集、模块、类型等信息

  • 在大型应用程序中,可能需要枚举整个程序集中所有类型的元数据信息,比如获取所有的类名、特性(Attributes)等。
Assembly assembly = Assembly.GetExecutingAssembly();
foreach (Type type in assembly.GetTypes())
{
    Console.WriteLine($"Type: {type.FullName}");

    foreach (Attribute attribute in Attribute.GetCustomAttributes(type))
    {
        Console.WriteLine($"  Attribute: {attribute.GetType().Name}");
    }
}

8. 处理泛型类型参数

  • 反射可以帮助获取泛型类型的具体参数类型,并据此创建特定类型的实例。

9. 动态生成代码或动态编译

  • .NET Framework 和 .NET Core 提供了 System.Reflection.Emit 命名空间,允许开发者在运行时动态生成类型和方法。这对于实现AOP(面向切面编程)、动态代理或其他高级编程技术非常有用。

10. 配置驱动的应用程序扩展

  • 反射常用于构建插件式架构,根据配置文件加载不同插件(DLL)并在运行时动态加载并执行插件中的代码。

总之,C#反射是一个强大的工具,它允许程序在运行时获得关于类型和程序集的信息,并基于这些信息进行操作,极大地增强了应用程序的灵活性和适应性。但需要注意的是,过度使用反射可能会降低性能,应谨慎权衡其带来的便利性和潜在的成本。

注意事项:

  • 反射通常会带来性能开销,因为它涉及到运行时类型查找和动态方法调用。
  • 安全性方面,过度依赖反射可能导致代码容易受到攻击,例如绕过私有成员保护机制。
  • 静态编译优化对反射调用可能不适用,因此在对性能敏感的场合应谨慎使用反射。

python推荐学习汇总连接:
50个开发必备的Python经典脚本(1-10)

50个开发必备的Python经典脚本(11-20)

50个开发必备的Python经典脚本(21-30)

50个开发必备的Python经典脚本(31-40)

50个开发必备的Python经典脚本(41-50)
————————————————

​最后我们放松一下眼睛
C#中的反射(Reflection)使用经典案例,c#,unity,游戏引擎文章来源地址https://www.toymoban.com/news/detail-787893.html

到了这里,关于C#中的反射(Reflection)使用经典案例的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 国内外大数据经典案例研究

    大数据时代的来临使得产生的数据量呈爆炸式增长,各行各业均面临着海量数据的分析、处理问题。如何运用大数据技术从海量数据中挖掘出有价值的信息,将是今后企业发展的一个巨大挑战。点评收集研究了国内外大数据应用的经典案例,希望可以对读者有所启示。 1 、塔

    2024年02月05日
    浏览(77)
  • 路由器故障排错三大经典案例

    对于网络管理员来说,熟悉与掌握路由排错的思路和技巧是非常必要的。小编将通过三例典型的路由故障排错案例进行分析。 案例1 不堪重负,路由器外网口关闭 1、网络环境 某单位使用的是Cisco路由器,租用电信30MB做本地接入和l0MB教育网双线路上网,两年来网络运行稳定,

    2024年02月05日
    浏览(48)
  • 经典智能合约案例之发红包

    角色分析:发红包的人和抢红包的人 功能分析: 发红包:发红包的功能,可以借助构造函数实现,核心是将ether打入合约; 抢红包:抢红包的功能,抢成功需要一些断言判断,核心操作是合约转账给抢红包的人; 退还:当红包有剩余的时候,允许发红包的人收回余额,可以

    2024年02月07日
    浏览(46)
  • Python递归的几个经典案例

    当我们碰到诸如需要求阶乘或斐波那契数列的问题时,使用普通的循环往往比较麻烦,但如果我们使用递归时,会简单许多,起到事半功倍的效果。这篇文章主要和大家分享一些和递归有关的经典案例,结合一些资料谈一下个人的理解,也借此加深自己对递归的理解和掌握一

    2024年02月05日
    浏览(48)
  • MySQL学习指南&笔记&经典案例句

    该文章是一篇关于MySQL的一个学习的笔记或是指南,该文章中有很多的经典的案例可进行相应的练习和参考,后期的话会持续更新关于数据库系统方面的文章。 关于综合案例的话可以对该篇文章进行查阅和学习也附加了相应的问题和sql句: MySQL综合应用练习(直接拷贝到自己空

    2024年02月05日
    浏览(48)
  • 阿里后端开发:抽象建模经典案例

    在互联网行业,软件工程师面对的产品需求大都是以具象的现实世界事物概念来描述的,遵循的是人类世界的自然语言,而软件世界里通行的则是机器语言,两者间跨度太大,需要一座桥梁来联通,抽象建模便是打造这座桥梁的关键。基于抽象建模,不断地去粗取精,从现实

    2024年02月09日
    浏览(96)
  • 【入门Flink】- 02Flink经典案例-WordCount

    需求:统计一段文字中,每个单词出现的频次 基本思路:先逐行读入文件数据,然后将每一行文字拆分成单词;接着按照单词分组,统计每组数据的个数。 1.1.数据准备 resources目录下新建一个 input 文件夹,并在下面创建文本文件words.txt words.txt 1.2.代码编写 打印结果如下:(

    2024年02月06日
    浏览(73)
  • C++动态规划经典案例解析之合并石子

    区间类型问题,指求一个数列中某一段区间的值,包括求和、最值等简单或复杂问题。此类问题也适用于动态规划思想。 如 前缀和 就是极简单的区间问题。如有如下数组: 现给定区间信息 [3,6] ,求区间内所有数字相加结果。即求如下图位置数字之和。 Tips: 区间至少包括

    2024年02月11日
    浏览(39)
  • 手搭手Ajax经典基础案例省市联动

    环境介绍 技术栈 springboot+mybatis-plus+mysql 软件 版本 mysql 8 IDEA IntelliJ IDEA 2022.2.1 JDK 1.8 Spring Boot 2.7.13 mybatis-plus 3.5.3.2 pom.xml application.yml配置文件 数据库表 MybatisX逆向工程 逆向工程:通过数据库表接口,逆向生成java工程结构 实体类、mapper接口、mapper映射文件、Service接口、serv

    2024年02月08日
    浏览(43)
  • session 生命周期和经典案例-防止非法进入管理页面

    Session 生命周期-说明 public void setMaxInactiveInterval(int interval) 设置 Session 的超时时间(以秒为单位),超过指定的时长,Session 就会被销毁。 值为正数的时候,设定 Session 的超时时长。 负数表示永不超时 public int getMaxInactiveInterval()获取 Session 的超时时间 public void invalidate() 让当

    2024年02月16日
    浏览(36)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包