C#通过反射方法实现依赖注入

这篇具有很好参考价值的文章主要介绍了C#通过反射方法实现依赖注入。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

        看了很多依赖注入的插件,有时候一直在想,是不是都需要定义一个容器来绑定依赖注入的动态库,难道就不能按需注入?我这里的诉求其实很简单,希望注入的实体,在项目中没有任何一个地方是需要强引用的。

        这里以切换关系数据库为例子。我在开发中定义,不允许在数据库中写任何编程性的代码,例如视图、存储过程、方法等,这样做也是为了迁移数据库做准备的,这个是大前提,否则,我接下来举例就没有意义了。我认为,数据库就是提供高速存储服务就足够了。

        在dotnet中,很多orm都支持多种数据库的支持,也都支持大部分的关系数据库,例如Oracle,Mssql,Mysql,Postgresql,Sqlite等,我把不同的数据库操作封装成不同的数据库访问层基类,例如 cyb.DAL.SQLServer,cyb.DAL.Oracle,....类似这样,这些实体都实现接口cyb.IDAL

//mssql的数据库访问实体
public abstract class BaseDAL<T> : IBaseDAL<T>
    where T:class
{
    //orm数据库访问实体
    protected mssqlContext dbContext {get;private set;}
}


接口 
public interface IBaseDAL<T>:IBaseDAL
    where T:class
{
}

所有的DAL基类都实现接口IBaseDAL,那么这里就已经定义好了DAL的规范,包括增删改查等等,再往下派生,定义一个员工表

        namespace cyb.IDAL.Basic

        public interface IDALEmployee : IBaseDAL<Employee>,IDALEmployee

        {

        }

        namespace cyb.DAL.Basic

        public class DALEmployee : BaseDAL<Employee>,IDALEmployee

        {

        }

到此,类DALEmployee和接口IDALEmployee已经产生了关系,且在整个系统中,只存在这么一种关系,DALEmployee是接口IDALEmployee唯一实现实体类。

为了加快搜索注入的程序集,我把程序集cyb.DAL.Basic放到目录 bin\DAL中。

在系统中定义一个IOCHelper工具类,此了要完成两个事情,第一,搜索接口的实现类;第二,缓存完成匹配的实现类;

public static createObject<IObject>(string path="");

参数path:是搜索实现类的位置,例如DAL或者其他什么,这个没有关系了,就是方便搜索,留空是在整个appdomain中搜索,就是第一次的时候会稍微慢一点点,毕竟搜索的程序集会比较多。

在工具类内部定义一个字典容器 Dictionary<Type,Type>,其中key是接口,value是实体类。

方法体也简单,第一步就是找文件,当然是找dll文件,如果你写的程序集后缀不是dll,那么自己改改就好了,这里不贴出代码,其实代码挺多的,后边慢慢分析。大致思路如下:
 

//iType是接口类型
if(cache.TryGetValue(iType,out Type impType)
{
    var imp = Activator.CreateInstance(typ);
    return imp;
}

var dir = new DirectoryInfo(这里是搜索的目录);

var fis = dir.GetFiles("*.dll");

foreach(var fi in fis)

{
    //这里一定要加错误陷进,有时候,搜索到的dll文件不一定是dotnet的程序集,或者导出类时候是有问题的。
    try
    {
        var asm = Assembly.Load(fi.FullName);
        //这里就把实现类找出来了
        var types = asm.GetExportedTypes().Where(t => iType.IsAssignableFrom(t) && !t.IsInterface && t.IsAbstract == false).ToList();
        if(types.Count == 0)
        {            
            //这里报个错,没找到
            return null;
        }
        if(types.Count > 1)
        {
            //这里找到多个实现类,也报个错
            return null;
        }
        cache[iType]=types[0];
        var imp = Activator.CreateInstance(typ);
        return imp;
    }
    catch(Exception ex)
    {
        logHelper.Error(ex);
    }
}

其实代码可以改进一下,先从AppDomain中找已经加载的程序集,没找到再去找dll文件,细节就不提了,这里只是举例而已。

关键一步来了,看java实现注入的写法,挺爽的,于是也就有样学样了,做一个标注。在业务层对象BLLEmployee : IBLLEmployee中定义:

        [Autowire]

        protected IDALEmployee dal;

        创建这个业务层的时候,同时要调用一下createObject<IDALEmployee>("");方法,这个方法怎么调用,也很讲究。其实可以在业务层的基类中发起,为什么要定义成protected?因为基类通过反射找Field是找不到private的,这里也可以优化的,但是涉及到比较复杂的框架设计了,为了这个歌定义讲这么多划不来,呵呵。

        好嘛,控制层(Controler)创建的时候,就创建业务层,那么一层层往下创建,也就能一层层注入了。

        最难的就是调用注入方法createObject<T>(""),我的框架封装好了这些麻烦事,程序员是不需要操心了,只是操碎了我的心。

        在dotnet core中,这种方法好像行不通,好吧,那就网上查看一下微软的文档,找到一个很好的办法,在加载注入dll时候,把依赖的文件也加载进来

        AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(MyResolveEventHandler);

        其中 MyResolveEventHandler方法就是处理加载依赖的事件方法,里边怎么写网上也有代码,抄一下改一下就好了,我是改了很多的。

        另外为了知道注入过程中出错的时候到底发生了什么,要在关键代码处输出最详细的日志,例如加载了哪个dll文件,导出类的时候是什么问题导致失败,创建实体对象的时候是什么原因出现异常等等,总之多写日志就是有好处的,简化了后续的调试,我遇到最多的就是找不到依赖文件,其次就是写实体类的时候,构造函数、属性、成员的初始化有问题,通过记录日志就非常方便的发现问题并能快速解决。一切问题都解决后,日志也就没有了。

        最后,不要尝试对注入的容器做持久化,其实没有什么意义,在没有加载程序集的时候,实现类是不可能呢出现的,持久化重新加载的时候必然报错,不要为了那么一点点时间而干难堪的事情。

        我也用样的方法尝试按常规来做依赖注入,就是使用网上常说的几种方法,都会有些问题,所以我就放弃了,另外,这样的注入方法自己写的,支持Framework和core,在不同架构下使用相同方法,对于程序员来说,没有任何不适。

        在我的框架中,使用反射的机会还是很高的,但是同学们也要自己注意,毕竟IO操作还是有风险的,特别是linux下,要放开权限给程序,这里是相当于一个安全漏洞了,目前我还没更好的方法解决。动态加载文件,也很可能被恶意注入程序,所以,在使用的时候也要确保服务器的安全,我认为那是网管的事情,做一回甩锅侠。

        好了,大致也就这样了,框架的应用就是想要程序员开发代码的时候,不要太过于关注技术问题,把精力都放到两个方面,一个是业务实现,一个是和产品经理斗智斗勇。如果看过我前边写的文章就知道了,我把redis,mq,内部通讯,分布式事务,内存缓存等都封装成了组件。

        我还把与其他微服务交互的操作都封装成了cyb.DAL.Api程序集,当然是针对自己框架的情况下使用,因为这里封装了分布式事务的关键几个操作,程序员就象写一般DAL一样来操作WebApi,查询也是使用lambda。

        谢谢大家关注我的框架设计和开发之旅!文章来源地址https://www.toymoban.com/news/detail-697175.html

到了这里,关于C#通过反射方法实现依赖注入的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • spring如何进行依赖注入,通过set方法把Dao注入到serves

    你在service层后面方法的这些:   最后我们执行一下 :  什么叫做依赖注入,serve应该于Dao的注入我就通过配置文件在容器中注把他注给他: 配置文件:  依赖注入有个简单方法,把properties那个子标签:  就是把这个子标签给省掉他: 1、如何引入,首先打开配置文件: 当我

    2024年02月12日
    浏览(29)
  • 【创建型设计模式】C#设计模式之工厂模式,以及通过反射实现动态工厂。

    题目如下: 简单工厂实现: 上述代码给出了抽象基类的基本定义,和泛型工厂的实现方式,以及调用方式。 值得注意的是 where T : Car, new() 这个条件: where T : Car, new() 是对泛型类型参数 T 的约束。这个约束表明泛型类型参数 T 必须满足两个条件: T 必须是 Car 类或者其派生类

    2024年02月11日
    浏览(26)
  • c#依赖注入

    依赖注入(Dependency Injection,简称 DI)是一种设计模式,用于将对象的创建和管理责任从使用它的类中分离出来,从而实现松耦合和易于测试的代码。在 C# 中,依赖注入通常通过以下方式实现: 构造函数注入(Constructor Injection): 这是最常见的依赖注入方式,通过类的构造

    2024年02月12日
    浏览(26)
  • .NET 通过源码深究依赖注入原理

    依赖注入 (DI) 是.NET中一个非常重要的软件设计模式,它可以帮助我们更好地管理和组织组件,提高代码的可读性,扩展性和可测试性。在日常工作中,我们一定遇见过这些问题或者疑惑。 Singleton服务为什么不能依赖Scoped服务? 多个构造函数的选择机制? 源码是如何识别循环

    2024年02月05日
    浏览(52)
  • C# Blazor 学习笔记(10):依赖注入

    Blazor 具有前后端不分离模式,但是如何直接调用需要一定的设置 依赖注入在spring里面很常见,毕竟.NET 是个巨型融合怪。只要你这个好用我就抄。我还是很佩服的,能实现就行,谁管是谁第一个开发的。MVVM还是WPF首创的呢,Vue用也没关系。能简化程序员逻辑就行。 依赖注入

    2024年02月14日
    浏览(29)
  • 【C#】.net core 6.0 依赖注入生命周期

    给自己一个目标,然后坚持一段时间,总会有收获和感悟! 对于.net core而言,依赖注入生命周期有三种瞬态(Transient)、作用域(Scoped)和单例(Singleton),无论使用哪种生命周期,都需要确保对象的线程安全性,并正确地处理依赖关系。 在了解依赖注入的生命周期前,我

    2024年02月03日
    浏览(38)
  • 通过C#实现矩阵求逆-简单版

    网上大部分C#实现矩阵求逆都比较复杂,现在在这里分享一种很好理解的矩阵求逆方法,而且可以适用于任何形式的可逆矩阵求逆,但是肯定运行效率不如其它的算法,正所谓鱼和熊掌不可兼得。 我们采用的是通过单位矩阵变换的这种方法来实现的,话不多说,下面解释实现

    2024年02月09日
    浏览(25)
  • C# Atrribute和反射的简单例子

    Attribute 需要以Attribute 结尾, 并继承Attribute 结果 : 工厂模式 webAPI应用 更换ConnServiceImpl1为ConnServiceImpl2时, 只需要 换为 使用抽象类: 结果:

    2024年02月13日
    浏览(23)
  • java通过反射创建反射对象三种的方法

    目录 前言: 代码部分: computer类: 1.类名.class创建反射对象: 2.对象.getclass创建反射对象: 3.Class.forName(\\\"\\\")创建反射对象: JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态

    2024年02月14日
    浏览(30)
  • .NET 8最强新功能:键控服务依赖注入

    什么是键控服务依赖注入? 在之前的依赖注入中,服务是根据其类型进行注册和解析的。如果出现同一接口有多个实现怎么办呢?这时候就可以使用.NET 8的新功能“键控服务依赖注入”。它允许您注册接口的多个实现,每个实现都与一个唯一键相关联,然后基于该键解析所需

    2024年02月04日
    浏览(30)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包