C#Generic Generics(一个严肃的问题)

Tah*_*san 11 c# generics metaprogramming

在C#中,我试图编写代码,我将创建一个Func委托,它本身就是通用的.例如,以下(非通用)委托返回任意字符串:

Func<string> getString = () => "Hello!";
Run Code Online (Sandbox Code Playgroud)

另一方面,我希望创建一个类似于泛型方法的泛型.例如,如果我想要一个通用的Func为类型T返回默认值(T).我想我会按如下方式编写代码:

Func<T><T> getDefaultObject = <T>() => default(T);
Run Code Online (Sandbox Code Playgroud)

然后我会用它作为

getDefaultObject<string>()这将返回null,如果我写,getDefaultObject<int>()将返回0.

这个问题不仅仅是一个学术上的运动.我找到了许多我可以使用它的地方,但我无法正确使用语法.这可能吗?有没有提供这种功能的库?

Bli*_*ndy 8

那么你不能只根据返回值重载任何东西,所以这包括变量.

然而,你可以摆脱lambda表达式并编写一个真正的函数:

T getDefaultObject<T>() { return default(T); }
Run Code Online (Sandbox Code Playgroud)

然后你完全按照自己的意愿调用它:

int i=getDefaultObject<int>();       // i=0
string s=getDefaultObject<string>(); // s=null
Run Code Online (Sandbox Code Playgroud)


Dar*_*rio 4

尽管人们可能会找到像斯蒂芬·克利里(Stephen Cleary)这样的实用解决方法

Func<T> CreateGetDefaultObject<T>() { return () => default(T); }
Run Code Online (Sandbox Code Playgroud)

您可以直接指定泛型,从理论上讲,这是一个非常有趣的问题,C# 当前的类型系统无法解决。


正如您所说,本身是通用的类型被称为更高级别的类型

考虑以下示例(伪 C#):

Tuple<int[], string[]> Test(Func<?> f) {
    return (f(1), f("Hello"));
} 
Run Code Online (Sandbox Code Playgroud)

在您提议的系统中,调用可能如下所示:

Test(x => new[] { x }); // Returns ({ 1 }, { "Hello" })
Run Code Online (Sandbox Code Playgroud)

但问题是:我们如何输入函数Test及其参数f?显然,f将每种类型映射T到该类型的数组T[]。那么也许?

Tuple<int[], string[]> Test<T>(Func<T, T[]> f) {
    return (f(1), f("Hello"));
} 
Run Code Online (Sandbox Code Playgroud)

但这是行不通的。我们不能Test任何特定的 T参数进行参数化,因为f应该可以应用于所有类型T。在这一点上,C#的类型系统已经无法更进一步了。

我们需要的是像这样的符号

Tuple<int[], string[]> Test(forall T : Func<T, T[]> f) {
    return (f(1), f("Hello"));
} 
Run Code Online (Sandbox Code Playgroud)

在你的情况下,你可以输入

forall T : Func<T> getDefaultValue = ...
Run Code Online (Sandbox Code Playgroud)

我所知道的唯一支持这种泛型的语言是 Haskell:

test :: (forall t . t -> [t]) -> ([Int], [String])
test f = (f 1, f "hello")
Run Code Online (Sandbox Code Playgroud)

有关此表示法,请参阅有关多态性的Haskellwiki 条目forall