代表组合不端行为

时间:2013-03-06 20:57:39

标签: c# delegates

提供以下代码:

List<string> aux = new List<string>();

aux.Add("a");
aux.Add("ab");
aux.Add("ac");
aux.Add("abc");
aux.Add("b");
aux.Add("bc");
aux.Add("c");
aux.Add("e");
aux.Add("f");

Func<string, bool> searchForA = (f => f.Contains("a"));
Func<string, bool> searchForC = (f => f.Contains("c"));
Func<string, bool> searchForF = (f => f.Contains("f"));

有人可以向我解释为什么会这样打电话

aux.Where(searchForA + searchForF + searchForC).ToList();

返回“ac”,“abc”,“bc”和“c”,结果与

相同
aux.Where(searchForC).ToList();

我的意思是,第一次查询时是“a”,“ab”还是“F”?

编辑:我使用了委托组合,因为我想动态定义搜索模式!

EDIT2:对新的示例代码进行重大编辑检查,这是我尝试解决的问题

string[] searchFor = "a c f".Split(' ');

Func<string, bool>[] delegates = new Func<string, bool>[searchFor.Length];
for (int i = 0; i < searchFor.Length; i++)
{
    string search = searchFor[i]; // Make sure the lambda does not capture a loop variable!
    delegates[i] = new Func<string, bool>(f => f.Contains(search));
}

List<string> aux = new List<string>(); 
aux.Add("a");
aux.Add("ab");
aux.Add("ac");
aux.Add("abc");
aux.Add("b");
aux.Add("bc");
aux.Add("c");
aux.Add("e");
aux.Add("f");

List<string> result = aux.Where((Func<string, bool>)Delegate.Combine(delegates)).ToList();

1 个答案:

答案 0 :(得分:13)

调用两个非void返回委托的组合具有语义“调用第一个,丢弃结果,调用第二个,返回结果”。它没有语义“如果它们碰巧返回or”则称它们为“bool”。请记住,委托组合必须适用于任何委托类型;为什么运行时应该为bool返回委托而不是or语义选择and语义?它应该为返回string的代理连接字符串做什么?如果你组合int返回的代表应该添加数字吗?

组合结果的问题无法以一致的方式解决,因此选择忽略除最后一个之外的所有结果。

如果您想要or两个谓词,那么您可以自己轻松完成。这是一个方便的扩展方法:

static Func<T, bool> Or<T>(this Func<T, bool> f1, Func<T, bool> f2)
{ return t => f1(t) || f2(t); }

现在你可以说

...Where(searchForA.Or(searchForC).Or(searchForF))...

您还可以将其扩展到多个代理:

static Func<T, bool> OrMany<T>(params Func<T, bool>[] fs)
{ 
    Func<T, bool> result = t => false;
    foreach(Func<T, bool> f in fs)
        result = result.Or(f);
    return result;
}

现在,您可以将“扩展表单”与代表列表一起使用:

...Where(OrMany(searchForA, searchForC, searchForf))...
带有一系列代表的

或“未扩展表单”:

Func<string, bool>[] delegates = whatever;
...Where(OrMany(delegates))...