假设您的代码是通过构造函数注入任何依赖项而为DI和IOC正确设计的。然后,在组合根处是否使用IOC容器或DI是否对此问题无关紧要。我想。
无论如何,我一次又一次地发现自己在如何处理基于范围的服务(例如交易或其他明显的短暂操作)方面的精神上的斗争。我想遵守一些限制因素:
IDisposable
- 这是一个漏洞的抽象,只有实际的实现类型(和组成根处的小提琴手)应该关心。为了能够使用using
,我们需要IDisposable
,但由于依赖关系接口不应该是IDisposable
,您如何绕过它来获取范围行为?
答案 0 :(得分:4)
在这种情况下,我会注入一个服务工厂来创建那些作用域服务,并让服务接口派生自IDisposable
。这样,工厂将负责创建适当的服务实例,以及决定返回哪个服务实现的唯一点。您不需要在任何地方注入范围服务。
public interface ITransaction : IDisposable
{
}
public interface ITransactionFactory
{
ITransaction CreateTransaction();
}
public class Foo
{
private readonly ITransactionFactory transactionFactory;
public Foo(ITransactionFactory transactionFactory)
{
this.transactionFactory = transactionFactory;
}
public void DoSomethingWithinTransaction()
{
using(ITransaction transaction = this.transactionFactory.CreateTransaction())
{
DoSomething();
}
}
}
答案 1 :(得分:1)
可能会推出自己的“垃圾收集器”吗?定期检查Dictionary<Transaction>
的IsComplete和/或LastAccessed属性并浪费“旧”属性的东西。这是“行走内存泄漏”,但要么你明确清理(比如通过IDisposable),要么你自己锻炼如何清理。
可能有一个AOP解决方案可以启动“gc”......提交/回滚听起来像是一个很好的切割地点......也许你甚至根本不需要GC ......在从提交或回滚备份callstack的路上清理事务。
祝你好运。我很想知道其他人提出的解决方案(和想法)。
干杯。基思。
答案 2 :(得分:1)
我想你可以使用的另一个选择是用一次性类型包装你的实例,这样它可以自动处理类型的处理,无论该类型是否实际上是一次性的。例如,我可以定义类似的东西:
public class DisposableWrapper<T> : IDisposable
{
private readonly T _instance;
private readonly IDisposable _disposable;
public DisposableWrapper(T instance)
{
_instance = instance;
_disposable = instance as IDisposable;
}
public void Dispose()
{
if (_disposable != null)
_disposable.Dispose();
}
public static implicit operator T(DisposableWrapper<T> disposableWrapper)
{
return disposableWrapper._instance;
}
}
(希望有更多的错误处理!)
鉴于我知道在处理时该类型是否是一次性的,我可以相应地调用它。我还可以提供一个隐式运算符来从中强制转换回内部类型。有了上面的,还有一个漂亮的扩展方法:
public static class DisposableExtensions
{
public static DisposableWrapper<T> Wrap<T>(this T instance)
{
return new DisposableWrapper<T>(instance);
}
}
让我们假设我有一个服务,我注入一个类型,它可能是:
public interface IUserService
{
IUser GetUser();
}
我可以做类似的事情:
public HomeController(IUserService service)
{
using (var disposable = service.Wrap())
{
var user = service.GetUser();
// I can even grab it again, implicitly.
IUserService service2 = disposable;
}
}
现在无论IUserService
的具体实施是否是一次性的,我仍然可以安全地假设无关紧要。
另一个快速控制台示例:
class Program
{
static void Main(string[] args)
{
using (var instance = new ClassA().Wrap())
{
ClassA instanceA = instance;
}
using (var instance = new ClassB().Wrap())
{
ClassB instanceB = instance;
}
Console.ReadKey();
}
}
public class ClassA
{
}
public class ClassB : IDisposable
{
public void Dispose()
{
Console.Write("Disposed");
}
}
答案 3 :(得分:1)
如今,大多数IoC容器都对这种性质的工作单元提供了大量内置支持。
在Autofac中,最符合您要求的机制是Owned<T>
关系类型。您可以通过this article看到它的实际效果(并获得更多资料)。
希望这有帮助,
尼克