转移 IDisposable 对象的所有权和构建器设计模式
Transferring ownership of an IDisposable object and the builder design pattern
当对象创建另一个对象(直接或通过工厂、构建器等)时,我习惯了这种方法 - 是 "owns" 它的对象,从而管理它的生命周期。
这个想法几乎适用于所有情况。
但有时创建对象的人根本无法管理它,例如在构建器设计模式实现中:
IFoo BuildFoo()
{
var dep = new Dep();
return new Foo(dep);
}
因此,此处构建器无法管理 dep
对象的生命周期,因为:
- 它没有对它的引用;
- 它不知道什么时候
Dispose
它是安全的。
天真的解决方案是制作 Foo : IDisposable
并让它管理传递给其构造函数的 Dep
。
但另一个难题出现了:
using (var dep = new Dep())
{
using (var foo = new Foo(dep))
{
// (1) do something with foo
}
// (2) !!! do something with dep !!!
}
上面的代码变得不安全:在(2)
点使用dep
是不安全的,因为它已经被foo
.Dispose
d了。
而且在句法上没有任何东西可以表示,它的职责是管理对象的生命周期。
所以问题是:什么是通用解决方案?
你让 Foo
调用构建器来实例化 Dep
并在需要时使用它呢?这样 Foo
管理 Dep
的生命周期,而 Foo
的客户端不必担心它。
非常幼稚的实现
void Main()
{
using (var builder = new Builder())
{
var foo = builder.Create();
// do smtg
}
}
public class Foo
{
public Foo(Dep instance)
{
}
}
public class Dep : IDisposable
{
public void Dispose()
{
Console.WriteLine($"{this.GetType().Name} disposed!");
}
}
public class Builder : IDisposable
{
private List<IDisposable> _disposables = new List<System.IDisposable>();
public Foo Create()
{
var dep = new Dep();
_disposables.Add(dep);
var foo = new Foo(dep);
return foo;
}
public void Dispose()
{
foreach(var d in _disposables)
d.Dispose();
Console.WriteLine($"{this.GetType().Name} disposed!");
}
}
如果某物拥有 IDisposable,那么它应该实现 IDisposable。
而且,当然,这是非常幼稚的实现,就像示例一样。
在这种情况下,我不会担心。我想我会在这里被打成碎片,但是 "builders"、"factories" 等都是我认为可以创建对象并将其处理交给请求的对象的地方它。
虽然有一条规则,但 builder/factory 必须 仅 是 创建 对象,而不对它做任何事情.
当然,如果您使用 new
关键字更新对象,那么您就是在将自己耦合到该实现(即使它是通过工厂 class 间接实现的)。您可能想要考虑依赖注入,具体取决于创建的对象的用途,在这种情况下,DI 容器将创建对象 and 在正确的时间为您处理它们,基于他们配置的生活方式。
当对象创建另一个对象(直接或通过工厂、构建器等)时,我习惯了这种方法 - 是 "owns" 它的对象,从而管理它的生命周期。
这个想法几乎适用于所有情况。
但有时创建对象的人根本无法管理它,例如在构建器设计模式实现中:
IFoo BuildFoo()
{
var dep = new Dep();
return new Foo(dep);
}
因此,此处构建器无法管理 dep
对象的生命周期,因为:
- 它没有对它的引用;
- 它不知道什么时候
Dispose
它是安全的。
天真的解决方案是制作 Foo : IDisposable
并让它管理传递给其构造函数的 Dep
。
但另一个难题出现了:
using (var dep = new Dep())
{
using (var foo = new Foo(dep))
{
// (1) do something with foo
}
// (2) !!! do something with dep !!!
}
上面的代码变得不安全:在(2)
点使用dep
是不安全的,因为它已经被foo
.Dispose
d了。
而且在句法上没有任何东西可以表示,它的职责是管理对象的生命周期。
所以问题是:什么是通用解决方案?
你让 Foo
调用构建器来实例化 Dep
并在需要时使用它呢?这样 Foo
管理 Dep
的生命周期,而 Foo
的客户端不必担心它。
非常幼稚的实现
void Main()
{
using (var builder = new Builder())
{
var foo = builder.Create();
// do smtg
}
}
public class Foo
{
public Foo(Dep instance)
{
}
}
public class Dep : IDisposable
{
public void Dispose()
{
Console.WriteLine($"{this.GetType().Name} disposed!");
}
}
public class Builder : IDisposable
{
private List<IDisposable> _disposables = new List<System.IDisposable>();
public Foo Create()
{
var dep = new Dep();
_disposables.Add(dep);
var foo = new Foo(dep);
return foo;
}
public void Dispose()
{
foreach(var d in _disposables)
d.Dispose();
Console.WriteLine($"{this.GetType().Name} disposed!");
}
}
如果某物拥有 IDisposable,那么它应该实现 IDisposable。 而且,当然,这是非常幼稚的实现,就像示例一样。
在这种情况下,我不会担心。我想我会在这里被打成碎片,但是 "builders"、"factories" 等都是我认为可以创建对象并将其处理交给请求的对象的地方它。
虽然有一条规则,但 builder/factory 必须 仅 是 创建 对象,而不对它做任何事情.
当然,如果您使用 new
关键字更新对象,那么您就是在将自己耦合到该实现(即使它是通过工厂 class 间接实现的)。您可能想要考虑依赖注入,具体取决于创建的对象的用途,在这种情况下,DI 容器将创建对象 and 在正确的时间为您处理它们,基于他们配置的生活方式。