代码之家  ›  专栏  ›  技术社区  ›  KRA2008

是否有一种using/Dispose语法,它会更愿意进行Dispose,但与链锁一样安全?

  •  -1
  • KRA2008  · 技术社区  · 7 年前

    如果我在做以下事情:

    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 ,是否有一个好的方法(“好”当然是主观的)在它们被用来释放资源后尽快处理它们?我真的很喜欢使用链的安全性和可读性,我只是好奇是否有其他方法可以做到这一点。

    2 回复  |  直到 7 年前
        1
  •  1
  •   Servy    7 年前

    您可以编写一个方法来使用 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 方法接受 从外面,但处理它自己,所以如果你打电话 如果您仍保留在范围内,那么即使在处理完它之后,您也可能最终使用它,这 应该 错误。在这种情况下,我们永远不会抓住一次性物品,但其他人可能不知道他们不应该这样做。

    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());
    
        2
  •  0
  •   Jens Meinecke    7 年前

    版本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 语句确保事情按正确的顺序发生,而不是依赖于你来做正确的事情

    如果编译器能确保事情按正确的顺序进行-让编译器帮你做-减少出错的机会