2015-01-10 73 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對象。

相關問題