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.
The solution is interfaces. As @mike-z wrote, interfaces support generic methods. So, we can create the non-generic interface IFactory with generic method which incapsulates a reference to a generic method in some class. To bind the generic method of a [Factory] class using such interface we usually need to create small classes implementing the IFactory interface. They act just like closures used by lambdas.
I don't see big semantic difference between this and the generic method delegates that I've asked for. The solution is very much like what compiler does for lambdas [that just call other methods] (create closure with the method that calls the).
What are we losing? Mostly syntactic sugar.
Anonymous functions/lambdas. We cannot create generic lambdas. Being able to create anonymous classes (like in Java) would have solved the problem. But this isn't much of a problem to begin with as lambdas are just syntactic sugar in .Net.
Ability to implicitly create delegate/link from the method group (C# term). We cannot use the method group in any way if it's generic. This doesn't affect the semantics too.
Ability to define generic delegates is impeded. We cannot make a
generic IFactory interface with method V. This is not a problem too.
This is the code of the solution. The Factory class from the question is unchanged.
public interface IFactory {
ICollection Create(IEnumerable values);
}
public class Worker { //not generic
IFactory _factory;
public Worker(IFactory factory) {
_factory = factory;
}
public ICollection DoWork(IEnumerable values) { //generic method
return _factory.Create(values);
}
}
public static class Program {
class ListFactory : IFactory {
public ICollection Create(IEnumerable values) {
return Factory.CreateList(values);
}
}
class SetFactory : IFactory {
public ICollection Create(IEnumerable values) {
return Factory.CreateSet(values);
}
}
public static void Main() {
string[] values1 = new string[] { "a", "b", "c" };
int[] values2 = new int[] { 1, 2, 2, 2 };
Worker listWorker = new Worker(new ListFactory());
Worker setWorker = new Worker(new SetFactory());
ICollection result1 = listWorker.DoWork(values1);
ICollection result2 = listWorker.DoWork(values2); //.Count == 4
ICollection result3 = setWorker.DoWork(values2); //.Count == 2
}
}