C#泛型(一个严肃的问题)

C#泛型(一个严肃的问题),c#,generics,metaprogramming,C#,Generics,Metaprogramming,在C#中,我试图编写代码,创建一个本身是泛型的Func委托。例如,以下(非泛型)委托正在返回任意字符串: Func<string> getString = () => "Hello!"; Func getString=()=>“你好!”; 另一方面,我想创建一个与泛型方法类似的泛型方法。例如,如果我希望泛型Func为类型T返回默认值(T),我可以想象我编写的代码如下: Func<T><T> getDefaultObject = <T>()

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

Func<string> getString = () => "Hello!";
Func getString=()=>“你好!”;
另一方面,我想创建一个与泛型方法类似的泛型方法。例如,如果我希望泛型Func为类型T返回默认值(T),我可以想象我编写的代码如下:

Func<T><T> getDefaultObject = <T>() => default(T);
Func getDefaultObject=()=>default(T);
那我就把它当作

getDefaultObject()
将返回null,如果我编写
getDefaultObject()
将返回0


这个问题不仅仅是一个学术练习。我已经找到了很多地方可以使用这个,但我不能得到正确的语法。这可能吗?有提供这种功能的库吗?

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

objecto=Activator.CreateInstance(typeof(StringBuilder))

这正是你想要的。您可以按以下方式编写:

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


Blindy的解决方案更好。

您不能仅基于返回值重载任何内容,因此这包括变量

但是,您可以去掉lambda表达式并编写一个实函数:

T getDefaultObject<T>() { return default(T); }
T getDefaultObject(){返回默认值(T);}
然后你就可以像你想的那样叫它:

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

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

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

尽管您可能会找到类似斯蒂芬·克利里(Stephen Cleary)的实际解决方法

Func<T> CreateGetDefaultObject<T>() { return () => default(T); }
但问题是:我们如何键入函数
Test
及其参数
f
? 显然,
f
将每种类型的
T
映射到这种类型的数组中

Tuple<int[], string[]> Test<T>(Func<T, T[]> f) {
    return (f(1), f("Hello"));
} 
在你的情况下,你可以打字

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

有关所有
符号,请参阅上的Haskell Wiki条目。

是否有原因导致
Func CreateGetDefaultObject(){return()=>default(T);}
不起作用?我现在明白了。您希望将编译时类型参数传递给委托。感谢您的回答,但问题更多的是关于动态设置泛型委托(如果可能的话)。关于您的代码的问题是,您正在创建一个方法,而不是一个可以在方法中声明、实例化和使用的委托。是的,但没有回答这个问题。谢谢Dario,这是一个非常有趣的答案。尽管我不是Haskell大师,但我理解您的答案和您给出的链接。就我所知而且,没有解决方案/解决办法,因为这是该语言的一个限制,因为它不支持秩N类型。也许再过5-10年,微软将在CLR中添加“秩N类型”。@tahirhassan:是的,这是该语言类型系统的一个非常基本的属性(这是一个非常高级的接口,即使Haskell也只通过非标准扩展来支持它),这是无法超越的。我认为有一种可能性,您可以通过实现类似
interface-ToRankNArray{t[]Apply(t arg);}的接口来模拟这种行为
。Java或F#等语言允许创建匿名子类型,但它当然既不像匿名函数那样方便,也不会改变类型系统本身。
Tuple<int[], string[]> Test<T>(Func<T, T[]> f) {
    return (f(1), f("Hello"));
} 
Tuple<int[], string[]> Test(forall T : Func<T, T[]> f) {
    return (f(1), f("Hello"));
} 
forall T : Func<T> getDefaultValue = ...
test :: (forall t . t -> [t]) -> ([Int], [String])
test f = (f 1, f "hello")