This is a hard question about language design, patterns and semantics. Please, don't down-vote just because you don't see the practical value.
First, let's think about functions and their parameters. Then we'll look at the analogies between functions with their parameters/arguments and generic classes/functions with their type-parameters/type-arguments.
Functions are blocks of code with some unspecified values called "parameters". You supply the arguments and receive the result.
Generic classes are classes with some unspecified "type-parameters". You supply the type-arguments and then you can work with the class - call the constructor or invoke static methods.
Generic functions in non-generic classes are functions with some unspecified "type-parameters" and some unspecified "value-parameters". You supply the type-arguments and value-arguments to receive result.
Delegates are pointers to specific functions. When you create delegate you don't specify the function arguments, but supply them later.
The problem is that .Net doesn't have equivalent of Delegates for generic functions with unspecified generic type-parameters. You cannot supply type-values for the type-parameters later. We can imagine delegates that have not only free value parameters, but also free type-parameters.
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);
Below is the [pseudo]code for a program that I want to write in C#. I want to know how one can achieve the similar behavior in a correct C# program.
How can we emulate delegates with free generic type-parameters in C#?
How can we pass the reference/link to generic function[s] with yet-unknown generic parameters through the non-generic code?
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
}
}
See how we pass the references to generic functions (Factory.CreateList and Factory.CreateSet) to the Worker class constructor without specifying the type arguments? Type arguments are supplied later when the generic DoWork function is called with concrete-typed arrays. DoWork uses the type-arguments to select the correct function, passes value-arguments to it and returns the received value.
Final solution: Emulating delegates with free generic type parameters in C#
open type
and especiallytype constructor
. – Accumulative