静态方法签名类型参数和部分应用
Static method signature type arguments and partial application
我最近一直在研究函数式编程,并希望将一些概念带入我的 C#
世界。我正在尝试组合函数来创建服务(或任何你称之为它们的东西),而不是创建具有可注入依赖项的 类。
我想出了一种方法,通过创建一个像这样的静态方法,使用两个参数和一个 return 参数来部分应用函数(与注入依赖项具有相同的效果):
// 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;
}
这有效,但是我想向它传递一个静态方法,例如:
static string MakeName(string a, string b) => a + " " + b;
当我尝试连接它时,出现错误 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();
}
为什么直接传递静态方法时编译器无法计算出类型参数?有没有一种方法可以使用静态方法,而无需将它们显式映射到具有基本相同(类型)参数的 Func<>
?
更新
阅读 Enrico Buonanno
的 Functional programming in C#
(强烈推荐)提供了另一个解决此问题的好选择。在 7.1.3
中,他给出了几个关于如何直接使用 Funcs
而不是方法组的选项。
您可以像这样用 Func
制作 getter 只有 属性:
static Func<string, string, string> MakeName => (a,b) => a + " " + b;
因为如果你有两个参数不同的方法,编译器不知道使用 method1 还是 method2。
示例:
static string MakeName(string a, string b) => a + " " + b;
static string MakeName(int a, string b) => a + " " + b;
编译器怎么知道你指的是哪一个?方法一还是方法二?仅仅因为你现在在方法组中只有一个方法,并不意味着它永远都是那样。添加方法将以这种方式中断。
var f1 = PartiallyApply(MakeName, first);
所以如果你想解决这个问题,你必须在方法调用中设置你的通用参数:
var f1 = PartiallyApply<string, string, string>(MakeName, first);
var f2 = PartiallyApply<string, int, string>(MakeName, first);
或者您可以在 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();
}
我最近一直在研究函数式编程,并希望将一些概念带入我的 C#
世界。我正在尝试组合函数来创建服务(或任何你称之为它们的东西),而不是创建具有可注入依赖项的 类。
我想出了一种方法,通过创建一个像这样的静态方法,使用两个参数和一个 return 参数来部分应用函数(与注入依赖项具有相同的效果):
// 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;
}
这有效,但是我想向它传递一个静态方法,例如:
static string MakeName(string a, string b) => a + " " + b;
当我尝试连接它时,出现错误 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();
}
为什么直接传递静态方法时编译器无法计算出类型参数?有没有一种方法可以使用静态方法,而无需将它们显式映射到具有基本相同(类型)参数的 Func<>
?
更新
阅读 Enrico Buonanno
的 Functional programming in C#
(强烈推荐)提供了另一个解决此问题的好选择。在 7.1.3
中,他给出了几个关于如何直接使用 Funcs
而不是方法组的选项。
您可以像这样用 Func
制作 getter 只有 属性:
static Func<string, string, string> MakeName => (a,b) => a + " " + b;
因为如果你有两个参数不同的方法,编译器不知道使用 method1 还是 method2。
示例:
static string MakeName(string a, string b) => a + " " + b;
static string MakeName(int a, string b) => a + " " + b;
编译器怎么知道你指的是哪一个?方法一还是方法二?仅仅因为你现在在方法组中只有一个方法,并不意味着它永远都是那样。添加方法将以这种方式中断。
var f1 = PartiallyApply(MakeName, first);
所以如果你想解决这个问题,你必须在方法调用中设置你的通用参数:
var f1 = PartiallyApply<string, string, string>(MakeName, first);
var f2 = PartiallyApply<string, int, string>(MakeName, first);
或者您可以在 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();
}