1

我现在正在做以下事情

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>));

这有可能吗?

4

2 回答 2

2

这可能吗?是和不是:-)

typeof(DatabaseMapper<,OracleException>)不是有效的 C# 代码。您要么必须提供所有泛型类型参数,要么根本不提供。所以没有办法通知Container它应该TExceptionOracleException. 所以不,你不能这样做。

但是,是的,您当然可以这样做:-)。只需创建一个OracleExceptionDatabaseMapper<T>继承自DatabaseMapper<T, OracleException>该类型并在注册中使用该类型的类:

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

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

这样,给定的实现只有 1 个泛型类型,并且可以映射到给定服务接口的单个​​泛型类型参数。

更新

从 Simple Injector 2.4 开始,可以注册部分开放的泛型类型,但由于 C# 仍然不支持,因此您必须手动创建部分开放的泛型类型,如下所示:

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

container.RegisterOpenGeneric(typeof(IDatabaseMapper<>), databaseMapperType);
于 2012-03-02T17:48:24.053 回答
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方法重载,允许您注册该类型(使用 aFunc<T>或使用 an Expression)。

上面的代码检查请求的服务类型是否为 an IDatabaseMapper<T>,如果是,它将构造一个DatabaseMapper<T, OracleExpression>whereT替换为服务类型的实际类型。使用该类型从容器请求该类型的注册。使用该BuildExpression注册对象的方法,我们可以构建一个表达式树,该树描述该 的新实例的创建DatabaseMapper。此表达式 id 使用该e.Register方法注册,该方法有效地将 映射IDatabaseMapper<T>到 a 的创建DatabaseMapper<T, OracleException>

重要提示:我认为使用未注册的类型解析应该只用作后备选项,因为通常有更简单的方法可以解决您的问题(例如我在另一个答案中显示的那个),但未注册的类型解析在某些高级中可能很有用场景(DatabaseMapper<T, TException>例如,当它被密封时)。

于 2012-03-03T02:03:20.437 回答