在C#中,我正在尝试编写代码,我将创建一个本身就是通用的Func委托。例如,以下(非通用)委托返回任意字符串:
Func<string> getString = () => "Hello!";
另一方面,我希望创建一个类似于泛型方法的泛型。例如,如果我想要一个通用的Func为类型T返回默认值(T)。我想我会按如下方式编写代码:
Func<T><T> getDefaultObject = <T>() => default(T);
然后我会用它作为
getDefaultObject<string>()
将返回null,如果我要写getDefaultObject<int>()
,则返回0.
这个问题不仅仅是一个学术上的运动。我找到了许多我可以使用它的地方,但我无法正确使用语法。这可能吗?有没有提供这种功能的库?
答案 0 :(得分:8)
嗯,你不能只根据返回值重载任何东西,所以这包括变量。
然而,您可以摆脱lambda表达式并编写一个真正的函数:
T getDefaultObject<T>() { return default(T); }
然后你完全按照自己的意愿调用它:
int i=getDefaultObject<int>(); // i=0
string s=getDefaultObject<string>(); // s=null
答案 1 :(得分:4)
虽然有人可能会找到像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"));
}
但这不起作用。我们无法使用任何特定 Test
参数化T
,因为f
应该可以应用于所有类型{{1} }。此时,C#的类型系统无法进一步发展。
我们需要的是像
这样的符号T
在您的情况下,您可以输入
Tuple<int[], string[]> Test(forall T : Func<T, T[]> f) {
return (f(1), f("Hello"));
}
我所知道的唯一支持这种泛型的语言是Haskell:
forall T : Func<T> getDefaultValue = ...
请参阅polymorphism上有关此test :: (forall t . t -> [t]) -> ([Int], [String])
test f = (f 1, f "hello")
表示法的Haskellwiki条目。
答案 2 :(得分:0)
这是不可能的,因为C#中的委托实例不能包含泛型参数。最接近的是将类型对象作为常规参数传递并使用反射。 :(
在许多情况下,投射到动态有助于消除反射的痛苦,但动态在创建新实例时无效,例如您的示例。
答案 3 :(得分:-1)
您无法执行此操作,因为必须在运行时知道泛型类型参数。你必须使用激活类:
Object o = Activator.CreateInstance(typeof(StringBuilder));
这将完全符合您的要求。您可以按以下方式编写它:
public T Default<T>()
{
return (T)Activator.CreateInstance(typeof(T));
}
修改强>
Blindy的解决方案更好。