如果我正在执行以下操作:
using (var foo = bar.GetFoo())
using (var blat = new Blat(foo))
using (var bonk = Bonk.FromBlat(blat))
using (var bork = Bob.FromBip(bonk))
{
var target = bork.ToArray(); // I GOT THE TARGET
}
这是非常安全且易读的,但是我的理解是,只有在最后一行之后,整个事情才会展开,以处置所有内容。假设foo
,blat
和bonk
仅用于创建bork
的一行,是否有一种好方法(“好”当然是主观的)来处理他们习惯于尽快释放资源后的那一刻?我真的很喜欢使用链的安全性和可读性,我很好奇是否还有另一种方法可以做到这一点。
答案 0 :(得分:1)
您可以编写一种方法来使用产生值的IDisposable
。这里的部分问题是,using
语句作为一个语句不会产生值,因此很难链接:
public static TResult Use<TSource, TResult>(this TSource source, Func<TSource, TResult> selector)
where TSource : IDisposable
{
using (source)
return selector(source);
}
这使您可以编写:
var target = bar.GetFoo()
.Use(foo => new Blat(foo))
.Use(blat => Bonk.FromBlat(blat))
.Use(bonk => Bob.FromBonk(bonk))
.Use(bork => bork.ToArray());
请注意,此Use
方法从外部接受IDisposable
,但将其自身处置,因此,如果您在Use
上调用IDisposable
,则仍然保持范围,您甚至可能在处理完它后仍然使用它,这应该是 错误。在这种情况下,我们永远不会抓住一次性物品,但是其他人可能不知道他们不应该这样做。
如果您想解决这个问题,可以编写一个将一次性值链接在一起的函数。通过将所有功能整合到一个功能中,您可以确保没有任何一次性产品可以非常轻松地从其中“漏出”:
public static TResult ChainDisposables<T1, T2, T3, T4, TResult>(Func<T1> firstFunc,
Func<T1, T2> secondFunc,
Func<T2, T3> thirdFunc,
Func<T3, T4> fourthFunc,
Func<T4, TResult> resultFunc)
where T1 : IDisposable
where T2 : IDisposable
where T3 : IDisposable
where T4 : IDisposable
{
return firstFunc()
.Use(secondFunc)
.Use(thirdFunc)
.Use(fourthFunc)
.Use(resultFunc);
}
(只需按照示例,您需要为链中每个不同数量的对象创建重载。)
哪位让你写:
var target = ChainDisposables(() => bar.GetFoo(),
foo => new Blat(foo),
blat => Bonk.FromBlat(blat),
bonk => Bob.FromBonk(bonk),
bork => bork.ToArray());
答案 1 :(得分:0)
版本1和版本2在功能上并不等效,因为处理顺序应在您的伪代码中颠倒为2:
Foo foo = null;
Blat blat = null;
Bonk bonk = null;
Bork bork = null;
try
{
foo = bar.GetFoo();
blat = new Blat(foo);
bonk = Bonk.FromBlat(blat);
bork = Bob.FromBip(bonk);
var target = bork.Whatever; // I GOT THE TARGET
}
finally
{ // the disposal should happen in reverse order to instantiation
bork?.Dispose();
bonk?.Dispose();
blat?.Dispose();
foo?.Dispose();
}
看到错误的顺序后,您可能会理解为什么使用链接的using
语句可以确保事情以正确的顺序发生,而不是依靠您来正确处理
如果编译器可以确保按正确的顺序完成操作-请让编译器为您执行-减少出错的机会