C # List.Find метод - как я могу передать значение в предикат? - PullRequest
7 голосов
/ 07 октября 2009

Я не могу понять, как сделать «поиск» в списке, который у меня есть, на основе использования значения, которое я передам во время выполнения. Если вы видите мой код ниже, я хочу иметь возможность найти CustomClass в списке, для которого его параметр Path равен X, где X будет определяться во время выполнения.

Есть идеи, как сделать такую ​​находку в Списке? Или это невозможно без написания итератора и поиска вручную? В каком случае, возможно, существует коллекция ключей, которую я должен использовать вместо этого?

   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. Я должен признать, что я не совсем следую предикатным вещам в документе в http://msdn.microsoft.com/en-us/library/x0b5b5bc.aspx

Ответы [ 8 ]

12 голосов
/ 07 октября 2009

Используйте лямбду:

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

или если вы все еще хотите именованный метод:

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));
1 голос
/ 07 октября 2009

Только для полноты, вот что вы бы сделали, если не хотите использовать лямбду:

// 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;
    }
}

А затем используйте его как:

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

Обратите внимание, что вы передаете ссылку на метод , а не результат метода - Match против Match().

Проверьте эту ветку также: Предикаты делегатов в C # .

1 голос
/ 07 октября 2009

Вы можете написать

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

Метод Find () возвращает ноль, если не найдено ни одного элемента, соответствующего предикату.

0 голосов
/ 02 июля 2013

Вот решение, которое я использовал. Мне нужно было передать несколько аргументов, и я не хотел использовать что-либо, что мешало бы мне редактировать метод во время выполнения, поэтому я пришел к этому.

Очевидно, что если вы хотите, вы можете изменить его на универсальный метод (правильный термин?), Используя аргументы типа. Это также позволяет обойти проблему лямбд в методе. Не уверен, относится ли это также к анонимным методам или нет, но это уже отдельно, так что ничего страшного.

Я не знаю, отразится ли отражение на производительности или нет.

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 голосов
/ 01 августа 2012

В посте Павла, помеченном как ответ, я думаю, что строка:

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

должно быть вместо:

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

Это потому, что выражение слева от => является определением переменной (тип выводится из выражения) - в противном случае компилятор выдаст ошибку переопределения.

Это выражение также может быть записано с явным определением как:

CustomClass cc = this.files.Find((CustomClass  cc2) => cc2.Path == u);
0 голосов
/ 07 октября 2009

.NET 2.0 ответ с использованием анонимного делегата (обратите внимание, что это работает только для C #, VB.NET не имеет анонимных делегатов).

public void someMethod()
{
  Uri u= new Uri("www.test.com");
  CustomClass cc = this.files.find(delegate(CustomClass oTemp) { return oTemp.Path == u;});
}
0 голосов
/ 07 октября 2009

Попробуйте использовать анонимный метод для поиска и использовать любую локальную переменную, которая вам нужна. Если это неудовлетворительно, вызовите ваш обычно определенный метод делегата.

0 голосов
/ 07 октября 2009
public void someMethod()
{
    Uri u= new Uri("www.test.com");
    CustomClass cc = this.files.find( p => { return p.Path == u; } );
}
...