2013-08-21 45 views
3

我目前擁有的代碼非常類似於python裝飾器,它將一個函數作爲參數並返回由另一個包裝的相同函數(在這種情況下打開和關閉perforce連接)。你能寫一個可以接受任意數量參數的c#裝飾器函數嗎?

public Func<TArg, TReturn> EnableP4<TReturn, TArgs>(Func<TArg, TReturn> function) 
    { 
     Func<TArg, TReturn> p4Wrapper = (TArg funcArg) => 
     { 
      try 
      { 
       if (con.Status.Equals(ConnectionStatus.Disconnected)) { con.Connect(options); } 
       return function(funcArg); 
      } 
      finally { con.Disconnect(); } 
     }; 
     return p4Wrapper; 
    } 

目前這個只適用於功能的一個參數,我想知道,如果它可以作出更普遍的(也許如果有解壓一個數組的方法的一種方式?)。

(沿着這個東西線?)

public Func<TArgs, TReturn> EnableP4<TReturn, TArgs>(Func<TArgs, TReturn> function) 
    { 
     Func<TArgs, TReturn> p4Wrapper = (TArgs args) => 
     { 
      try 
      { 
       if (con.Status.Equals(ConnectionStatus.Disconnected)) { con.Connect(options); } 
       return function(*args); 
      } 
      finally { con.Disconnect(); } 
     }; 
     return p4Wrapper; 
    } 

其中TArgs是TARG []。

+0

你可以舉例說明你打算如何使用它?我不太清楚我明白你在找什麼。 – Bobson

回答

6

你可以只使用Func<T>(不Func<TArg,TResult>),並允許編譯器通過封閉處理多個參數爲你lambda表達式。

如果你改變了你的方法:通過

public Func<T> EnableP4<T>(Func<T> function) 

你總是可以把它叫做:

var newFunc = EnableP4(() => SomeFunc(arg1, arg2, arg3)); 

這是很好的,因爲它允許任何數量的參數,而無需多個重載。

1

不,你可以在C#中用強類型結果做到這一點。這主要是由於返回類型 - 您可以使用任意數量的參數(即Emit或反射)相對容易地構造函數調用,但要獲得強類型結果,您必須具有多個函數。

通常的做法是爲每個0-n(通常是0-3是足夠的)參數數量具有多個函數。

public Func<TReturn> EnableP4<TReturn>(Func<T1, TReturn> function)... 
public Func<T1, TReturn> EnableP4<TReturn, T1>(Func<T1, TReturn> function).... 
public Func<T1, T2, TReturn> 
     EnableP4<TReturn, T1, T2>(Func<T1, T2, TReturn> function)... 

注:

  • 您可以用dynamic實驗,看看如果你接近你想要什麼
  • 也依賴注入框架(如團結)允許您將一個接口的所有方法/類,所以在某些情況下它可能會工作(可能不是這種情況,因爲它看起來像是在數據訪問層內的某種重構代碼)。
0

您不需要傳遞所有參數;相反,您可以傳遞一個已經提供給它的參數的lambda表達式。

這很容易通過一個例子來解釋。鑑於這種:

public Func<T> Wrapper<T>(Func<T> function) 
{ 
    Func<T> wrapper =() => 
    { 
     try 
     { 
      Console.WriteLine("Prequel"); 
      return function(); 
     } 

     finally 
     { 
      Console.WriteLine("Sequel"); 
     } 
    }; 

    return wrapper; 
} 

你可以這樣做:

void run() 
    { 
     // Supply arguments to test() here: 
     var wrapped = Wrapper(() => test(1, 2)); 
     Console.WriteLine(wrapped()); 
    } 

    private int test(int a, int b) 
    { 
     Console.WriteLine("test()"); 
     return a + b; 
    } 
0

的類型參數變量號unsupported in C#,所以我認爲這是不可能的,做你想做的與你目前有。 .Net框架本身有一個原因that many func/action delegate declarations。對於同一個命名空間中的元組,這也是可見的。

我想你可以使用參數對象來解決它,它基本上是一個封裝所有參數的類。如果再創建一個基類或接口,用於這些模型,你可以限制你的裝飾方法:

public Func<TArgs, TReturn> EnableP4<TReturn, TArgs>(Func<TArgs, TReturn> function) 
    where TArgs : IArgs 

這是非常相似的框架,其中一個EventArgs參數對象圍繞通過內部事件中使用的概念。這裏的想法是一樣的,你將不得不繼承基礎模型/接口並用你想要的參數創建特定的模型。

這當然不是最優的,因爲它需要很多修改,對於簡單的方法調用來說是非標準的,但我認爲它應該很好地工作。

你有沒有考慮過這方法攔截?例如,我知道Unity supports it

相關問題