静态方法签名类型参数和部分应用程序

Aag*_*age 9 c# functional-programming func partial-application

我最近一直在研究功能编程,并希望将一些概念带到我的C#世界.我正在尝试编写函数来创建服务(或任何你称之为的服务),而不是创建具有可注入依赖项的类.

我想方设法通过创建一个像这样的静态方法,用两个参数和一个返回参数来部分应用一个函数(与注入依赖项具有相同的效果):

// this makes a func with a single arg from a func with two
static Func<T2, TResult> PartiallyApply<T1, T2, TResult>(
        Func<T1,T2, TResult> f, 
        T1 t1)
    {
        // use given t1 argument to create a new function
        Func<T2, TResult> map = t2 => f(t1, t2);
        return map;
    }
Run Code Online (Sandbox Code Playgroud)

这工作,但我想传递一个静态方法,如下所示:

static string MakeName(string a, string b) => a + " " + b;
Run Code Online (Sandbox Code Playgroud)

当我尝试连接它时,我得到错误The type arguments for method 'Program.PartiallyApply<T1, T2, TResult>(Func<T1, T2, TResult>, T1)' cannot be inferred from the usage.但是当我添加一个创建显式的步骤时Func<string,string,string,我指向它确实有效的方法:

static void Main(string[] args)
{
    var first = "John";
    var last  = "Doe";
    var f1    = PartiallyApply(MakeName, first);   // cannot be inferred from the usage

    Func<string, string, string> make = MakeName;  // map it to func            
    var f2 = PartiallyApply(make, first);          // works
    var name = f2(last);

    Console.WriteLine(name);
    Console.ReadKey();
}
Run Code Online (Sandbox Code Playgroud)

为什么编译器在直接传递静态方法时不能计算出类型args?有没有办法可以使用静态方法而无需将它们显式映射到Func<>具有基本相同(类型)参数的方法?

UPDATEFunctional programming in C#通过Enrico Buonanno(强烈推荐)给出了解决这个让另一个不错的选择.在7.1.3他给出了如何一起工作的几个选项Funcs,直接,而不是方法组.你可以用这样的一个getter only属性Func:

static Func<string, string, string> MakeName => (a,b) => a + " " + b;
Run Code Online (Sandbox Code Playgroud)

Ali*_*efi 4

因为如果您有两个具有不同参数的方法,编译器不知道使用 method1 或 method2。

例子:

static string MakeName(string a, string b) => a + " " + b;
static string MakeName(int a, string b) => a + " " + b;
Run Code Online (Sandbox Code Playgroud)

编译器怎么知道你指的是哪一个呢?方法1还是方法2?仅仅因为方法组中现在只有一种方法,并不意味着它会一直如此。添加一个方法就会以这种方式中断。

var f1 = PartiallyApply(MakeName, first);
Run Code Online (Sandbox Code Playgroud)

因此,如果你想解决这个问题,你必须在方法调用中设置通用参数:

var f1 = PartiallyApply<string, string, string>(MakeName, first);
var f2 = PartiallyApply<string, int, string>(MakeName, first);
Run Code Online (Sandbox Code Playgroud)

或者您可以在 PartiallyApply 方法中获取所有参数:

static string MakeName(string a, string b) => a + " " + b;
    static string MakeName(int a, string b) => a + " " + b;
    // this makes a func with a single arg from a func with two
    static Func<T2, TResult> PartiallyApply<T1, T2, TResult>(
            Func<T1, T2, TResult> f,
            T1 t1,
            T2 t2)

    {
        // use given t1 argument to create a new function
        Func<T2, TResult> map = result => f(t1, t2);
        return map;
    }



    static void Main(string[] args)
    {
        var first = "John";
        var last = "Doe";
        var f1 = PartiallyApply(MakeName, first, last);   //works now
        var name = f1(last);
        Console.WriteLine(name);

        Func<string, string, string> make = MakeName;  // map it to func            
        var f2 = PartiallyApply(make, first, last);          // works
        name = f2(last);

        Console.WriteLine(name);
        Console.ReadKey();
    }
Run Code Online (Sandbox Code Playgroud)