2009-10-07 18 views
7

No puedo encontrar la forma de hacer un "buscar" en una lista que he basado en el uso de un valor que voy a pasar en tiempo de ejecución. Si ve mi código a continuación, quiero poder encontrar CustomClass en la Lista cuyo parámetro Path es igual a X, donde X se definirá en tiempo de ejecución.C# List.Find method - ¿cómo puedo pasar un valor en el predicado?

¿Alguna idea de cómo hacer un tal hallazgo en una lista? ¿O esto no es posible sin escribir un iterador y hacer el hallazgo manualmente? ¿En cuyo caso tal vez haya una colección con clave que debería usar en su lugar?

private List<CustomClass> files; 

    public void someMethod() 
    { 
     Uri u= new Uri(www.test.com); 
     CustomClass cc = this.files.find(matchesUri(u)); // WON'T LET ME DO THIS 
    } 

    private static bool matchesUri(List<CustomClass> cc, Uri _u) 
    { 
     return cc.Path == _u;   } 


public class CustomClass 
{ 
    private Uri path; 

    public Uri Path 
    { 
     get { return this.path; } 
     set { this.path = value; } 
    } 
} 

PS. Debo admitir que no comprendo muy bien las cosas en el predicado mana en http://msdn.microsoft.com/en-us/library/x0b5b5bc.aspx

Respuesta

12

Use un lambda:

Uri u = new Uri("www.test.com"); 
CustomClass cc = this.files.Find(cc => cc.Path == u); 

o si todavía quiere un método denominado:

static bool matchesUri(CustomClass cc, Uri _u) 
{ 
    return cc.Path == _u; 
} 

Uri u = new Uri("www.test.com"); 
CustomClass cc = this.files.Find(cc => matchesUri(cc, u)); 
+0

gracias chicos - dicho sea de paso - ¿debería haber podido (si estaba más arriba en C#) resolver esto solo mirando la sintaxis del método en el doco? (es decir, Parámetros, coincidencia, Tipo: System .. ::. Predicate <(Of <(T>)>), El predicado <(Of <(T>)>) delegado que define las condiciones del elemento para buscar ... – Greg

+0

El tipo de parámetro restringe el tipo de delegar puede pasar al método y, por lo tanto, a la firma del método o lambda que debe usar para crear ese delegado. No significa, en sí mismo, el uso de lambdas más que cualquier otro tipo de delegado. La documentación para lambdas está aquí: http://msdn.microsoft.com/en-us/library/bb397687.aspx –

+1

Delegate es similar a un puntero de función. Al mirar la firma ('delegado bool Predicate (T obj)') puede ver que un predicado es una función (método) que toma un ** único parámetro de tipo T **, y devuelve ** bool ** . – Groo

1

Puede escribir

CustomClass cc = this.files.Find(p=> p.Path == u); 

El método Find() devuelve un valor nulo si no se encontró ningún elemento que coincida con el predicado.

0
public void someMethod() 
{ 
    Uri u= new Uri("www.test.com"); 
    CustomClass cc = this.files.find(p => { return p.Path == u; }); 
} 
+0

¿Por qué declaración lambda? –

+0

PEBCAK. Pedo cerebral. Elige tu opción. –

0

Trate de usar método anónimo para la búsqueda y utilizar cualquier variable local que desee dentro de ella . Si eso no es satisfactorio, llame a su método delegado normalmente definido.

1

Para completarlo solamente, aquí es lo que haría si no desea utilizar una lambda:

// Predicate must be a method with a single parameter, 
// so we must pass the other parameter in constructor 

public class UriMatcher 
{ 
    private readonly Uri _u; 
    public UriMatcher(Uri u) 
    { 
     _u = u; 
    } 

    // Match is Predicate<CustomClass> 
    public bool Match(CustomClass cc) 
    { 
     return cc.Path == _u; 
    } 
} 

Y luego usarlo como:

public void someMethod() 
{ 
    Uri u = new Uri("www.test.com"); 
    UriMatcher matcher = new UriMatcher(u); 
    CustomClass cc = this.files.Find(matcher.Match); 
} 

Tenga en cuenta que usted está pasando una referencia a un método, no el resultado del método - Match vs Match().

Consulte este hilo también: Predicate Delegates in C#.

0

.NET 2.0 responde utilizando un delegado anónimo (tenga en cuenta que esto solo funciona para C#, VB.NET no tiene delegados anónimos).

public void someMethod() 
{ 
    Uri u= new Uri("www.test.com"); 
    CustomClass cc = this.files.find(delegate(CustomClass oTemp) { return oTemp.Path == u;}); 
} 
0

En el post de Pavel marcado como respuesta, creo que la línea:

CustomClass cc = this.files.Find(cc => cc.Path == u); 

debe estar en su lugar como:

CustomClass cc = this.files.Find(cc2 => cc2.Path == u); 

Esto es debido a que la expresion a la izquierda de => es una definición variable (el tipo se deduce de la expresión) - De lo contrario, el compilador daría un error de redefinición.

Esta expresión también se puede escribir con una definición explícita como:

CustomClass cc = this.files.Find((CustomClass cc2) => cc2.Path == u); 
0

Aquí es una solución que he usado.Necesitaba pasar varios argumentos y no quería usar nada que me impidiera editar el método durante el tiempo de ejecución, así que se me ocurrió esto.

Obviamente, si lo desea, podría cambiarlo a un método genérico (¿con el término correcto?) Utilizando los argumentos de tipo. Esto también soluciona el problema de lambdas en un método. No estoy seguro de si eso se aplica también a los métodos anónimos o no, pero ya está separado, así que no es gran cosa.

No sé si el reflejo tendría un golpe de rendimiento o no.

private Predicate<ItemData> FindItemData(string search, string fieldName) 
{ 
    var field = typeof(ItemData).GetField(fieldName); 
    return delegate(ItemData item) { return (string)field.GetValue(item) == search; }; 
} 

//in another method... 
itemlist.Find(FindItemData(e.Row[2].ToString(), "ItemName")); 
+0

Diré que no he comprobado dos veces que me permite hacer modificaciones, pero de lo contrario, funciona muy bien. –

Cuestiones relacionadas