【发布时间】:2012-10-04 10:30:14
【问题描述】:
这是一个关于语言设计、模式和语义的难题。请不要因为看不到实用价值就投反对票。
首先,让我们考虑一下函数及其参数。然后我们将看看函数及其参数/参数与泛型类/函数及其类型参数/类型参数之间的类比。
函数是具有一些未指定值的代码块,称为“参数”。 您提供参数并接收结果。
通用类是具有一些未指定的“类型参数”的类。 您提供类型参数,然后您就可以使用该类 - 调用构造函数或调用静态方法。
非泛型类中的泛型函数是具有一些未指定的“type-parameters”和一些未指定的“value-parameters”的函数。 您提供 type-arguments 和 value-arguments 来接收结果。
委托是指向特定函数的指针。创建委托时,您不指定函数参数,而是稍后提供它们。
问题在于 .Net 对于具有未指定泛型类型参数的泛型函数没有等效的委托。以后不能为 type-parameters 提供 type-values。 我们可以想象委托不仅有免费的值参数,还有免费的类型参数。
static class SomeClass {
//generic function
public static T GetValue<T>() {
return default(T);
}
}
//creating delegate to generic function or method group
Func{TFree}<TFree> valueFactory = SomeClass.GetValue;
//creating delegate to anonymous generic function
Func{TFree}<int, List<TFree>> listFactory = {TFree}(int capacity) => new List<TFree>(capacity);
下面是我想用 C# 编写的程序的 [伪] 代码。我想知道如何在正确的 C# 程序中实现类似的行为。
我们如何在 C# 中使用免费的泛型类型参数来模拟委托?
我们如何通过非泛型代码将引用/链接传递给具有未知泛型参数的泛型函数?
public static class Factory { //Everything compiles fine here
public delegate ICollection<T> FactoryDelegate<T>(IEnumerable<T> values);
public static ICollection<T> CreateList<T>(IEnumerable<T> values) {
return new List<T>(values);
}
public static ICollection<T> CreateSet<T>(IEnumerable<T> values) {
return new HashSet<T>(values);
}
}
public class Worker { //non-generic class
Func{TFree}<FactoryDelegate<TFree>> _factory; //TFree is a "free" generic type paramenter
public Worker(Func{TFree}<FactoryDelegate<TFree>> factory) {
_factory = factory;
}
public ICollection<T> DoWork<T>(IEnumerable<T> values) { //generic method
return _factory{T}(values); //supplying T as the argument for type parameter TFree
}
}
public static class Program {
public static void Main() {
string[] values1 = new string[] { "a", "b", "c" };
int[] values2 = new int[] { 1, 2, 2, 2 };
Worker listWorker = new Worker(Factory.CreateList); //passing reference to generic function
Worker setWorker = new Worker(Factory.CreateSet); //passing reference to generic function
ICollection<string> result1 = listWorker.DoWork(values1);
ICollection<int> result2 = listWorker.DoWork(values2); //.Count == 4
ICollection<int> result3 = setWorker.DoWork(values2); //.Count == 2
}
}
看看我们如何在不指定类型参数的情况下将通用函数(Factory.CreateList 和 Factory.CreateSet)的引用传递给 Worker 类构造函数? 类型参数 稍后在使用具体类型数组调用通用 DoWork 函数时提供。 DoWork 使用 type-arguments 选择正确的函数,将 value-arguments 传递给它并返回接收到的值。
最终解决方案: Emulating delegates with free generic type parameters in C#
【问题讨论】:
-
查看条款
open type,尤其是type constructor。 -
我认为 C# 在不使用反射或使 Worker 通用的情况下没有任何方法可以做到这一点。我怀疑 .Net 不支持的高级类型会有所帮助。
-
我不确定,但您是否看过 F#?强制 C# 变得更实用可能会很痛苦。
标签: c# generics delegates function-pointers strong-typing