C# List.Find方法 - 如何将值传递到谓词函数中?

7
我不知道如何基于传入的值,在List中执行“查找”操作。若您查看以下代码,我想查找CustomClass在List中的Path参数等于X的对象,其中X将在运行时定义。
有没有办法在List中实现这样的查找?还是说必须手动编写迭代器并进行查找?如果是这样,也许应该考虑使用键控集合来代替。
   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; }
    }
}

补充一下,我必须承认我并没有完全理解文档中关于谓词部分的内容,文档链接如下:http://msdn.microsoft.com/en-us/library/x0b5b5bc.aspx

8个回答

12

使用lambda表达式:

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

谢谢大家 - 顺便问一下,如果我对C#更熟悉的话,我是不是可以通过查看文档中方法的语法来解决这个问题?(即:参数、匹配、类型:System..::.Predicate<(Of <(T>)>),定义要搜索的元素条件的 Predicate<(Of <(T>)>) 委托...) - Greg
参数类型限制了您可以传递给方法的委托类型,因此您必须使用的方法或lambda的签名来创建该委托。它本身并不意味着使用lambda,就像任何其他委托类型一样。有关lambda的文档在此处:http://msdn.microsoft.com/en-us/library/bb397687.aspx - Pavel Minaev
1
委托(Delegate)类似于函数指针。从签名(delegate bool Predicate<T>(T obj))可以看出,谓词是一个接受单个类型为 T 的参数并返回布尔值的函数(方法)。 - vgru

1

你可以写

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

如果没有找到与谓词匹配的元素,则Find()方法返回null。


1

仅为完整起见,以下是如果您不想使用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;
    }
}

然后将其用作:

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

请注意,您正在传递一个方法的引用,而不是该方法的结果 -- Match vs Match()
还要查看此线程:C#中的Predicate委托

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

PEBCAK。脑抽了。随便选一个。 - Matthew Scharley

0

.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

这里是我使用的一种解决方案。我需要传递多个参数,并且不想使用任何会阻止我在运行时编辑该方法的东西,所以我想出了这个方法。

显然,如果您想要的话,可以将其更改为使用类型参数的通用方法(正确的术语?)。这也解决了方法中的lambda问题。不确定是否也适用于匿名方法,但已经分开,所以没什么大不了的。

我不知道反射是否会带来性能损失。

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

我会说我没有双重检查它是否允许我进行编辑,但除此之外它运行得非常好。 - Arlen Beiler

0

尝试使用匿名方法进行搜索,并在其中使用任何本地变量。如果不满意,调用通常定义的委托方法。


0
在 Pavel 标记为答案的帖子中,我认为这一行是:
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);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接