using System; using System.Collections.Generic; using System.Linq; static class PartialApplicationDynamic { // Create a matching delegate type to simplify delegate creation. delegate IEnumerable fsDelegate(Func f, IEnumerable s); static IEnumerable fs(Func f, IEnumerable s) => s.Select(f); static dynamic f1(dynamic x) => x * 2; static dynamic f2(dynamic x) => x * x; static T[] ArrayConcat(T[] arr1, T[] arr2) { var result = new T[arr1.Length + arr2.Length]; Array.Copy(arr1, result, arr1.Length); Array.Copy(arr2, 0, result, 1, arr2.Length); return result; } // Use a specialized params delegate to simplify calling at the risk of inadvertent params expansion. delegate TResult partialDelegate(params TParams[] args); static partialDelegate PartialApplyDynamic(TDelegate f, params dynamic[] args) where TDelegate : Delegate { return rest => (TResult)f.DynamicInvoke(ArrayConcat(args, rest).Cast().ToArray()); } static void Main() { // Cast to object to avoid params expansion of the arrays. object args1 = new object[] { 0, 1, 2, 3 }; object args2 = new object[] { 2, 4, 6, 8 }; var fsf1 = PartialApplyDynamic, IEnumerable>(fs, new Func(f1)); var fsf2 = PartialApplyDynamic, IEnumerable>(fs, new Func(f2)); Console.WriteLine("fsf1, 0-3: " + string.Join(", ", fsf1(args1))); Console.WriteLine("fsf1, evens: " + string.Join(", ", fsf1(args2))); Console.WriteLine("fsf2, 0-3: " + string.Join(", ", fsf2(args1))); Console.WriteLine("fsf2, evens: " + string.Join(", ", fsf2(args2))); } }