2012-01-27 12 views
5

Tengo una expresión lambda en línea que me gustaría usar en toda mi aplicación. Parece que no puedo encontrar una referencia sobre cómo hacer esto con más parámetros que el elemento que se prueba. Aquí hay un ejemplo rápido de lo que tengo actualmente.¿Puedo utilizar un método en lugar de la expresión Lambda con parámetros adicionales

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 

sé que el IEnumerable.Where acepta un método con el tipo de elemento como un parámetro y un valor booleano de regresar.

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

Private Function FindName(Name As String) As Boolean 
    Return Name Like "*Jo*" 
End Function 

Me gustaría pasar la variable de búsqueda a FindName también. Simplemente no puedo entender la sintaxis calculada para lograr esto. La única solución de trabajo que he encontrado es pasar todo a una función para realizar la declaración original.

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 

No se siente obligado a responder en VB.

+0

acorta mi [enfoque delegado] (http://stackoverflow.com/a/9036948/284240). –

Respuesta

6

Lo bueno con las expresiones lambda es que permiten cierres para capturar automáticamente las variables que son locales su alcance Por ejemplo (perdón por el C#):

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

En el código anterior, la variable Search en realidad se está encapsulado en un cierre. Si desea pasar sólo un método, que tendrá que simular lo que hacen los cierres con una estructura de clase real:

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); 

Sin embargo, esta estrategia sólo es útil en un pequeño subconjunto de los casos. Encuentro que generalmente es mejor usar una expresión lambda que pase las variables apropiadas a la función que hace todo el trabajo.

1

me gustaría utilizar un método de extensión: -

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

Después de haber leído su pregunta nuevamente, ¿no estoy 100% seguro de que esto es lo que realmente está haciendo? – pingoo

+0

Lo que buscaba puede no existir después de leer las respuestas hasta el momento. Pero la extensión limpiará la función separada, por lo que en mi caso, la extensión funcionará bien. –

-1

no creo que se puede pasar en más argumentos al método Where, pero se puede configurar el parámetro de búsqueda como un miembro de la clase, que el método FindName puede acceder. Por ejemplo (Voy a escribir esto en C# ya que es lo que estoy más familiarizado):

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

Esto es una mala práctica. Está utilizando estado global para resolver un problema local. Esto puede conducir fácilmente a problemas. Si devuelve el resultado, por ejemplo, no tiene control sobre cuándo realmente se ejecuta la consulta, mientras tanto, la variable podría cambiar. Mismo problema si tiene múltiples hilos. Use LINQ directamente o un método de extensión como otros sugirieron. – aKzenT

+0

Pensando en lo que dijo puedo ver lo que quiere decir y ahora estoy de acuerdo con usted, nunca funcionaría en un contexto de múltiples subprocesos tampoco. –

0

Se puede usar un Func(Of T, TResult) Delegate incluso con múltiples parámetros:

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" ' 
Cuestiones relacionadas