2016-02-02 121 views
2

我正在嘗試創建一個帶參數的func擴展方法。我想支持可變數量的參數(無,1,2,... 10)具有可變數量參數參數的匿名方法

我有類似的東西,只適用於三個參數。 如何將其簡化爲支持可變數量的參數,而不必爲每個排列都複製並粘貼?它甚至有可能嗎?

(注:我的例子很裸機我真正的實現有很多更多的邏輯,如支持具有計數,Thread.sleep代碼,跟蹤記錄,異常處理等「重試」的邏輯。)

謝謝!

public static class UtilExtensions 
{ 
    public static TResult Execute<T1, T2, T3, TResult>(Func<T1, T2, T3, TResult> function, T1 argument1, T2 argument2, T3 argument3)) 
    { 
     // do other stuff ... like logging 

     try 
     { 
      // call our 'action' 
      TResult result = function(argument1, argument2, argument3); 
      return result; 
     } 
     catch (Exception ex) 
     { 
      // do other stuff ... like logging, handle Retry logic, etc. 
     } 
    } 
} 

,並調用它是這樣的:

public string DoSomething(int arg1, string arg2, MyObject arg3) 
{ 
    if (arg1 == 1) 
     throw new Exception("I threw an exception"); 

    return "I ran successfully"; 
} 
public string DoSomethingElse() 
{ 
    return "blah blah blah"; 
} 

public string DoSomethingMore(DateTime dt) 
{ 
    return "hi mom"; 
} 


[TestMethod] 
public void Should_call_UtilsExtensions_Execute_method_successfully() 
{ 
    int p1 = 0; 
    string p2 = "Hello"; 
    MyObject p3 = new MyObject(); 

    string results = UtilExtensions.Execute<int, string, MyObject, string>(
     DoSomething, p1, p2, p3); 

    // ??? So how would I use my UtilExtensions api to call 
    // DoSomethingElse (no arguments) 
    // DoSomethingMore (one argument) 
    // I'm okay to create overloads of my Execute method 
    // but I don't want to copy-and-paste the same code/logic in each method 

    results.Should().Be("I ran successfully"); 
} 
+0

https://msdn.microsoft.com/en-us/library/w5zay9db.aspx –

+0

如果我理解正確,你想要的東西類似於C++ variadic模板。看看這個答案:http://stackoverflow.com/questions/6844890/simulate-variadic-templates-in-c-sharp –

+0

@李泰勒。我不認爲params會起作用......但如果你能以其他方式展示我會很高興。 – Raymond

回答

2

我不認爲你可以做到這一點,因爲據我所知,這正是Func鍵和動作類型有許多不同的聲明的原因用於.Net中的不同參數編號。見https://msdn.microsoft.com/en-us/library/018hxwa8(v=vs.110).aspx

左手邊你問類似下面的東西,除了在這種情況下,OP問的接口Can I have a variable number of generic parameters?

的問題基本上是仿製藥相同的基本限制。

你也許可以用反射做一些事情,但我認爲你最好選擇一些合理的參數來支持和寫入重載。

參數不起作用,因爲對於參數,數組中的所有類型都是相同的類型。 T1,T2等是供您使用的不同類型。你必須將參數聲明爲Object [],這完全擊敗了泛型。雖然也許你願意放棄類型檢查,如果你真的有一個未知數量的參數可能不切實際的高。

+0

謝謝,這就是我的想法......也許是代碼生成器的時候了。 – Raymond

+0

@Raymond是的我以前見過用於這個確切目的的代碼生成器。它感覺骯髒,但實際上可能是最好的解決方案。只要你考慮過其他可能的解決方案的意義,並且認爲這對於這種情況是最好的,那麼我認爲它是可以的。 –

1

你不能那樣做。另一種方法是創建一個接受一個參數的擴展方法,但該參數可以由匿名函數組成。所以你的調用代碼將完全控制如何使用它。不乾淨的,但有點清潔比一個代碼生成路線至少:

public static class UtilExtensions 
{ 
    public static TResult Execute<TResult>(this Func<TResult> function) 
    { 
     // do logging 

     try 
     { 
      TResult result = function(); 
      return result; 
     } 
     catch (Exception ex) 
     { 
      // do other stuff ... like logging, handle Retry logic, etc. 
     } 

     // or throw - this right here could prove unpredictable and is verrrry dirty 
     return default(TResult); 
    } 
} 

用法:

var param1 = 1; 
var param2 = "string"; 

Func<bool> function =() => 
{ 
    // do stuff with param1 and param2 
    return true; 
} 

var results = function.Execute(); 
+0

我真的很喜歡這種方法,並且是我最終使用的......但是,我仍然需要複製並粘貼我的代碼4次。其中一個用於Action vs Func ,另一個用於異步方法支持。我仍然可以考慮採用代碼生成的方法。 – Raymond

+0

@Raymond是的,我猜想你必須重複代碼基本上4次 - 想不到一個方法。儘管......代碼會坐在同一個地方,之後沒有什麼理由變化。我很想知道一個代碼生成的方法是否值得花費時間。 – Balah