2012-07-23 9 views
4

我有一段代码在一个适度复杂的重试和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逻辑将执行该操作(文件放置,文件获取,等等)。

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

有没有在C#中做到这一点的好方法?

回答

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>代表和所有必要参数的几个重载。这些过载会“咖喱”通用操作及其参数纯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以及很好的措施。

+0

这将如何满足的事实,每个操作都有不同的签名? – desigeek 2012-07-23 20:05:19

+1

@desigeek DoAction(()=> FilePut(source,dest)); DoAction(()=> bla-bla1(x)); DoAction(()=> bla-bla3(x1,x2,x3)); – 2012-07-23 20:09:22

+1

签名差异隐藏在“动作”委托中。 “行动”代表都具有相同的签名。 – 2012-07-23 20:09:51

0

您可以使用递归:

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

,然后用它是这样的:

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

非常干净的代码,但它消耗你的例外。你怎么知道行动是否成功?最好将if语句放在catch块中,如果有足够的尝试离开并重新抛出,则递归。 – 2012-07-23 20:22:06

+0

只是好奇,为什么递归? – FishBasketGordo 2012-07-23 20:23:43

+0

@KrisVandermotten:你说得对。我只是认为“异常=>再试一次”的逻辑,作为OP的起点。 – Andre 2012-07-23 20:37:08

相关问题