C# NuGet包库中的依赖注入
这是基于本问题中讨论的概念 我正在从事一个使用Castle.Windsor进行DI的项目,并引用了几个定制的NuGet包。我已经在通过NuGet引用的一个类库(我们称之为MyNugetLib)中安装了Castle.Windsor,并且在该库中的IWindsorContainer上定义了一个扩展方法,该方法注册本地服务C# NuGet包库中的依赖注入,c#,dependency-injection,inversion-of-control,castle-windsor,C#,Dependency Injection,Inversion Of Control,Castle Windsor,这是基于本问题中讨论的概念 我正在从事一个使用Castle.Windsor进行DI的项目,并引用了几个定制的NuGet包。我已经在通过NuGet引用的一个类库(我们称之为MyNugetLib)中安装了Castle.Windsor,并且在该库中的IWindsorContainer上定义了一个扩展方法,该方法注册本地服务 public static class WindsorContainerExtensions { public static void RegisterMyNugetLi
public static class WindsorContainerExtensions
{
public static void RegisterMyNugetLibServices(this IWindsorContainer container)
{
container.RegisterLocalServices();
}
private static void RegisterLocalServices(this IWindsorContainer container)
{
container.Register(...)
}
}
引用此NuGet包(我们称之为MyProj)的项目也使用Windsor,并在安装程序中调用NuGet包中定义的扩展方法。这一切都有效。
我的问题是如何将Windsor容器引用从MyProj传递到MyNugetLib?我曾尝试将IWindsorContainer注入到我需要的类的构造函数中,但该类使用如下惰性实例化:
private static readonly Lazy<MyClass> LazyInstance = new Lazy<MyClass>(() => new MyClass());
private MyClass() {}
public static MyClass Instance => LazyInstance.Value;
Lib.MyClass.Instance
我成功完成这项工作的唯一方法是在MyClass中公开一个公共属性,该属性在MyProj中用于设置WindsorContainer
public IWindsorContainer DIContainer { get; set; }
在MyProj中
Lib.MyClass.DIContainer = MyProj.WindsorContainer
namespace MyProj
{
public class WindsorInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
// enable registration of lazy services
container.Register(Component.For<ILazyComponentLoader>().ImplementedBy<LazyOfTComponentLoader>());
container.Register(Classes.FromAssemblyContaining(typeof(MyNugetLib.DI.IMyNugetLibSingleton)).BasedOn<MyNugetLib.DI.IMyNugetLibSingleton>().WithService.FromInterface().LifestyleSingleton());
container.Register(Classes.FromAssemblyContaining(typeof(MyNugetLib.DI.IMyNugetLibTransient)).BasedOn<MyNugetLib.DI.IMyNugetLibTransient>().WithService.FromInterface().LifestyleTransient());
// register local services
}
}
public class MyLocalClass : IMyLocalClass
{
private Lazy<MyNugetLib.IMyClass> myNugetLibLazyService
public MyLocalClass(Lazy<MyNugetLib.IMyClass> lazyService)
{
this.myNugetLibService = lazyService;
}
internal MyLocalType DoSomethingHere()
{
this.myNugetLibService.Value.DoSomething();
// etc
}
}
}
我不是特别喜欢这个。有更好的方法吗
更新:(感谢insane_开发者的建议) 问题是:如何在惰性构造函数中注入依赖项?如果我能做到这一点,那么我就可以从MyNugetLib中删除对Windsor的依赖 所以我会
private IService1 service1;
private IService2 service2;
private MyClass(IService1 myService1, IService2 myService2)
{
this.service1 = myService1;
this.service2 = myService2
}
public static MyClass Instance => LazyInstance.Value;
private static readonly Lazy<MyClass> LazyInstance = new Lazy<MyClass>(() => new MyClass(???));
专用iSeries服务1;
私人IService2服务2;
私有MyClass(IService1 myService1、IService2 myService2)
{
this.service1=myService1;
this.service2=myService2
}
公共静态MyClass实例=>LazyInstance.Value;
private static readonly Lazy Lazy实例=new Lazy(()=>new MyClass(???));
如何编写上面的func,使其在构造函数中注入依赖项?我从未使用Castle.Windsor,但我认为它与其他容器类似。您实际上不需要将对容器的引用传递到库中。您应该能够在主应用程序中配置所有映射,该应用程序具有对库的引用。如果你按照你的建议去做,你将对Castle.Windsor有一个具体的依赖,这不是一个好主意。多亏了@Inasane\u developer的建议,我能够以一种更干净的方式来做这件事。 问题是MyNugetLib使用的是使用
Lazy
创建的静态单例。依赖项不能注入到那些构造函数中,因此我试图找到一种好方法来传递对DI容器的引用。不管如何,它在MyNugetLib中引入了对DI包的直接依赖,这并不好。更好的解决方案是在MyNugetLib中一致地使用依赖项注入,使用静态单例重构类,使普通构造函数具有注入的依赖项,并从主应用程序(MyProj)注册这些依赖项。为了做到这一点,我必须重构MyProj使用一些MyNugetLib类的方式,这样它就不再通过静态属性引用单例,而是通过注入依赖项引用单例,注入依赖项在主DI容器中注册为单例,注入为惰性依赖项。
这就是我(概念上)所做的
然后,在MyProj中
namespace MyProj
{
public class WindsorInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
// enable registration of lazy services
container.Register(Component.For<ILazyComponentLoader>().ImplementedBy<LazyOfTComponentLoader>());
container.Register(Classes.FromAssemblyContaining(typeof(MyNugetLib.DI.IMyNugetLibSingleton)).BasedOn<MyNugetLib.DI.IMyNugetLibSingleton>().WithService.FromInterface().LifestyleSingleton());
container.Register(Classes.FromAssemblyContaining(typeof(MyNugetLib.DI.IMyNugetLibTransient)).BasedOn<MyNugetLib.DI.IMyNugetLibTransient>().WithService.FromInterface().LifestyleTransient());
// register local services
}
}
public class MyLocalClass : IMyLocalClass
{
private Lazy<MyNugetLib.IMyClass> myNugetLibLazyService
public MyLocalClass(Lazy<MyNugetLib.IMyClass> lazyService)
{
this.myNugetLibService = lazyService;
}
internal MyLocalType DoSomethingHere()
{
this.myNugetLibService.Value.DoSomething();
// etc
}
}
}
名称空间MyProj
{
公共类WindsorInstaller:IWindsorInstaller
{
public void安装(IWindsorContainer、IConfigurationStore)
{
//启用惰性服务的注册
container.Register(Component.For().ImplementedBy());
container.Register(Classes.FromAssemblyContaining(typeof(MyNugetLib.DI.IMyNugetLibSingleton)).BasedOn().WithService.FromInterface().LifestyleSingleton());
container.Register(Classes.FromAssemblyContaining(typeof(MyNugetLib.DI.IMyNugetLibTransient)).BasedOn().WithService.FromInterface().LifestyleTransient());
//注册本地服务
}
}
公共类MyLocalClass:IMyLocalClass
{
私有惰性myNugetLibLazyService
公共MyLocalClass(懒惰懒散服务)
{
this.myNugetLibService=lazyService;
}
内部MyLocalType DoSomethingHere()
{
this.myNugetLibService.Value.DoSomething();
//等
}
}
}
使用IMyNugetLibSingleton
和IMyNugetLibTransient
我能够用一个register
语句注册实现这些的所有类。
我现在已经将“懒散”从MyNugetLib移到了MyProj。注入的依赖项myNugetLibLazyService仅在需要时解析。MyNugetLib的依赖项现在可以由使用者选择使用任何DI contanier来解析
我对这个解决方案很满意,但如果有人有更好的想法,我仍然愿意接受建议。我要指出的是,在singleton类中使用公共构造函数完全违背了它作为singleton的目的。你是对的。我会改变的。谢谢我不明白Lib.MyClass.DIContainer的目的是什么,你能再解释一遍吗?它在Lib.MyClass中用于解析本地服务。例如,[code]内部IMyLibService服务{get{if(this.myLibService==null){this.myLibService=this.DIContainer.Resolve();}返回this.myLibService;}}}[/code]@erionpc不使用静态字段,相反,创建一个类似MyClassProvider的类,将Instance和LazyInstance作为实例字段(所以不是静态的)。然后将这个类注册为singleton并将容器传递给这个Classic。我希望MyNugetLib独立于MyProj,注册自己的服务,并且不依赖于MyProj中定义的DI容器,但我不确定这是否可行。Thanks@erionpc我真的不知道这是个多好的主意,但我想这是可能的。大概