2016-10-03 125 views
0

我無法防止重複的代碼。委託傳遞爲通用參數時調用C#委託方法

目前,我有以下方法:

protected delegate bool CallbackDelegate<T>(T param, out string result); 
protected delegate bool CallbackDelegate<T, U>(T param1, U param2, out string result); 

protected bool ClientCtrlCallback<T>(T param, CallbackDelegate<T> callbackMethod) 
{...} 
protected bool ClientCtrlCallback<T,U>(T param1, U param2, CallbackDelegate<T,U> callbackMethod) 
{...} 

兩個ClientCtrlCallback方法具有相同的代碼(檢查溝通渠道的有效性,try-catch塊,獲取鎖等),在調用CallbackDelegate方法周圍建。

我一直在試圖合併這些ClientCtrl方法,但沒有成功,因爲委託約束是不被允許的。這是據我得到:(爲清楚起見移除不必要的代碼)

protected delegate bool CallbackDelegate1<T>(T param, out string result); 
protected delegate bool CallbackDelegate2<T, U>(T param1, U param2, out string result); 
protected const string METHOD_MY_DELEGATE1 = "CallbackDelegate1"; 
protected const string METHOD_MY_DELEGATE2 = "CallbackDelegate2"; 
protected interface ParameterSet { }; 
protected class OneParameter<T>: ParameterSet { public T p1; }; 
protected class TwoParameters<T,U> : ParameterSet { public T p1; public U p2; }; 

protected bool ClientCtrlCallback<D,T,U>(ParameterSet parameterset, D callbackMethod, string successLog = null) // where MyDelegate : delegate //not allowed 
{ 
    // delegate constrained is not allowed, so check it here 
    if (!typeof(D).IsSubclassOf(typeof(Delegate))) 
    return false; 

    // check name of method (this works) 
    string methodName = (callbackMethod as Delegate).Method.Name; 

    // Call the delegate // doesn't work. 
    string result; 
    switch (methodName) 
    { 
    case METHOD_MY_DELEGATE1: 
     // doesnt work 
     //(callbackMethod as Delegate)((parameterset as OneParameter<T>).p1, out result); 
     break; 

    case METHOD_MY_DELEGATE2: 
     // doesnt work 
     //(callbackMethod as Delegate)((parameterset as TwoParameters<T, U>).p1, (parameterset as TwoParameters<T, U>).p2, out result); // doesnt work 
     break; 
    } 
    return true; 
} 

它開始變得醜陋了參數類。交換機比較代表的姓名會變得更糟(我也不喜歡每個人都給他們一個不同的名字)。然後,當我想調用Delegate的方法時,總是有麻煩:編譯時錯誤Method name expected

我不明白爲什麼我可以從Delegate獲取方法名稱,但不調用Delegate的方法。我錯過了什麼大事?

+0

也許用類,接口,虛擬方法和所有爵士樂來代替整個事物? –

+1

不要這樣做。如果在這兩種方法中存在多餘的重複代碼,則將重複的代碼抽象爲輔助方法。但不要更改兩個方法的簽名,然後嘗試在運行時強制實現類型系統。更一般地說:人們花費太多時間擔心小的重複。正如你所發現的那樣,它們的重複數據刪除非常昂貴,而且這種努力可能會更好地用於編寫測試,尋找錯誤,設計下一個版本等等。 –

+0

嘗試使用Action <>? – lindexi

回答

0

EDITED
你就不能有:

protected delegate bool CallbackDelegate<TParameterSet>(TParameterSet param, out string result) 
    where TParameterSet : ParameterSet; 

然後(似乎並沒有多大用處,現在,這取決於你的代碼的其餘部分):

protected bool ClientCtrlCallback<TParameterSet>(TParameterSet parameterset, CallbackDelegate<TParameterSet> callbackMethod, string successLog = null) 
    where TParameterSet : ParameterSet 
{ 
    string result; 
    return callbackMethod(parameterset, out result); 
} 

而且最後你的回調方法:

bool CallbackMethodOneParameter<T>(OneParameter<T> parameter, out string result) 
{ 
    // Do your stuff with parameter.p1; 
    // set result 
    // return success or fail 
} 

bool CallbackMethodTwoParameters<T, U>(TwoParameters<T, U> parameters, out string result) 
{ 
    // Do your stuff with parameters.p1 and parameters.p2; 
    // set result 
    // return success or fail 
} 

不再申請
我也想知道你是否真的需要在這裏使用泛型。你的回調方法可能已經知道你的ParameterSet包含哪些類型。
因爲,在這個泛型中,如果你需要另一個參數,你將不得不在任何地方改變這個簽名。它會變得痛苦。


在你的代碼,調用您的代理,你可以這樣做:

var parameters = new object[] { (parameterset as OneParameter<T>).p1, null }; 
var success = (callbackMethod as Delegate).DynamicInvoke(parameters); 
result = parameters[1]; 
+0

這確實是可能的,但我們假設回調方法不能更改 – Brecht

+0

您將需要包裝方法,但我不太喜歡這個想法。 (或者你需要一個完全不同的解決方案) –

+0

@Brecht,我的編輯可能會讓你感興趣,我也會回答如何打電話給你的代表;) –

1

不要讓這種方法有責任接受將被傳遞到回調參數第一個地方。不要通過任何參數。如果調用者有一個他們想要在回調中使用的值,那麼可以使用閉包關閉該變量。

這個對象不僅要接受任意數量的參數並將它們傳入回調函數(並且不可能以類型安全的方式完全概括),而且調用方也很容易解決這個問題一個完全一般的情況和完全類型的安全方式,但是這些信息在邏輯上是調用者的私有實現細節,並不是該方法有任何理由首先要知道的信息。