2014-01-28 125 views
1

假設我有以下WCF代碼:如何傳遞幾個方法(帶參數)作爲參數?

try 
    { 
     ServiceClient proxy = new ServiceClient(); 
     proxy.ClientCredentials.UserName.UserName = "user"; 
     proxy.ClientCredentials.UserName.Password = "password"; 
     proxy.GetData(2); 
     if (proxy.State = CommunicationState.Opened) 
     { 
      proxy.GetData("data"); 
     } 
     proxy.Close(); 
    } 
    catch (FaultException ex) 
    { 
     // handle the exception  
    } 

而且因爲我注意到,TRY ... CATCH和其他邏輯是重複的,更不用說建立一個WCF電話是昂貴的,我想送許多「方法和參數」用於這個功能。

實質上,將GetData(2)GetData("data")作爲方法數組傳遞,並使結果以異步或同步方式返回。

我該如何做到這一點?

我想我可以有兩個'ref'對象來處理結果[]和對結果[]的共享鎖。不過,我不知道如何將「帶參數的方法」作爲參數傳遞給另一個函數。

也許看着這個的另一種方式可能是一個函數指針數組,對於具有不同參數的相同函數。

任何人都可以推動我這樣做的正確方法嗎?

更多信息:

我問這個問題so I can optimize this approach to handling WCF exceptions and retries但讓我沒有在每次通話後總是打開/關閉客戶端。

回答

7

使用代表,並通過他們在列表中。

當需要返回值時,使用C#Func<T>委託。

List<Func<Data>> funcList = new List<Func<Data>>(); 
funcList.Add(() => GetData(2)); 

// You can use any condition as you otherwise would to add to the list. 
if (proxy.State = CommunicationState.Opened) 
{ 
    funcList.Add(() => GetData("data")); 
} 

List<Data> ProcessFuncs(List<Func<Data>> funcDatas) 
{ 
    List<Data> returnList = new List<Data>(); 
    foreach(var func in funcDatas) 
    { 
     returnList.Add(func()); 
    } 
} 

(只要返回類型是相同的,這將工作)

這僅僅是當然的示例;如果您的方法不返回任何內容,則可以使用C#Action委託,該委託只執行一個操作並且不返回任何值。

List<Action> actionList = new List<Action>(); 
actionList.Add(() => ProcessData("data")); // ProcessData is a void with no return type 
actionList.Add(() => ProcessData(2)); 

public void ProcessActions(List<Action> actions) 
{ 
    foreach(var action in actions) 
    { 
     action(); 
    } 
} 

響應於一些評論:

此代碼編譯和是所有當量:

class Program 
{ 
    public static string GetData(string item) { return item; } 
    public static string GetData(int item) { return item.ToString(); } 

    static void Main(string[] args) 
    { 
     string someLocalVar = "what is it?"; 
     int someLocalValueType = 3; 

     Func<string> test =() => 
     { 
      return GetData(someLocalVar); 
     }; 

     Func<string> test2 =() => GetData(someLocalValueType); 
     someLocalValueType = 5; 

     List<Func<string>> testList = new List<Func<string>>(); 

     testList.Add(() => GetData(someLocalVar)); 
     testList.Add(() => GetData(2)); 
     testList.Add(test); 
     testList.Add(test2); 

     someLocalVar = "something else"; 

     foreach(var func in testList) 
     { 
      Console.WriteLine(func()); 
     } 

     Console.ReadKey(); 
    } 
} 

結果是:

enter image description here

+0

你甚至可以使用Action版本,如果他們*做*返回的東西。你可以在lambda中包含賦值。這可能是危險的,但有時它可能是你想要的。 – Magus

+0

是的,或者您也可以爲您的操作(而不是lambda)創建一個{}主體,然後執行任何操作,然後不會從操作中返回任何內容。很多可能性。 –

+0

我錯過了什麼,因爲我不認爲代碼甚至編譯...我得到「委託」System.Func 「不帶1個參數」。我敢肯定,你不能僅僅通過傳遞參數來將代表添加到列表中,就像調用方法一樣... – evanmcdonnal

0

你可以使用C#代表:

委託是表示與 特定參數列表的方法的引用和返回類型的類型。當您實例化 委託時,可以將其實例與任何具有 兼容簽名和返回類型的方法相關聯。您可以通過委託實例調用(或調用) 方法。代表用於將 方法作爲參數傳遞給其他方法。事件處理程序僅僅是通過代理調用的方法 。您可以創建一個自定義的 方法,如某個事件發生時,諸如Windows控件的類可以調用您的方法 。下面的例子顯示了一個委託 聲明:

更多內容: http://msdn.microsoft.com/en-us/library/ms173171.aspx

1

婁是如何的示例使代表和他們的論據的集合,然後調用t稍後在不知道方法定義的情況下下襬。據我所知,如果你想在一次通用調用中調用不同定義的方法,你必須做這樣的事情。

List<Tuple<delegate, object[]>> delegates = new List<Tuple<delegate, object[]>>(); 

    delegates.Add(new Tuple<delegate, object[]>(new Func<Arg1Type, Arg2Type, ReturnType>(MyFunctionName), new object[] { arg1, arg2 }); 

    foreach (Tuple<delegate, object[]> d in delegates) 
    { 
     d.Item1.DynamicInvoke(d.Item2); 
    } 
+0

我想我寧願只是收集'Action',並在lambda中傳遞參數和函數。可能會更清潔。 – Magus

+0

@Magus我的代碼有點草率,那些必須是'Func',因爲它們有一個返回類型,我只是沒有把它分配到任何地方。我不知道在lambda表達式中傳遞參數的代碼,據我所知它不能編譯。其實,100%不會編譯。當你說'List >'a和b是參數,c是返回類型。他聲明那些返回類型爲「Data」的funcs然後嘗試傳遞它們沒有說他們會採用的隨機參數...您必須使用對象數組和「DynamicInvoke」來獲得這種行爲。 – evanmcdonnal

+0

我的意思是沿'字符串b; Action a =()=> b = SomeFunction(param1,param2);'其中b應該是一個字段。它很乾淨,並且做同樣的事情。 – Magus

0

可以傳遞函數用參數是這樣的:

public void strategy<R, T1, T2>(Func<R, T1, T2> f); 

public bool predicate(string a, string b); 

strategy<bool, string, string>(predicate); 

第一行聲明接受功能f功能strategy(); 該函數返回類型R並採用T1T2類型的兩個參數。

第二行定義了一個函數,返回bool並接受兩個string

第三行調用傳遞謂詞作爲參數的策略。

0

不是一定要了解你想要達到什麼目的,但基本上如果你的服務暴露了GetData(int)方法和GetData(string)方法以及異步代理,你應該異步調用使用的東西都喜歡:

var getData = proxy.GetDataAsync(2); 
var getData2 = proxy.GetDataAsync("data"); 

await Task.WhenAll(getData, getData2); 

// Gets the result using getData.Result...etc. 
1

我不會在這裏使用委託,因爲那樣你就受到類型的限制並解決它變得可怕和過於複雜。我只是有一個回調,它可以讓你在ServiceClient設置完成後自由統治。我認爲這是一個有名字的模式,但我不知道。

interface IProxyActionCallback 
{ 
    void DoProxyStuff(ServiceClient proxy); 
} 

void MyMethod(IProxyActionCallback callback) 
{ 
    try 
    { 
     ServiceClient proxy = new ServiceClient(); 
     proxy.ClientCredentials.UserName.UserName = "user"; 
     proxy.ClientCredentials.UserName.Password = "password"; 

     callback.DoProxyStuff(proxy); 

     proxy.Close(); 
    } 
    catch (FaultException ex) 
    { 
     // handle the exception  
    } 
} 

然後調用類的方法:

MyMethod(new DoSpecificStuff()); 

哪裏DoSpecificStuff是實現接口,並允許你做代理的特定呼叫類:

class DoSpecificStuff : IProxyActionCallback 
{ 
    public void DoProxyStuff(ServiceClient proxy) 
    { 
     proxy.GetData(2); 
     if (proxy.State = CommunicationState.Opened) 
     { 
      proxy.GetData("data"); 
     } 
    } 
} 

所以你將有大量的類實現接口,並且它們都「共享」同一個try-catch鍋爐板代理的東西。