我正在尝试编写一个补充函数,以便在提供一个函数时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));
}
Run Code Online (Sandbox Code Playgroud)
在REPL中,出现错误:
main.cs(17,42):错误CS0411:无法从用法中推断方法`MainClass.Complement(System.Func)'的类型参数。尝试明确指定类型参数编译失败:1错误,0警告编译器退出状态1
我看了一些关于堆栈溢出的问题,这些问题涵盖了相同的错误消息,例如this和this,但是我看不到它们与我遇到的这个问题有什么关系。
Complement(GreaterThanTwo)正在尝试使用方法组,而不是Func<int,bool>委托。这失败了,因为Complement<T>需要通用委托。
该调用将使用进行编译Func<int,bool>,例如:
Func<int,bool> cmp= x=>x > 2;
var NotGreaterThanTwo = Complement(cmp);
Run Code Online (Sandbox Code Playgroud)
Func<int,bool> cmp= GreaterThanTwo;
var NotGreaterThanTwo = Complement(cmp);
Run Code Online (Sandbox Code Playgroud)
这就提出了一个问题,为什么原始代码不起作用?一个明确的投也可以工作:
var NotGreaterThanTwo = Complement((Func<int,bool>)GreaterThanTwo);
Run Code Online (Sandbox Code Playgroud)
方法组代表一组重载方法,而不仅仅是单个方法。这意味着,编译器必须能够找到它在任何情况下使用可用组。
其余的都是假设,因为我还没有找到有关此特定案例的明确参考或设计说明。
前两个方法组转换规则可能解释了问题所在:
对应于形式为E(A)的方法调用(方法调用)选择单个方法M,并进行以下修改:
- 参数列表A是一个表达式列表,每个表达式都分类为一个变量,并具有D的formal_parameter_list中相应参数的类型和修饰符(ref或out)。
- 所考虑的候选方法仅是那些以其正常形式(适用的函数成员)适用的方法,而不是仅以其扩展形式适用的那些方法。
如果方法调用算法产生错误,则会发生编译时错误。否则,该算法将产生具有与D相同数量的参数的单个最佳方法M,并认为存在转换。
由于Complement<T>(Func<T, bool> f)没有调用,因此编译器不知道该组中要选择和转换的方法。它甚至不知道是什么T,因此不知道该组中的任何方法是否匹配。
另一方面,这可行:
var xx=new []{1,2,3}.Where(GreaterThanTwo);
Run Code Online (Sandbox Code Playgroud)
在这种情况下,Where的签名是:
public static System.Collections.Generic.IEnumerable<TSource> Where<TSource> (
this System.Collections.Generic.IEnumerable<TSource> source,
Func<TSource,bool> predicate);
Run Code Online (Sandbox Code Playgroud)
并且type参数已经可以从中使用IEnumerable<TSource>。
方法组是一个名称的一套方法(可能是只有一个) -即理论上的
ToString方法可以有多个重载(加任何扩展方法)ToString(),ToString(string format)等-因此ToString本身是一个“方法组”。
使用时:
Func<int, bool> NotGreaterThanTwo = Complement(GreaterThanTwo);
Run Code Online (Sandbox Code Playgroud)
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;
}
Run Code Online (Sandbox Code Playgroud)
因此,编译器无法推断您所指的是哪种特定方法,因此您需要通过解决这种歧义来提供帮助。
您如何决定解决方案取决于您,但是这里至少有3种选择:
指定通用参数:
Complement<int>(GreaterThanTwo);
Run Code Online (Sandbox Code Playgroud)将方法组隐式转换为所需的委托:
Func<int, bool> greaterThanTwo = GreaterThanTwo;
var notGreaterThanTwo = Complement(greaterThanTwo);
Run Code Online (Sandbox Code Playgroud)明确将方法组转换为所需的委托:
Complement((Func<int, bool>)GreaterThanTwo);
Run Code Online (Sandbox Code Playgroud)| 归档时间: |
|
| 查看次数: |
321 次 |
| 最近记录: |