Список C #.Найти метод - как я могу передать значение в предикат?

StackOverflow https://stackoverflow.com/questions/1529846

Вопрос

Я не могу понять, как выполнить "поиск" в списке, который у меня есть, на основе использования значения, которое я передам во время выполнения.Если вы видите мой приведенный ниже код, я хочу иметь возможность найти 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

Это было полезно?

Решение

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

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

Другие советы

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

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

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

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

// 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#.

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

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

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

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

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

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

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

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

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"));
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top