如何结束一个函数及其参数...某种“超级委托”?

时间:2012-07-23 19:58:21

标签: c# delegates

我有一大堆代码在一个中等复杂的重试和try / catch逻辑中执行“文件放置”操作。这工作正常,看起来大致如下:

while (...) {
try {
    FilePut(source, destination)
    }
catch () {
   //Check exception type, possibly re-throw, possibly return, possibly increment
   //counters being checked by while loop
   }
}

这种逻辑的细节不是问题。但我意识到我还有其他一些操作也需要在同一种逻辑中执行,我想避免复制并在我的应用程序中粘贴这个逻辑。我想将它移动到一个函数并重用该函数。该函数必须对要调用的操作进行某种引用,try逻辑将执行该操作(文件put,文件get,等等)。

对于委托来说,这似乎是个好地方,但问题是,每个操作都有不同的签名,所以我不知道如何能够编写上面的逻辑来调用“any”操作

在C#中有一个很好的方法吗?

2 个答案:

答案 0 :(得分:4)

您需要Action delegate来隐藏所有不同的签名。像这样:

public void DoAction(Action action)
{
    // Make the boilerplate code whatever you need it to be. 
    // I've just used a try catch for simplicity.
    try
    {
        // Call the action at the appropriate time.
        action();
    }
    catch
    {
        // Handle any exceptions as you wish.
    }
}

然后,为了能够处理具有不同签名的操作,您可以定义一些重载,这些重载采用不同类型的通用Action<T>委托和所有必需的参数。这些重载会将通用操作及其参数“curry”到普通Action

public void DoAction<T>(Action<T> action, T arg1)
{
    DoAction(() => action(arg1));
}

public void DoAction<T1, T2>(Action<T1, T2> action, T1 arg1, T2 arg2)
{
    DoAction(() => action(arg1, arg2));
}

public void DoAction<T1, T2, T3>(Action<T1, T2, T3> action, T1 arg1, T2 arg2, T3 arg3)
{
    DoAction(() => action(arg1, arg2, arg3));
}

// etc...

使用:

public void SomeOtherMethod()
{
    DoAction(MethodThatTakesTwoInts, 42, 23);
    DoAction(MethodThatTakesAString, "Don't Panic!");
}

此外,如果您不熟悉它们,请查看Func delegates的相关系列以及其他方法。

答案 1 :(得分:0)

您可以使用递归:

protected void TryNTimes(int numberOfTries, Action action)
{
    try
    {
        if (numberOfTries == 0) return;
        action();
    }
    catch (Exception)
    {
        TryNTimes(numberOfTries - 1, action);
    }
}

然后像这样使用它:

TryNTimes(10, () => Foo());