补充高阶函数

时间:2019-06-20 07:54:48

标签: c#

我正在尝试编写一个补数函数,以便在提供函数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));
   }

Here is a link to the same.

在代表中,我得到了错误:

  

main.cs(17,42):错误CS0411:方法的类型参数   无法从中推断出MainClass.Complement(System.Func)   用法。尝试显式指定类型参数编译   失败:1个错误,0个警告编译器退出状态1

我已经查看了一些关于堆栈溢出的问题,这些问题涵盖了相同的错误消息,例如thisthis,但是我看不到它们与该问题的关系,我是我有。

2 个答案:

答案 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种选择:

  1. 指定通用参数:

    Complement<int>(GreaterThanTwo);
    
  2. 将方法组转换为所需的委托:

    Func<int, bool> greaterThanTwo = GreaterThanTwo; 
    var notGreaterThanTwo = Complement(greaterThanTwo);
    
  3. 将方法组明确转换为所需的委托:

    Complement((Func<int, bool>)GreaterThanTwo);