C#反射应用之实现动态可配置可扩展框架的简单示例

简介: C#反射应用之实现动态可配置可扩展框架的简单示例

设想一个场景:

我们做了一个项目,最初,只支持MySQL数据库,所以我们一般直接在项目内部定义一个类,并定义其方法

#MySqlHelper.cs
public class MySqlHelper
{
    public void Query()
    {
    }
}

使用上,当然更简单了

//项目最初,只支持MySQL
MySqlHelper mySqlHelper = new MySqlHelper();
mySqlHelper.Query();

 

隔了1个月,产品说版本升级,支持一下SQLServer吧,然后,搞开发的同学,就开始想了,你这么搞,难道我再加一个类不成,也不是不行,就是太low了,不过既然都是和数据库操作相关的类,干脆我就写个接口,定义数据库操作相关方法,然后定义和数据库相关的类来实现这个接口吧,毕竟也是要成为架构师的人嘛,怎能没有这点小想法。

于是,猿A写了一个接口

#IDBHelper.cs
public interface IDBHelper
{
    void Query();
    //void Insert();
    //void Update();
    //void Delete();
}

接着,写了2个类MySQLHelper和SQLServerHelper且都继承该接口

#MySqlHelper.cs
public class MySqlHelper:IDBHelper
{
    public void Query()
    {
    }
}
=======
#SqlServerHelper.cs
public class SqlServerHelper : IDBHelper
{
    public void Query()
    {
        //throw new NotImplementedException();
    }
}

这样,客户是哪个数据库,我就用哪种方式吧。

猿B看到了猿A的写法,大叫一声,“瞎搞”,然后开始了喷水.............

小A啊,一般来说,不同的客户采用不同的数据库,甚至可能采用多个数据库,那么,我们自然不能在代码实现中,将这部分代码写死,如果客户中间要换数据库呢?那不是还得改程序吗?既然我们做产品,当然要做成通用的嘛!像这种情况,配置文件就该派上用场了,我们可以在app.config中指定数据库种类,比如这里,我通过AppSettings节点,添加了一个key值为IDBHelperConfig的项,项内分别保存了类所在的dll和类的名称。

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
    </startup>
  <appSettings>
    <add key="IDBHelperConfig" value="ReflectionDemo,ReflectionDemo.MySqlHelper"/>
  </appSettings>
  <connectionStrings>
    <!--数据库连接字符串-->
    <add name="Customers" connectionString="Data Source=ElevenPC; Database=Customers; User ID=sa; Password=Password; MultipleActiveResultSets=True" providerName="System.Data.SqlClient" />
  </connectionStrings>
</configuration>

我们就可以通过反射动态加载dll,然后实现动态可配置加载方式,到这里,小心思又要来了,反射每次要写那么多代码,如果每次调用都写那么多,那将DRY原则置于何地呀,所以,就把它封装成一个简单工厂吧,这样就看起来完美了,

我们可以把上图内容封装到类SimpleFactory,代码如下

public static class SimpleFactory
{
    //通过配置文件,来决定使用哪种数据库
    static string dllName = ConfigurationManager.AppSettings["IDBHelperConfig"].Split(',')[0];
    static string typeName = ConfigurationManager.AppSettings["IDBHelperConfig"].Split(',')[1];
    public static IDBHelper CreateInstance()
    {
        Assembly assembly = Assembly.Load(dllName);
        Type type1 = assembly.GetType(typeName);
        object o = Activator.CreateInstance(type1);
        IDBHelper dBHelper = o as IDBHelper;
        return dBHelper;
    }
}

这样,操作就简单了,我们只需在调用时,调用工厂类方法,创建对象,然后即可调用相应的Query方法了

IDBHelper dBHelper = SimpleFactory.CreateInstance();
dBHelper.Query();

看上去清爽多了,就跟直接new 类是一样的。

 

那可能有小伙伴要说了,其实我没必要用反射啊,我在配置文件里定义了要使用的数据库类型,那我可以直接在工厂类里将这个值作为参数传入,然后根据这个值来生成相应的类啊,反正最后返回的都是IDBHelper对象。是的,这样的设计确实也没问题,那么,我们这里为什么要如此设计呢?这样做有什么好处呢?其实,是为了实现程序的可扩展,此话怎讲呢?

再来想象一下这个场景,如果,我们现在又要支持Oracle数据库了,按照刚刚提到的这种方式的话,那我们就需要修改源程序,在SimpleFactory类里添加对应的Oracle对象的生成逻辑,使用时在修改配置文件。

而如果是采用的上述方式的话,你发现没,我们只需要将Oracle对象对应的类库文件放到项目路径下,然后通过修改配置文件,即可完成程序的扩展,而基本无需改动源程序的任何代码。那么,你觉得哪种方式更优呢?

其实,说到这里,我们能看出来,之前将MySqlHelper.cs和SqlServerHelper.cs放在项目框架下是不合理的,因为,作为单独的数据库操作类,我们应该将其设计成单独类库,这样不仅代码结构更加合理,而且,能够实现代码的复用和扩展,这是我最终的项目架构图。

这样的话,我们就实现了一个通用的动态加载的可配置可扩展的框架示例。其实应该是挺简单的,主要就是借助反射来实现动态加载和可扩展,借助配置文件来做到可配置。

 

源码我放到了GitHub,有需要的请自取

https://github.com/IronMarmot/Samples/tree/master/MyReflection/ReflectionDemo

最新版本讲解,请关注下方公众号。

相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。 &nbsp; 相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情:&nbsp;https://www.aliyun.com/product/rds/mysql&nbsp;
相关文章
|
存储 监控 算法
基于 C# 时间轮算法的控制局域网上网时间与实践应用
在数字化办公与教育环境中,局域网作为内部网络通信的核心基础设施,其精细化管理水平直接影响网络资源的合理配置与使用效能。对局域网用户上网时间的有效管控,已成为企业、教育机构等组织的重要管理需求。这一需求不仅旨在提升员工工作效率、规范学生网络使用行为,更是优化网络带宽资源分配的关键举措。时间轮算法作为一种经典的定时任务管理机制,在局域网用户上网时间管控场景中展现出显著的技术优势。本文将系统阐述时间轮算法的核心原理,并基于 C# 编程语言提供具体实现方案,以期深入剖析该算法在局域网管理中的应用逻辑与实践价值。
335 5
|
开发框架 安全 .NET
掌握 LINQ:通过示例解释 C# 中强大的 LINQ的集运算
通过本文的示例,我们详细介绍了C#中LINQ的强大集合运算功能。LINQ提供了一种简洁、灵活和类型安全的方式来查询和操作数据集合,从而大大提高了代码的可读性和可维护性。希望本文能帮助读者更好地掌握和应用LINQ,提高开发效率。
398 13
|
程序员 C# 数据库
C# 比较对象新思路,利用反射技术打造更灵活的比较工具
中途接手的项目,碰到需要在更新对象信息时比较并记录差异的需求,最变态的还有附加要求,怎么办?有没有既能满足需求又能对项目影响最小的方法呢?分享这个我封装的方法,一个利用反射技术打造的更灵活的比较工具
337 5
|
存储 安全 物联网
C# 在物联网 (IoT) 应用中的应用
本文介绍了C#在物联网(IoT)应用中的应用,涵盖基础概念、优势、常见问题及其解决方法。重点讨论了网络通信、数据处理和安全问题,并提供了相应的代码示例,旨在帮助开发者更好地利用C#进行IoT开发。
763 3
|
编译器 C#
c# - 运算符<<不能应用于long和long类型的操作数
在C#中,左移运算符的第二个操作数必须是 `int`类型,因此需要将 `long`类型的位移计数显式转换为 `int`类型。这种转换需要注意数据丢失和负值处理的问题。通过本文的详细说明和示例代码,相信可以帮助你在实际开发中正确使用左移运算符。
430 0
|
编译器 C#
c# - 运算符<<不能应用于long和long类型的操作数
在C#中,左移运算符的第二个操作数必须是 `int`类型,因此需要将 `long`类型的位移计数显式转换为 `int`类型。这种转换需要注意数据丢失和负值处理的问题。通过本文的详细说明和示例代码,相信可以帮助你在实际开发中正确使用左移运算符。
428 2
|
编译器 C#
c# - 运算符<<不能应用于long和long类型的操作数
在C#中,左移运算符的第二个操作数必须是 `int`类型,因此需要将 `long`类型的位移计数显式转换为 `int`类型。这种转换需要注意数据丢失和负值处理的问题。通过本文的详细说明和示例代码,相信可以帮助你在实际开发中正确使用左移运算符。
284 3
|
消息中间件 网络协议 安全
C# 一分钟浅谈:WebSocket 协议应用
【10月更文挑战第6天】在过去的一年中,我参与了一个基于 WebSocket 的实时通信系统项目,该项目不仅提升了工作效率,还改善了用户体验。本文将分享在 C# 中应用 WebSocket 协议的经验和心得,包括基础概念、C# 实现示例、常见问题及解决方案等内容,希望能为广大开发者提供参考。
1445 0
|
10月前
|
XML 前端开发 C#
C#编程实践:解析HTML文档并执行元素匹配
通过上述步骤,可以在C#中有效地解析HTML文档并执行元素匹配。HtmlAgilityPack提供了一个强大而灵活的工具集,可以处理各种HTML解析任务。
427 19
|
11月前
|
监控 算法 C#
C#与Halcon联合编程实现鼠标控制图像缩放、拖动及ROI绘制
C#与Halcon联合编程实现鼠标控制图像缩放、拖动及ROI绘制
2354 0