2012-07-23 8 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

相關問題