1

我做以下,現在如何註冊一個在SimpleInjector中具有比TService更多類型參數的TImpl?

container.Register<IDatabaseMapper<User>, DatabaseMapper<User, OracleException>>(); 
container.Register<IDatabaseMapper<Desk>, DatabaseMapper<Desk, OracleException>>(); 
container.Register<IDatabaseMapper<Commodity>, DatabaseMapper<Commodity, OracleException>>(); 

但我想這樣做

container.RegisterOpenGeneric(typeof(IDatabaseMapper<>), typeof(DatabaseMapper<,OracleException>)); 

這在某種程度上可能嗎?

回答

2

這可能嗎?是和否:-)

typeof(DatabaseMapper<,OracleException>)是無效的C#代碼。您必須提供全部泛型類型參數或根本沒有。因此無法通知Container它應該填寫缺少的TException類型參數,其中包含OracleException。所以不,你不能這樣做。

但是,當然你可以這樣做:-)。只需創建一個OracleExceptionDatabaseMapper<T>類,從DatabaseMapper<T, OracleException>繼承並使用該類型的註冊:

// Helper class 
public class OracleExceptionDatabaseMapper<T> 
    : DatabaseMapper<T, OracleException> 
{ 
} 

// Registration 
container.RegisterOpenGeneric(typeof(IDatabaseMapper<>), 
    typeof(OracleExceptionDatabaseMapper<>)); 

通過這種方式,給定的實施只有1個通用的類型,可以映射到特定服務接口的單泛型類型參數。

UPDATE

由於簡單的噴油器2.4可以註冊parial開放式泛型類型,但由於這是還沒有C#支持你將不得不手動創建部分開放式泛型類型如下:

Type databaseMapperType = typeof(DatabaseMapper<,>).MakeGenericType(
    typeof(DatabaseMapper<,>).GetGenericArguments().First(), 
    typeof(OracleException)); 

container.RegisterOpenGeneric(typeof(IDatabaseMapper<>), databaseMapperType); 
+0

'的typeof(DatabaseMapper <,OracleException>)' 沒有表明在編譯時任何錯誤,所以我錯誤地認爲它應該工作。你的方法工作,但是這正是我想避免 - 一個數據庫供應商特定的異常創建一個類,而不是提供類型爲AA參數 – mrt181 2012-03-05 07:58:55

+0

這樣'DatabaseMapper :IDatabaseMapper 其中TEntity:類,IEntity 其中TException:DbException' – mrt181 2012-03-05 08:05:59

+2

創建額外的類通常不是問題,尤其是當您將該類放到容器的配置附近時。在這種情況下,它對應用程序是不可見的,只是你的[Composition Root]的一部分(http://blog.ploeh.dk/2011/07/28/CompositionRoot.aspx)。重新考慮將此解決方案放在更復雜(但有趣)的'ResolveUnregisteredType'上。 – Steven 2012-03-05 08:59:07

1

爲了完整起見,在這裏是如何做到這一點使用未註冊的類型解析一個例子:

container.ResolveUnregisteredType += (s, e) => 
{ 
    var serviceType = e.UnregisteredServiceType; 

    if (serviceType.IsGenericType && 
     serviceType.GetGenericTypeDefinition() == typeof(IDatabaseMapper<>)) 
    { 
     Type argument = serviceType.GetGenericArguments()[0]; 

     var closedDatabaseMapperType = typeof(DatabaseMapper<,>) 
      .MakeGenericType(argument, typeof(OracleException)); 

     var registration = 
      container.GetRegistration(closedDatabaseMapperType, true); 

     e.Register(registration.BuildExpression()); 
    } 
}; 

只要請求未註冊的類型,容器就會調用ResolveUnregisteredType事件。這給你最後一次註冊該類型的機會。提供的UnregisteredTypeEventArgs包含兩個Register方法過載,允許您註冊該類型(使用Func<T>或使用Expression)。

上述檢查該代碼,以查看是否所請求的服務類型是IDatabaseMapper<T>並且如果是這樣,這將構造一個DatabaseMapper<T, OracleExpression>其中T被替換的實際類型的服務類型的。使用這種類型的容器請求該類型的註冊。使用該註冊對象的BuildExpression方法,我們可以構建一個表達式樹來描述創建該DatabaseMapper的新實例。該表達式編號比使用e.Register方法註冊,其有效地將IDatabaseMapper<T>映射到創建DatabaseMapper<T, OracleException>

重要提示:我相信使用未註冊類型的解決方案應該只能作爲回退選項,因爲通常有更簡單的方法來解決您的問題(例如我在其他答案中顯示的方法),但未註冊的類型解析可以在某些高級場景中非常有用(例如DatabaseMapper<T, TException>被密封)。

相關問題