为什么我不能将System.IO.Abstractions与Ninject绑定?(Why can't I bind System.IO.Abstractions with Ninject?)

编程入门 行业动态 更新时间:2024-10-22 02:56:30
为什么我不能将System.IO.Abstractions与Ninject绑定?(Why can't I bind System.IO.Abstractions with Ninject?)

我只是学习使用Ninject依赖注入,并使用System.IO.Abstractions来抽象文件系统。 我试图使用Ninject将DirectoryInfoBase绑定到DirectoryInfo如下所示:

IKernel ninject = new StandardKernel(); ninject.Bind<DirectoryInfoBase>().To<DirectoryInfo>();

但我得到了错误

错误1类型'System.IO.DirectoryInfo'不能在泛型类型或方法'Ninject.Syntax.IBindingToSyntax.To()'中用作类型参数'TImplementation'。 没有从'System.IO.DirectoryInfo'到'System.IO.Abstractions.DirectoryInfoBase'的隐式引用转换。 C:\ Users \ Trevor \ Dropbox \ Code \ PhotoOrganiser \ PhotoOrganiser \ Program.cs 13 13 PhotoOrganiserApp

我在这里想念的是什么? 我认为像这样的图书馆的目标是能够执行这些类型的任务吗?

I am just learning to use dependency injection with Ninject, and am using System.IO.Abstractions to abstract the filesystem. I am trying to use Ninject to bind DirectoryInfoBase to DirectoryInfo as so:

IKernel ninject = new StandardKernel(); ninject.Bind<DirectoryInfoBase>().To<DirectoryInfo>();

But am getting the error

Error 1 The type 'System.IO.DirectoryInfo' cannot be used as type parameter 'TImplementation' in the generic type or method 'Ninject.Syntax.IBindingToSyntax.To()'. There is no implicit reference conversion from 'System.IO.DirectoryInfo' to 'System.IO.Abstractions.DirectoryInfoBase'. C:\Users\Trevor\Dropbox\Code\PhotoOrganiser\PhotoOrganiser\Program.cs 13 13 PhotoOrganiserApp

What am I missing here? I thought the goal of libraries such as this was to be able to perform these sorts of tasks?

最满意答案

System.IO.Abstractions正在使用适配器模式 。 它是一种技巧,用于某些类型,没有任何抽象(抽象类或接口),以便与DI一起使用它们。 由于无法在.NET中向现有类型添加抽象,因此创建了一个包装器(适配器),它具有抽象(在本例中为抽象类),以便用于松散地耦合实现。

这里的问题是你没有使用包装器,你直接使用实现。

IKernel ninject = new StandardKernel(); ninject.Bind<DirectoryInfoBase>().To<DirectoryInfoWrapper>() .WithConstructorArgument("instance", new DirectoryInfo(@"C:\Somewhere\"));

但是,这里还有另一个问题 - DirectoryInfo需要一个目录路径作为构造函数参数。 因此,这意味着使用抽象工厂通常更有意义,因此可以在目录路径已知时在运行时创建它。 在这种情况下,将工厂注入服务然后调用方法在运行时创建实例更有意义。 System.IO.Abstractions的作者使工厂内部,但你可以建立一个相同的。

[Serializable] public class DirectoryInfoFactory : IDirectoryInfoFactory { public DirectoryInfoBase FromDirectoryName(string directoryName) { var realDirectoryInfo = new DirectoryInfo(directoryName); return new DirectoryInfoWrapper(realDirectoryInfo); } } public class SomeService : ISomeService { private readonly IDirectoryInfoFactory directoryInfoFactory; public SomeService(IDirectoryInfoFactory directoryInfoFactory) { if (directoryInfoFactory == null) throw new ArgumentNullException("directoryInfoFactory"); this.directoryInfoFactory = directoryInfoFactory; } public void DoSomething() { // The directory can be determined at runtime. // It could, for example, be provided by another service. string directory = @"C:\SomeWhere\"; // Create an instance of the DirectoryInfoWrapper concrete type. DirectoryInfoBase directoryInfo = this.directoryInfoFactory.FromDirectoryName(directory); // Do something with the directory (it has the exact same interface as // System.IO.DirectoryInfo). var files = directoryInfo.GetFiles(); } }

然后配置容器以注入可以创建多个运行时实例而不是单个实例的工厂。

IKernel ninject = new StandardKernel(); ninject.Bind<IDirectoryInfoFactory>().To<DirectoryInfoFactory>();

但System.IO.Abstractions的作者还有另一个技巧,它将它更进了一步。 他创建了一个可以注入的聚合服务 ,并以松散耦合的方式提供System.IO命名空间中提供的许多类型的服务。

因此,您可以改为注入现有的IFileSystem服务,而不是创建自己的工厂,以便访问System.IO命名空间提供的几乎任何服务。

public class SomeService : ISomeService { private readonly IFileSystem fileSystem; public SomeService(IFileSystem fileSystem) { if (fileSystem == null) throw new ArgumentNullException("fileSystem"); this.fileSystem = fileSystem; } public void DoSomething() { // The directory can be determined at runtime. // It could, for example, be provided by another service. string directory = @"C:\SomeWhere\"; // Create an instance of the DirectoryInfoWrapper concrete type. DirectoryInfoBase directoryInfo = this.fileSystem.DirectoryInfo.FromDirectoryName(directory); // Do something with the directory (it has the exact same interface as // System.IO.DirectoryInfo). var files = directoryInfo.GetFiles(); } }

然后,您将配置容器只是为了注入IFileSystem以获得System.IO的所有功能。

IKernel ninject = new StandardKernel(); ninject.Bind<IFileSystem>().To<FileSystem>();

System.IO.Abstractions is using the Adapter Pattern. It is a trick used for certain types that don't have any abstraction (abstract class or interface) in order to use them with DI. Since there is no way to add an abstraction to an existing type in .NET, a wrapper (adapter) is created which has an abstraction (in this case, an abstract class) in order to use to loosely couple the implementation.

The problem here is that you are not using the wrapper, you are using the implementation directly.

IKernel ninject = new StandardKernel(); ninject.Bind<DirectoryInfoBase>().To<DirectoryInfoWrapper>() .WithConstructorArgument("instance", new DirectoryInfo(@"C:\Somewhere\"));

However, there is another gotcha here - DirectoryInfo requires a directory path as a constructor argument. So this means it typically makes more sense to use an Abstract Factory so it can be created at runtime when the directory path is known. In this case, it makes more sense to inject the factory into your service and then call the method to create the instance at runtime. The author of System.IO.Abstractions made the factory internal, but you can build one just the same.

[Serializable] public class DirectoryInfoFactory : IDirectoryInfoFactory { public DirectoryInfoBase FromDirectoryName(string directoryName) { var realDirectoryInfo = new DirectoryInfo(directoryName); return new DirectoryInfoWrapper(realDirectoryInfo); } } public class SomeService : ISomeService { private readonly IDirectoryInfoFactory directoryInfoFactory; public SomeService(IDirectoryInfoFactory directoryInfoFactory) { if (directoryInfoFactory == null) throw new ArgumentNullException("directoryInfoFactory"); this.directoryInfoFactory = directoryInfoFactory; } public void DoSomething() { // The directory can be determined at runtime. // It could, for example, be provided by another service. string directory = @"C:\SomeWhere\"; // Create an instance of the DirectoryInfoWrapper concrete type. DirectoryInfoBase directoryInfo = this.directoryInfoFactory.FromDirectoryName(directory); // Do something with the directory (it has the exact same interface as // System.IO.DirectoryInfo). var files = directoryInfo.GetFiles(); } }

And then configure the container to inject a factory that can create multiple runtime instances rather than a single instance.

IKernel ninject = new StandardKernel(); ninject.Bind<IDirectoryInfoFactory>().To<DirectoryInfoFactory>();

But there is another trick the author of System.IO.Abstractions used to take it a step further. He made an Aggregate Service that can be injected and provide many of the services that types in the System.IO namespace provide in a loosely-coupled way.

So, rather than making your own factory, you could instead inject the existing IFileSystem service in order to gain access to virtually any of the services the System.IO namespace provides.

public class SomeService : ISomeService { private readonly IFileSystem fileSystem; public SomeService(IFileSystem fileSystem) { if (fileSystem == null) throw new ArgumentNullException("fileSystem"); this.fileSystem = fileSystem; } public void DoSomething() { // The directory can be determined at runtime. // It could, for example, be provided by another service. string directory = @"C:\SomeWhere\"; // Create an instance of the DirectoryInfoWrapper concrete type. DirectoryInfoBase directoryInfo = this.fileSystem.DirectoryInfo.FromDirectoryName(directory); // Do something with the directory (it has the exact same interface as // System.IO.DirectoryInfo). var files = directoryInfo.GetFiles(); } }

You would then configure the container just to inject IFileSystem to gain all of the functionality of System.IO.

IKernel ninject = new StandardKernel(); ninject.Bind<IFileSystem>().To<FileSystem>();

更多推荐

本文发布于:2023-08-07 02:40:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1458893.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:我不   能将   绑定   System   IO

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!