2015-01-10 41 views
0

我只是学习使用依赖注入与Ninject,并使用System.IO.Abstractions抽象文件系统。我试图用Ninject绑定DirectoryInfoBaseDirectoryInfo像这样:为什么我无法将System.IO.Abstractions与Ninject绑定?

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

但正在错误

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

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

回答

4

System.IO.Abstractions正在使用Adapter Pattern。这是一种用于某些没有任何抽象(抽象类或接口)的类型的技巧,以便在DI中使用它们。由于没有办法在.NET中为现有类型添加抽象,因此将创建一个封装(适配器),其中包含一个抽象(在本例中为抽象类),以便用于松散地耦合实现。

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

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

但是,这里还有一个问题 - DirectoryInfo需要一个目录路径作为构造函数参数。所以这意味着使用Abstract Factory通常会更有意义,因此可以在目录路径已知时在运行时创建它。在这种情况下,将工厂注入到服务中然后调用该方法在运行时创建实例会更有意义。 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的作者还有另一个窍门让它更进一步。他做了一个Aggregate Service,可以注入并提供许多类型在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>(); 
0

您不能使用该特定绑定,因为DirectoryInfo不会继承或实现DirectoryInfoBase

你可能被误导的事实,你可以做使用

DirectoryInfo dirInfo; 
DirectoryInfoBase dirInfoBase = (DirectoryInfoBase)dirInfo; 

蒙上了DirectoryInfoDirectoryInfoBase但这只是可能的,因为在DirectoryInfoBase隐式转换操作符:

public static implicit operator DirectoryInfoBase(DirectoryInfo directoryInfo) 
{ 
    if (directoryInfo == null) 
     return null; 
    return new DirectoryInfoWrapper(directoryInfo); 
} 

我不熟悉System.IO.Abstractions但为什么你不注入IFileSystem,就像在exa中mple与

ninject.Bind<IFileSystem>().To<FileSystem>(); 

如果你有IFileSystem你可以做

fileSystem.DirectoryInfo.FromDirectoryName(directoryName) 

获得DirectoryInfoBase对象。

相关问题