2014-10-28 59 views
0

我正在尋找使用Unity來解析類型在運行時根據收到的特定數據。我的代碼(類似於下圖所示)當前在啓動時將類型註冊到引導程序類中,然後在主流程中決定需要什麼類型。Unity:有條件解決

我想要做的是用分辨率替換使用'new'關鍵字的代碼行,但是因爲此代碼與我的引導程序不匹配,所以我不知道如何做到這一點......我'對Unity來說新的東西,所以請放輕鬆。

// In Bootstrapper class 
resolver.RegisterType<IDataType1, DataType1>(); 
resolver.RegisterType<IDataType2, DataType2>(); 
resolver.RegisterType<IDataType3, DataType3>(); 


// Main flow...outwith bootstrapper 
switch (dataRecordType) 
{ 
    case DataRecordType.dataType1: 
     DataType1 dt1 = new DataType1(); 
     dt1.ProcessData(); 
     break; 

    case DataRecordType.dataType2: 
     DataType2 dt2 = new DataType2(); 
     dt2.ProcessData(); 
     break; 

    case DataRecordType.dataType3: 
     DataType3 dt3 = new DataType3(); 
     dt3.ProcessData(); 
     break; 

    default: 
     break; 
} 

回答

2

您在這裏缺少一些抽象概念。你錯過了你的數據類型的一般抽象,抽象,用於創建這些數據類型的實現:

// In your core layer 
public interface IDataType { 
    void ProcessData(); 
} 

public interface IDataTypeFactory { 
    IDataType Create(DataRecordType dataRecordType); 
} 

// In Bootstrapper class 
resolver.RegisterInstance<IDataTypeFactory>(new DataTypeFactory(resolver)); 
resolver.RegisterType<IDataType1, DataType1>(); 
resolver.RegisterType<IDataType2, DataType2>(); 
resolver.RegisterType<IDataType3, DataType3>(); 

private sealed class DataTypeFactory : IDataTypeFactory { 
    private readonly IUnityContainer container; 
    public DataTypeFactory(IUnityContainer container) { 
     this.container = container; 
    } 

    public IDataType Create(DataRecordType dataRecordType) { 
     switch (dataRecordType) { 
      case DataRecordType.dataType1: 
       return this.container.Resolve<IDataType1>(); 
      case DataRecordType.dataType2: 
       return this.container.Resolve<IDataType2>(); 
      case DataRecordType.dataType3: 
       return this.container.Resolve<IDataType3>(); 
      default: 
       throw new InvalidEnumArgumentException(); 
     } 
    } 
} 

你能看到的是,創建實現代碼轉移到了工廠。現在剩下的應用程序代碼可以是來自這樣的:

// Main flow...outwith bootstrapper 
IDataType dt = this.dataTypeFactory.Create(dataRecordType); 
dt.ProcessData(); 

IDataType1IDataType2IDataType3現在只能在引導程序中使用,並已成爲多餘的(或至少是多餘的,你提供的代碼),所以你甚至可以將它們一起刪除,並將引導程序邏輯更改爲以下內容:

// In Bootstrapper class 
resolver.RegisterInstance<IDataTypeFactory>(new DataTypeFactory(resolver)); 
resolver.RegisterType<DataType1>(); 
resolver.RegisterType<DataType2>(); 
resolver.RegisterType<DataType3>(); 

private sealed class DataTypeFactory : IDataTypeFactory { 
    private readonly IUnityContainer container; 
    public DataTypeFactory(IUnityContainer container) { 
     this.container = container; 
    } 

    public IDataType Create(DataRecordType dataRecordType) { 
     switch (dataRecordType) { 
      case DataRecordType.dataType1: 
       return this.container.Resolve<DataType1>(); 
      case DataRecordType.dataType2: 
       return this.container.Resolve<DataType2>(); 
      case DataRecordType.dataType3: 
       return this.container.Resolve<DataType3>(); 
      default: 
       throw new InvalidEnumArgumentException(); 
     } 
    } 
} 
+1

+1值得一提的是,IOC容器不應該錯過組合根(因爲OP似乎是初學者)。也有沒有一種方法可以創建一個工廠,而不用'container.Resolve'耦合代碼? – 2014-10-28 12:37:51

+0

@SriramSakthivel:感謝您的注意。我同意,容器不應該被引用到任何地方,除了Composition Root。可以將工廠與容器分離,但由於此工廠實現可以是Compostion Root的一部分,因此工廠引用容器本身沒有任何問題。但另一種選擇是將'DataTypeX'類注入工廠而不是容器。 – Steven 2014-10-28 12:51:32

+0

我想你的意思是將'Func '注入工廠?否則我們需要多個工廠實例來獲取'DataTypeX'的新實例是不是? – 2014-10-28 12:55:47