Emulating delegates with free generic type parameters in C#

前端 未结 3 712
小鲜肉
小鲜肉 2020-12-16 20:31

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.

3条回答
  •  情歌与酒
    2020-12-16 21:34

    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 Create(U arg). 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
        }
    }
    

提交回复
热议问题