Вы можете написать метод для использования 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());