2009-04-23 62 views
1

問題:我剛剛寫了第一個使用c#lambda表達式的代碼。它有效,但我不確定這是否是最好的方式。任何建議更好的方式來做lambda表達式?在表達式中有許多代碼行似乎很奇怪,就像我在下面做的那樣。c#lambda表達式 - 將代表結果添加到通用列表

背景:我有一個通用的代表列表。每個委託函數返回一個枚舉值,指示函數中發生了什麼。在對委託進行評估時,如果它不是特定的枚舉值,我需要將枚舉添加到列表中。

免責聲明:這裏的代碼是非常通用的,真正的代碼實際上確實在代理中確定返回值的東西!


class Class1 
{ 
    public enum WhatHappened 
    { 
     ThingA, 
     ThingB, 
     Nothing 
    } 

    private delegate WhatHappened del(); 

    public static List<WhatHappened> DoStuff() 
    { 
     List<del> CheckValues = new List<del>(); 

     List<WhatHappened> returnValue = new List<WhatHappened> { }; 

     CheckValues.Add(delegate { return method1(); }); 
     CheckValues.Add(delegate { return method2(); }); 

     CheckValues.ForEach(x => 
     { 
      WhatHappened wh = x(); 
      if (wh != WhatHappened.Nothing) 
       returnValue.Add(wh); 
     }); 

     return returnValue; 

    } 

    private static WhatHappened method1() 
    { 
     return WhatHappened.Nothing; 
    } 

    private static WhatHappened method2() 
    { 
     return WhatHappened.ThingA; 
    } 

} 

注:我本來喜歡將所有的項目(見下文),然後除去我不想讓那些(WhatHappened.Nothing)拉姆達。

CheckValues.ForEach(x => returnValue.Add(x())); 

回答

9

好吧,幾點建議:

  • 不要叫你的委託del。在這種情況下,我會使用Func<WhatHappened> - 但如果您想聲明自己的委託類型,給它一個更具描述性的名稱,並服從.NET命名約定。
  • 而不是使用匿名方法添加到CheckValues的,你可以用:

    CheckValues.Add(method1); 
    CheckValues.Add(method2); 
    

    編譯器將方法組轉換爲代表。

  • 我建議不使用Pascal大小寫的局部變量名開始。

  • returnValues您的集合初始是不是真的爲你做任何事情 - 只是調用List<T>構造正常,或者用我下面的代碼,它不需要一個局部變量開始。
  • 如果您的列表真的只中有兩名代表,我只是分別給他們打電話。這簡單得多。
  • 否則,你的確可以使用LINQ作爲賈裏德建議,但我會做到這一點略有不同:

    return CheckValues.Select(x => x()) 
            .Where(wh => wh != WhatHappened.Nothing) 
            .ToList(); 
    

編輯:作爲建議,這裏是完整的例子。這不是完全一樣丹尼斯的,但...我已經做了一些改動:)的

public static List<WhatHappened> DoStuff() 
{ 
    var functions = new List<Func<WhatHappened>> { Method1, Method2 }; 

    return functions.Select(function => function()) 
        .Where(result => result != WhatHappened.Nothing) 
        .ToList(); 
} 

(我假設method1method2已更名爲符合命名規則。當然,在實際生活中,我敢肯定,他們會擁有更多有用的名稱反正...)

1

在我看來,基於這個例子,它看起來很好。您可以通過更換重構甚至更多:

CheckValues.Add(delegate { return method1(); }); 
CheckValues.Add(delegate { return method2(); }); 

有:

CheckValues.Add(() => WhatHappened.Nothing); 
CheckValues.Add(() => WhatHappened.ThingA); 
3

您可以通過鏈接選擇(圖)去拉姆達一路凡(過濾器),而不是多個FOR循環和IF語句

// get results from the list of functions 
var results = CheckValues.Select(x => x()); 

// filter out only the relevant ones. 
var returnValues = results.Where(x => x != WhatHappened.Nothing); 

基本上,你要多想declaratively代替imperatively與lambda一起工作時。它會幫助你編寫更優雅的代碼。

2

編寫以下代碼而不是使用委託關鍵字更具有慣用性。但它並沒有改變基礎功能。

CheckValues.Add(() => method1()); 

另外,我覺得它更可讀傳遞給ForEach改寫爲以下

CheckValues = CheckValues. 
    Select(x => x()). 
    Where(wh => wh != WhatHappened.Nothing). 
    ToList(); 
+0

這不會編譯除非你有一個foreach擴展方法撿到一些可枚舉善良。我也喜歡在行首寫上我的點:) – 2009-04-23 18:38:02

+0

@Jon,我很習慣我的自定義LINQ方法,我忘記它們默認情況下不存在。已更新以避免我不擁有的擴展方法。我老實說在點之前或點之後來回點。我以前的偏好是點。但有些語言我用需要的字符爲(PowerShell和VB.Net)之後,所以我漂來回;) – JaredPar 2009-04-23 18:48:54

3

我會簡單地使用LINQ的,不過這只是我:

public static List<WhatHappened> DoStuff() 
{ 
    List<del> CheckValues = new List<del>(); 

    List<WhatHappened> returnValue = new List<WhatHappened>(); 

    CheckValues.Add(method1); 
    CheckValues.Add(method2); 

    return CheckValues 
       .Select(dlg => dlg()) 
       .Where(res => res != WhatHappened.Nothing) 
       .ToList(); 
} 

請注意,你也可以用代替聲明Func鍵代表類型,如果你願意,但在這種情況下不那麼簡單。 此外,我會返回一個IEnumerable<WhatHappened>而不是一個列表,但它都是關於上下文。

1

這裏有一個LINQ的免費解決方案:

return CheckValues 
    .ConvertAll<WhatHappened>(x => x()) 
    .FindAll(y => y != WhatHappened.Nothing); 

警告

這並不是最高效的解決方案,因爲它會重複兩次。

0

我無法捉摸的代碼的目的。但是在這裏去。
使用代表鏈接 更新:和喬恩ñJared的帖子

private delegate WhatHappened WhatHappenedDelegate(); 

public static List<WhatHappened> DoStuff() 
{ 
    WhatHappenedDelegate delegateChain = null; 
    delegateChain += method1; 
    delegateChain += method2; 

    return delegateChain.GetInvocationList() 
      .Select(x => (WhatHappened) x.DynamicInvoke()) 
      .Where(wh => (wh != WhatHappened.Nothing)) 
      .ToList<WhatHappened>(); 
}