2016-03-08 14 views
0

我的問題是這樣的。我有幾個功能:c#如何通過使用委託傳遞不同的功能到另一個功能

public List<FtpDirectoryEntry> ListDirectory(); 
public bool DirectoryExists(string dir); 
public void UploadFile(string file); 
public void UploadFiles(params string[] files); 

我想編寫一個函數來運行這些函數5次。如果我們在5次得不到結果,它會拋出異常。

public void CheckFunctionWithTrials(function X) 
{ 
    for (int i = 0; i < 5; i++) 
    { 
     try 
     { 
      X; 
      break; 
     } 
     catch (Exception e) 
     { 
      if (i == 5 - 1) 
      { 
       throw e; 
      } 
      else 
      { 
       DLog.Warn("Failed to upload file. Retry #" + (i + 1) + ": " + path); 
       Thread.Sleep(1000); 
      } 
     } 
    } 
} 

問題是這些函數有不同的簽名,所以我不能將它們作爲使用委託的參數傳遞。有沒有一種方法或模式可以幫助我解決這個問題?

+0

如果您甚至不知道他們採用了哪些參數,您希望如何調用其中一個函數? – DavidG

+0

@DavidG我知道這行不通。但它可以幫助我解釋我想要做什麼。 –

+0

雖然沒有任何意義。即使你通過它們,你會在'CheckFunctionWithTrials'方法中給它們什麼參數? – DavidG

回答

2

注意,這不使用委託,但Func<T>Action類型,而不是

我會改變你的簽名看起來像這樣:

public void CheckFunctionWithTrials(Action X) 

這可以讓你在一個函數傳遞不需要任何參數並且什麼也不返回然後你可以用一個匿名函數來調用它,就像這樣來「移除」參數。

CheckFunctionWithTrials(() => UploadFile(file)); 

這將使您的完整功能是這個樣子:

public void CheckFunctionWithTrials(Action X) 
    { 
     foreach (var i in Enumerable.Range(1, 5)) 
     { 
      try 
      { 
       X?.Invoke(); 
       break; 
      } 
      catch (Exception e) 
      { 
       if (i == 5) 
       { 
        throw; 
       } 
       else 
       { 
        //DLog.Warn("Failed to upload file. Retry #" + (i) + ": " + path); 
        Thread.Sleep(1000); 
       } 
      } 
     } 
    } 

你也有你的一些函數的返回類型,來獲取工作,你需要仿製藥。

public T CheckFunctionWithTrials<T>(Func<T> X) 
    { 
     foreach (var i in Enumerable.Range(1, 5)) 
     { 
      try 
      { 
       return X(); 
      } 
      catch (Exception e) 
      { 
       if (i == 5) 
       { 
        throw; 
       } 
       else 
       { 
        //DLog.Warn("Failed to upload file. Retry #" + (i) + ": " + path); 
        Thread.Sleep(1000); 
       } 
      } 
     } 
    } 

凡調用看起來是這樣的:

bool exists = CheckFunctionWithTrials(() => DirectoryExists(dir)); 

UPDATE:我其實有類似的功能在重試一次Task<T>我本地的回購協議之一。相同的基本概念,就像一個async方法

public async static Task<T> RetryOnceAsync<T>(this Func<Task<T>> tsk, TimeSpan wait) 
    { 
     try 
     { 
      return await tsk?.Invoke(); 
     } 
     catch (Exception ex) 
     { 
      Logger.Error(ex.Message); 
      await Task.Delay(wait); 
      return await tsk?.Invoke(); 
     } 
    }