4

我有一段代码在一个中等复杂的重试和尝试/捕获逻辑中执行“文件放置”操作。这工作正常,它看起来大致是这样的:

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

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

这似乎是一个委托的好地方,但问题是,这些操作中的每一个都有不同的签名,所以我不确定如何编写我的上述逻辑来调用“任何”操作。

有没有在 C# 中执行此操作的好方法?

4

2 回答 2

5

您需要一个Action代表来隐藏所有不同的签名。像这样的东西:

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代表家族以获取良好的衡量标准。

于 2012-07-23T20:02:15.050 回答
0

您可以使用递归:

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

然后像这样使用它:

TryNTimes(10, () => Foo());
于 2012-07-23T20:12:36.313 回答