2012-01-27 16 views
5

Mam wyrażenia lambda inline, które chciałbym użyć całej mojej aplikacji. Ja po prostu nie może się znaleźć odniesienie w jaki sposób to zrobić z więcej parametrów niż element w fazie testów. Oto krótki przykład tego, co obecnie mam.mogę użyć metody zamiast wyrażenia lambda z dodatkowymi parametrami

Private Sub Test() 
    Dim List As New List(Of String) From {"Joe", "Ken", "Bob", "John"} 
    Dim Search As String = "*Jo*" 
    Dim Result = List.Where(Function(Name) Name Like Search) 
End Sub 

wiem, że IEnumerable.Where przyjmuje metodę z typem elementów jako parametr i powracającego logiczną.

Chciałbym przekazać zmienną Search również do FindName. Po prostu wydaje mi się, że nie mogę uzyskać takiej składni. Jedynym rozwiązaniem, które wymyśliłem, jest przekazanie wszystkiego do funkcji umożliwiającej wykonanie oryginalnego komunikatu.

Private Sub Test() 
    Dim List As New List(Of String) From {"Joe", "Ken", "Bob", "John"} 
    Dim Search As String = "*Jo*" 
    Dim Result = FindName(List, Search) 
End Sub 

Private Function FindName(List As IEnumerable(Of String), Search As String) As IEnumerable(Of String) 
    Return List.Where(Function(Name) Name Like Search) 
End Function 

Nie czuj się zobowiązany do odpowiedzi w VB.

+0

skrócona moje podejście delegata [] (http://stackoverflow.com/a/9036948/284240). –

Odpowiedz

6

Zaletą wyrażeń lambda jest to, że pozwalają one zamknięcia automatycznie uchwycić zmienne, które są lokalne dla twój zakres. Na przykład (przeproszeniem C#)

List.Where(i => FindName(i, Search)); 

W powyższym kodzie zmiennym Search jest rzeczywiście zamknięty w zamknięcia. Jeśli chcesz po prostu przekazać metodę, będziesz musiał symulować zamknięcia co zrobić z rzeczywistej struktury klasowej:

public class NameFinder 
{ 
    private string _search; 
    public NameFinder(string search) { 
     _search = search; 
    } 
    public bool Match(string item) { 
     // C# equivalent of "return item LIKE _search" 
    } 
} 

// Usage 
var nameFinder = new NameFinder(Search); 
List.Where(nameFinder.Match); 

Jednak strategia ta jest użyteczna tylko w niewielkiej liczbie przypadków. Uważam, że to zwykle najlepiej jest po prostu użycie wyrażenia lambda, która przechodzi odpowiednie zmienne do funkcji, która wykonuje całą pracę.

1

użyłbym metodę rozszerzenia: -

Module Module1 

    Sub main() 
     Dim List As New List(Of String) From {"Joe", "Ken", "Bob", "John"} 
     Dim Search As String = "*Jo*" 
     Dim Result = List.FindName(Search) 
    End Sub 


End Module 

Public Module Extensions 

    <System.Runtime.CompilerServices.Extension()> 
    Public Function FindName(List As IEnumerable(Of String), Search As String) As IEnumerable(Of String) 

     Return List.Where(Function(Name) Name Like Search) 

    End Function 

End Module 
+0

Po przeczytaniu pytanie znowu nie jestem w 100% pewien, że to jest to, co właściwie chodzi? – pingoo

+0

Co miałem po nie może istnieć po przeczytaniu odpowiedzi tak daleko. Ale rozszerzenie oczyści oddzielną funkcję, więc w moim przypadku rozszerzenie będzie działało dobrze. –

-1

I nie sądzę, że można przejść na więcej argumentów do metody Where, ale można ustawić parametr szukania jako członek klasy której metoda FindName można uzyskać dostęp. Na przykład (będę pisać w C#, jak to, co jestem bardziej zaznajomieni z):

string search = "Ken"; 

private void Test() 
{ 
    var list = new List<string>() { "Joe", "Ken", "Bob", "John" }; 
    // Set search member to whatever you need before calling query 
    search = "Joe"; 
    var result = list.Where(FindName); 
} 

private bool FindName(string name) 
{ 
    // Predicate method will compare against whatever class member is set to 
    return name == search; 
} 
+1

To zła praktyka. Używasz globalnego stanu do rozwiązania lokalnego problemu. Może to łatwo prowadzić do problemów. Jeśli zwrócisz wynik, na przykład nie masz kontroli nad faktycznym wykonaniem zapytania, zmienna może się zmienić. Ten sam problem, jeśli masz wiele wątków. Użyj LINQ bezpośrednio lub metody rozszerzenia, jak sugerowali inni. – aKzenT

+0

Przeanalizowanie tego, co powiedziałeś, mogę zobaczyć, co masz na myśli, a teraz się z tobą zgadzam, nigdy nie będzie działać w kontekście wielowątkowym. –

0

można użyć Func(Of T, TResult) Delegate nawet z wieloma parametrami:

Dim names = {"Joe", "Ken", "Bob", "John", "Otto"} 
Dim matchesPattern As Func(Of String, String, Boolean) = 
    Function(input, searchPattern) input Like searchPattern 
Dim results = names.Where(Function(name) matchesPattern(name, "?o*")) 
' returns "Joe", "Bob" and "John" ' 
Powiązane problemy