2009-10-07 11 views
7

Nie mogę dowiedzieć się, jak zrobić "znaleźć" na liście, którą mam na podstawie wartości, które będę przekazywać w czasie wykonywania. Jeśli zobaczysz mój poniższy kod, chcę móc znaleźć CustomClass na liście, dla której jego parametr Path jest równy X, gdzie X zostanie zdefiniowany w czasie wykonywania.C# List.Find method - jak mogę przekazać wartość do predykatu?

Jakieś pomysły, jak zrobić takie znalezisko na liście? Czy nie jest to możliwe bez napisania iteratora i ręcznego znalezienia? W takim razie być może jest to kolekcja kluczy, którą powinienem użyć zamiast tego?

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. Muszę przyznać, że nie nadążam rzeczy źródłowe w doco na http://msdn.microsoft.com/en-us/library/x0b5b5bc.aspx

Odpowiedz

12

Użyj lambda:

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

lub jeśli nadal chcesz nazwanego metody:

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

dzięki chłopaki - przy okazji - czy powinienem był (jeśli byłem bardziej na C#) pracował to po prostu patrząc na składnię metody w doco? Parametry, dopasowanie, Typ: System .. :: Predykat <(Of <(T>)>), Predykat <(Of <(T>)>) delegat definiujący warunki elementu do wyszukiwania ... – Greg

+0

Typ parametru ogranicza typ delegat możesz przejść do metody, a tym samym podpis metody lub lambda, której musisz użyć do utworzenia tego delegata. Nie oznacza to samo w sobie stosowania lambdas, niż jakikolwiek inny typ delegata. Dokumentacja dla lambdas znajduje się tutaj: http://msdn.microsoft.com/en-us/library/bb397687.aspx –

+1

Delegat jest podobny do wskaźnika funkcji. Patrząc na sygnaturę ('delegate bool Predicate (T obj)') można zobaczyć, że predykat jest funkcją (metodą), która przyjmuje ** pojedynczy parametr typu T ** i zwraca wartość ** bool ** . – Groo

1

Możesz napisać

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

Metoda find() zwraca wartość null, jeśli żaden element nie został znaleziony pasujący predykat.

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

Dlaczego oświadczenie lambda? –

+0

PEBCAK. Pierdnięcie mózgu. Wybierz. –

0

Spróbuj użyć metody anonimowej wyszukiwania i użyć dowolnej zmiennej lokalnej, który ma w jej wnętrzu . Jeśli nie jest to satysfakcjonujące, wywołaj zwykle zdefiniowaną metodę delegowania.

1

kompletności sake tylko, o to co byś zrobił, jeśli nie chcesz używać 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; 
    } 
} 

a następnie użyć go jako:

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

nocie, że jesteś przekazanie referencji dla metody, a nie wyniku metody - vs .

Sprawdź ten wątek także: Predicate Delegates in C#.

0

. Odpowiedź .NET 2.0 przy użyciu anonimowego uczestnika (należy pamiętać, że działa to tylko dla języka C#, VB.NET nie ma anonimowych delegatów).

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

W poście Pavel oznaczona jako odpowiedź, myślę, że linia:

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

powinno być zamiast jak:

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

To dlatego, że expresion z lewej strony => jest definicja zmiennej (typ wywodzi się z wyrażenia) - W przeciwnym wypadku kompilator podałby błąd redefinicji.

Wyrażenie to może być także napisane wyraźnej definicji jako:

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

Oto rozwiązanie, które użyłem.Musiałem przekazać kilka argumentów i nie chciałem używać niczego, co uniemożliwiłoby mi edycję metody podczas uruchamiania, więc wymyśliłem to.

Oczywiście, jeśli chcesz, możesz zmienić ją na metodę ogólną (prawidłowa?) Za pomocą argumentów typu. Dotyczy to również problemu lambdas w metodzie. Nie wiem, czy to dotyczy również metod anonimowych, czy nie, ale jest już oddzielne, więc nic wielkiego.

Nie wiem, czy refleks będzie miał działanie, czy nie.

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

Powiem, że nie sprawdziłem jeszcze dwukrotnie, czy pozwala mi wprowadzać zmiany, ale poza tym działa bardzo dobrze. –