我正在尝试编写一个补数函数,以便在提供函数f
时返回一个函数,当提供与f
相同的输入时,它返回逻辑上相反的函数。
已经在VS2017中放入了类似的代码,但没有出现任何错误,但是我尚无法运行代码以查看其是否能按预期工作。我的意图是先在一个repl中尝试一下,看看它是否会按预期进行。我在那里使用的代码是这样的:
public static Func<T, bool> Complement<T>(Func<T, bool> f)
{
return (T x) => !f(x);
}
public static bool GreaterThanTwo (int x) {
return x > 2;
}
static public void Main(string[] args)
{
Func<int, bool> NotGreaterThanTwo = Complement(GreaterThanTwo);
Console.WriteLine(NotGreaterThanTwo(1));
}
在代表中,我得到了错误:
main.cs(17,42):错误CS0411:方法的类型参数 无法从中推断出MainClass.Complement(System.Func) 用法。尝试显式指定类型参数编译 失败:1个错误,0个警告编译器退出状态1
我已经查看了一些关于堆栈溢出的问题,这些问题涵盖了相同的错误消息,例如this和this,但是我看不到它们与该问题的关系,我是我有。
答案 0 :(得分:9)
Complement(GreaterThanTwo)
尝试使用a method group,而不是Func<int,bool>
委托。之所以失败,是因为Complement<T>
需要通用委托。
该调用将使用Func<int,bool>
进行编译,例如:
Func<int,bool> cmp= x=>x > 2;
var NotGreaterThanTwo = Complement(cmp);
有一个implicit conversion from method groups to delegates,这也适用:
Func<int,bool> cmp= GreaterThanTwo;
var NotGreaterThanTwo = Complement(cmp);
哪个提出了一个问题,为什么原始代码不起作用? 显式类型转换也可以:
var NotGreaterThanTwo = Complement((Func<int,bool>)GreaterThanTwo);
方法组代表重载方法的组,而不仅仅是单个方法。这意味着编译器必须能够找到在任何情况下要使用的可用组的哪个。
其余就是假设,因为我没有找到有关此特定案例的明确参考或设计说明。
前两个method group conversion rules可能解释了问题所在:
选择单个方法M,该方法对应于形式为E(A)的方法调用(方法调用),并进行以下修改:
- 参数列表A是一个表达式列表,每个表达式都被分类为一个变量,并且在D的formal_parameter_list中具有相应参数的类型和修饰符(ref或out)。
- 考虑的候选方法仅是那些以其正常形式(适用的函数成员)适用的方法,而不是那些仅以其扩展形式适用的方法。
如果方法调用算法产生错误,则发生编译时错误。否则,该算法将产生一个具有与D相同数量的参数的最佳方法M,并认为存在转换。
在Complement<T>(Func<T, bool> f)
中没有调用,因此编译器不知道该组中的哪个方法来选择和转换。它甚至不知道T
是什么,因此它不知道该组中的任何方法是否匹配。
另一方面这可行:
var xx=new []{1,2,3}.Where(GreaterThanTwo);
在这种情况下,Where
的签名是:
public static System.Collections.Generic.IEnumerable<TSource> Where<TSource> (
this System.Collections.Generic.IEnumerable<TSource> source,
Func<TSource,bool> predicate);
,并且IEnumerable<TSource>
中已经可以使用type参数。
答案 1 :(得分:9)
来自What is a method group in C#?
方法组是一组方法(可能只是一个)的名称-即,理论上
ToString
方法可能有多个重载(加上任何扩展方法):ToString()
,ToString(string format)
等-因此ToString
本身就是一个“方法组”。
使用时:
Func<int, bool> NotGreaterThanTwo = Complement(GreaterThanTwo);
GreaterThanTwo
是一个方法组。因此,这可能是正确的:
public static bool GreaterThanTwo (int x) {
return x > 2;
}
// to make it clear this is something completely different
public static bool GreaterThanTwo (Action<bool, string, object> x) {
return false;
}
因此,编译器无法推断您所指的是哪种特定方法,您需要通过解决这种歧义来提供帮助。
您如何决定解决方案取决于您,但是这里至少有3种选择:
指定通用参数:
Complement<int>(GreaterThanTwo);
将方法组转换为所需的委托:
Func<int, bool> greaterThanTwo = GreaterThanTwo;
var notGreaterThanTwo = Complement(greaterThanTwo);
将方法组明确转换为所需的委托:
Complement((Func<int, bool>)GreaterThanTwo);