3

我正在努力将 NHibernate 引入我们的代码库。我想我必须使用某种 DI 容器,这样我就可以将依赖项注入从数据库加载的实体中。我选择 Unity 作为容器。

我正在考虑使用 Unity 的拦截机制向我的代码添加事务方面,因此我可以执行以下操作:

class SomeService
{
    [Transaction]
    public void DoSomething(CustomerId id)
    {
        Customer c = CustomerRepository.LoadCustomer(id);
        c.DoSomething();
    }
}

处理[Transaction]程序将负责创建会话和事务,提交事务(或回滚异常)等。

我担心使用这种拦截方式会束缚我在代码中几乎所有地方都使用 Unity。如果我以这种方式引入方面,那么我绝不能调用new SomeService(),否则我将获得没有事务的服务。虽然这在生产代码中是可以接受的,但在测试中似乎开销太大。例如,我必须将其转换为:

void TestMethod()
{
    MockDependency dependency = new MockDependency();
    dependency.SetupForTest();
    var service = SomeService(dependency);
    service.DoSomething();
}

进入这个:

void TestMethod()
{
    unityContainer.RegisterType<MockDependency>();
    unityContainer.RegisterType<IDependency, MockDependency>();

    MockDependency dependency = unityContainer.Resolve<MockDependency>();
    dependency.SetupForTest();
    var service = unityContainer.Resolve<SomeService>();
    service.DoSomething();
}

这为我正在使用的每个模拟对象添加了 2 行代码,这导致了相当多的代码(我们的测试使用了很多有状态的模拟,因此测试类拥有 5-8 个模拟对象并不少见,并且有时更多。)

我不认为独立注入在这里会有所帮助:我必须为我在测试中使用的每个类设置注入,因为可以在编写测试后将方面添加到类中。

现在,如果我放弃使用拦截,我最终会得到:

class SomeService
{
    public void DoSomething(CustomerId id)
    {
        Transaction.Run(
            () => {
                Customer c = CustomerRepository.LoadCustomer(id);
                c.DoSomething();
             });
    }
}

诚然,这不是那么好,但似乎也没有那么糟糕。

我什至可以设置我自己的穷人的拦截:

class SomeService
{
    [Transaction]
    public void DoSomething(CustomerId id)
    {
        Interceptor.Intercept(
            MethodInfo.GetCurrentMethod(),
            () => {
                Customer c = CustomerRepository.LoadCustomer(id);
                c.DoSomething();
             });
    }
}

然后我的拦截器可以处理类的属性,但我仍然可以使用实例化类new而不必担心失去功能。

有没有更好的使用 Unity 拦截的方法,它不会强迫我总是使用它来实例化我的对象?

4

1 回答 1

0

如果您想使用 AOP 但又担心 Unity,那么我建议您查看 PostSharp。这将 AOP 实现为编译后检查,但对您在运行时使用代码的方式没有任何改变。

http://www.sharpcrafters.com/

他们有一个具有良好功能集的免费社区版,以及具有显着增强功能集的专业版和企业版。

于 2011-05-18T12:58:42.440 回答