繁体   English   中英

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

[英]C# Generic Generics (A Serious Question)

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

Func<string> getString = () => "Hello!";

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

Func<T><T> getDefaultObject = <T>() => default(T);

然后我会用它作为

getDefaultObject<string>()将返回null,如果我要编写getDefaultObject<int>()将返回0。

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

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

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

T getDefaultObject<T>() { return default(T); }

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

int i=getDefaultObject<int>();       // i=0
string s=getDefaultObject<string>(); // s=null

虽然有人可能会找到像Stephen Cleary这样的实用解决方案

Func<T> CreateGetDefaultObject<T>() { return () => default(T); }

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


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

请考虑以下示例(pseudo-C#):

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

在您建议的系统中,呼叫可能如下所示:

Test(x => new[] { x }); // Returns ({ 1 }, { "Hello" })

但问题是:我们如何键入函数Test和它的参数f 显然, f将每个类型T映射到这种类型的数组T[] 也许呢?

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

但这不起作用 我们不能用任何特定的 T参数化Test ,因为f应该可以应用于所有类型T 此时,C#的类型系统无法进一步发展。

我们需要的是一个符号

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

在您的情况下,您可以键入

forall T : Func<T> getDefaultValue = ...

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

test :: (forall t . t -> [t]) -> ([Int], [String])
test f = (f 1, f "hello")

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

这是不可能的,因为C#中的委托实例不能具有泛型参数。 最接近的是将类型对象作为常规参数传递并使用反射。 :(

在许多情况下,转换为动态有助于消除反射的痛苦,但动态在创建新实例时没有帮助,例如您的示例。

您不能这样做,因为必须在运行时知道泛型类型参数。 你必须使用激活类:

Object o = Activator.CreateInstance(typeof(StringBuilder));

这将完全符合你的要求。 您可以按以下方式编写它:

public T Default<T>()
{
  return (T)Activator.CreateInstance(typeof(T));
}

编辑

Blindy的解决方案更好。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM