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>被密封)。

相关问题