Список C #.Найти метод - как я могу передать значение в предикат?
-
20-09-2019 - |
Вопрос
Я не могу понять, как выполнить "поиск" в списке, который у меня есть, на основе использования значения, которое я передам во время выполнения.Если вы видите мой приведенный ниже код, я хочу иметь возможность найти 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"));