This is a tricky question about the design, patterns, and semantics of the language. Please do not vote because you do not see practical value.
First, think about functions and their parameters. Then we look at the analogy between functions with their parameters / arguments and general classes / functions with their type parameters / type arguments.
Functions are blocks of code with some unspecified values ββcalled "parameters". You pass arguments and get the result.
General classes are classes with some undefined "type parameters". You provide type arguments, and then you can work with the class - call the constructor or call static methods.
Common functions in nonequivalent classes are functions with some undefined "type parameters" and some undefined "parameter values". You get type arguments and value arguments to get the result.
Delegates are pointers to specific functions. When you create a delegate, you do not specify function arguments, but supply them later.
The problem is that .Net does not have a delegate equivalent for common functions with undefined typical type parameters. You cannot specify type values ββfor type parameters later. We can imagine delegates who have not only free parameter values, 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 the program I want to write in C #. I want to know how you can achieve similar behavior in the right C # program.
How can we emulate delegates with free type type parameters in C #?
How can we pass a link / link to a common function [s] with still unknown common parameters through non-common 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 references to common functions (Factory.CreateList and Factory.CreateSet) to the constructor of the Worker class without specifying type arguments? Type arguments are passed later when the generic DoWork function is called with specific typed arrays. DoWork uses type arguments to select the correct function, passes argument values ββto it, and returns the resulting value.
Final Solution: Delegate Emulation with Free Typical Type Parameters in C #