如何重构嵌套使用中的代码?

cki*_*tel 9 c# refactoring using-statement code-duplication

我有一些代码有很多重复.问题来自我正在处理嵌套IDisposable类型的事实.今天我有一些看起来像:

public void UpdateFromXml(Guid innerId, XDocument someXml)
{
    using (var a = SomeFactory.GetA(_uri))
    using (var b = a.GetB(_id))
    using (var c = b.GetC(innerId))
    {
        var cWrapper = new SomeWrapper(c);
        cWrapper.Update(someXml);
    }
}

public bool GetSomeValueById(Guid innerId)
{
    using (var a = SomeFactory.GetA(_uri))
    using (var b = a.GetB(_id))
    using (var c = b.GetC(innerId))
    {
        return c.GetSomeValue();
    }
}
Run Code Online (Sandbox Code Playgroud)

using对于这些方法中的每一个,整个嵌套块都是相同的(显示了两个,但是大约有十个).唯一不同的是当你到达using块的内层时会发生什么.

我想的一种方法是做一些事情:

public void UpdateFromXml(Guid innerId, XDocument someXml)
{
    ActOnC(innerId, c =>
    { 
        var cWrapper = new SomeWrapper(c);
        cWrapper.Update(someXml);
    });
}

public bool GetSomeValueById(Guid innerId)
{
    var result = null;

    ActOnC(innerId, c => { result = c.GetSomeValue(); });

    return result;
}

private void ActOnC(Guid innerId, Action<TheCType> action)
{
    using (var a = SomeFactory.GetA(_uri))
    using (var b = a.GetB(_id))
    using (var c = b.GetC(innerId))
    {
        action(c);
    }        
}
Run Code Online (Sandbox Code Playgroud)

这是有效的,它只是一种笨重的解析(作为一个人). 有没有人对如何减少using像这样的嵌套块的代码重复有任何其他建议? 如果他们不是IDisposable那么人们可能只是创建一个方法来返回...的结果,b.GetC(innerId)但这不是这里的情况.

Ser*_*rvy 1

我喜欢BFree提供的答案作为开始,但我会做一些修改。

//Give it a better name; this isn't designed to be a general purpose class
public class MyCompositeDisposable : IDisposable 
{
    public MyCompositeDisposable (string uri, int id, int innerid)
    {
        A = SomeFactory.GetA(uri);
        B = A.GetB(id);
        C = B.GetC(innerId);
    }

    //You can make A & B private if appropriate; 
    //not sure if all three or just C should be exposed publicly.
    //Class names are made up; you'll need to fix.  
    //They should also probably be given more meaningful names.
    public ClassA A{get;private set;}
    public ClassB B{get;private set;}
    public ClassC C{get;private set;}

    public void Dispose()
    {
        A.Dispose();
        B.Dispose();
        C.Dispose();
    }
}
Run Code Online (Sandbox Code Playgroud)

完成此操作后,您可以执行以下操作:

public bool GetSomeValueById(Guid innerId)
{
    using(MyCompositeDisposable d = new MyCompositeDisposable(_uri, _id, innerId))
    {
        return d.C.GetSomeValue();
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,MyCompositeDisposable 可能需要在构造函数和 Dispose 方法中具有 try/finally 块,以便创建/销毁中的错误正确确保没有任何内容最终未处理。