使用 DryIoc 替换 Abp 的 DI 框架 (2)

做了这个改动之后,剩下的就是需要针对注册与解析方法进行一些改动了,因为 IocManger 提供的注册与解析方法也是调用的具体 Ioc 容器所提供的方法,而 IWindsorContainer 提供的,DryIoc 的 IContainer 基本上也都有提供 ,只是个别特殊的方法有一些不同而已。

下面是改造完成的部分注册与解析接口(详细的可以查看 Github 代码):

public void Register(Type type, DependencyLifeStyle lifeStyle = DependencyLifeStyle.Singleton) { IocContainer.Register(type,ApplyLifestyle(lifeStyle)); } // ... 其他接口 public void Register(Type type, Type impl, DependencyLifeStyle lifeStyle = DependencyLifeStyle.Singleton) { if (type == impl) { // 这里通过 made 参数指定了解析对象时优先解析带有参数的构造函数 IocContainer.Register(type,impl,ApplyLifestyle(lifeStyle), made: Made.Of(FactoryMethod.ConstructorWithResolvableArguments)); RegisterTypeEventHandler?.Invoke(this,type,impl); } else { IocContainer.RegisterMany(new[] { type, impl }, impl, made: Made.Of(FactoryMethod.ConstructorWithResolvableArguments), reuse: ApplyLifestyle(lifeStyle)); RegisterTypeEventHandler?.Invoke(this,type,impl); RegisterTypeEventHandler?.Invoke(this,impl,impl); } } // ... 其他接口

这里需要注意一点的是带参数的解析方法 public T Resolve<T>(object argumentsAsAnonymousType) ,DryIoc 与 Castle Windsor 不同的是,它能够接收的只能是参数数组,而不能接收一个参数集合的匿名对象。所以我们需要将入参改为 object[] ,当然也因为变更了方法签名,所以我们需要更改 ScopedIocResolver、IIocResolver、IocResolverExtensions 定义里面带参数的解析方法签名。

public T Resolve<T>(object[] argumentsAsAnonymousType) { return IocContainer.Resolve<T>(argumentsAsAnonymousType); }

其次,还有一个 public T[] ResolveAll<T>() 内部调用了 IocContainer.ResolveAll 方法,而 DryIoc 是没有提供这个方法的,但是有一个 ResolveMany() 方法是一样的作用。下面是进行更改之后的 ResolveAll() 方法的所有重载:

///<inheritdoc/> public T[] ResolveAll<T>() { return IocContainer.ResolveMany<T>().ToArray(); } ///<inheritdoc/> public T[] ResolveAll<T>(object[] argumentsAsAnonymousType) { return IocContainer.ResolveMany<T>(args:argumentsAsAnonymousType).ToArray(); } ///<inheritdoc/> public object[] ResolveAll(Type type) { return IocContainer.ResolveMany(type).ToArray(); } ///<inheritdoc/> public object[] ResolveAll(Type type, object[] argumentsAsAnonymousType) { return IocContainer.ResolveMany(type, args:argumentsAsAnonymousType).ToArray(); }

除了解析方法之外,还有对象释放的方法 Release,由于 DryIoc 没有提供释放方法,所以这里只能显式地调用对象的 Dispose() 方法来进行释放。

public void Release(object obj) { if(obj is IDisposable disposeObj) { disposeObj.Dispose(); } }

做了以上变更之后,还有一个地方在提示错误:

public void RegisterAssemblyByConvention(Assembly assembly, ConventionalRegistrationConfig config) { var context = new ConventionalRegistrationContext(assembly, this, config); foreach (var registerer in _conventionalRegistrars) { registerer.RegisterAssembly(context); } if (config.InstallInstallers) { // 这里仍然使用了 IWindsorContainr 的方法 IocContainer.Install(FromAssembly.Instance(assembly)); } }

看过博主之前更新的 Abp 源码分析的同学应该知道,这个 Install() 的作用其实很简单,就是直接遍历指定程序集的类型,查找是否有实现了 IWindsorInstaller 接口的对象,如果有则调用其 Install() 方法。而在其 Install() 方法里面,一般都是通过传入的 IIocContainer 或者是 IIocManager 对象来进行组件注册的功能。

在这里,我们可以针对 IocManager 写两个扩展方法 Intsall() 和一个 IDryIocInstaller 接口用于实现相似的功能。

namespace Abp.Dependency { public interface IDryIocInstaller { void Install(IIocManager iocManager); } }

扩展方法:

using System; using System.Linq; using System.Reflection; namespace Abp.Dependency { public static class IocManagerExtensions { public static void Install(this IIocManager iocManager,IDryIocInstaller installer) { installer.Install(iocManager); } public static void Install(this IIocManager iocManager, Assembly assembly) { // 获得指定程序集内部所有的 Installer 类型 var installers = assembly.GetTypes().Where(type => type.GetInterfaces().Any(@interface => @interface == typeof(IDryIocInstaller))); // 遍历类型并通过 Activator 进行构造并调用 foreach (var installer in installers) { (Activator.CreateInstance(installer) as IDryIocInstaller)?.Install(iocManager); } } } }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpyypz.html