I've got a couple of utility functions to support memoization for functions with anywhere between 0 to 8 arguments:Public Shared Function Mize(Of TResult)(ByVal input_f As System.Func(Of TResult)) As System.Func(Of TResult)    Dim is_new = True    Dim result As TResult    Return Function()               If is_new Then                   result = input_f()                   is_new = False               End If               Return result           End FunctionEnd FunctionPublic Shared Function Mize(Of TArg1 As Structure, TResult)(ByVal input_f As System.Func(Of TArg1, TResult)) As System.Func(Of TArg1, TResult)    Dim map = New System.Collections.Generic.Dictionary(Of TArg1, TResult)    Return Function(arg1 As TArg1)               Dim result As TResult               If map.TryGetValue(arg1, result) Then Return result               result = input_f(arg1)               map.Add(arg1, result)               Return result           End FunctionEnd FunctionPublic Shared Function Mize(Of TArg1 As Structure, TArg2 As Structure, TResult)(ByVal input_f As System.Func(Of TArg1, TArg2, TResult)) As System.Func(Of TArg1, TArg2, TResult)    Dim map = New System.Collections.Generic.Dictionary(Of System.Tuple(Of TArg1, TArg2), TResult)    Return Function(arg1 As TArg1, arg2 As TArg2)               Dim args = System.Tuple.Create(arg1, arg2)               Dim result As TResult               If map.TryGetValue(args, result) Then Return result               result = input_f(arg1, arg2)               map.Add(args, result)               Return result           End FunctionEnd FunctionPublic Shared Function Mize(Of TArg1 As Structure, TArg2 As Structure, TArg3 As Structure, TResult)(ByVal input_f As System.Func(Of TArg1, TArg2, TArg3, TResult)) As System.Func(Of TArg1, TArg2, TArg3, TResult)    Dim map = New System.Collections.Generic.Dictionary(Of System.Tuple(Of TArg1, TArg2, TArg3), TResult)    Return Function(arg1 As TArg1, arg2 As TArg2, arg3 As TArg3)               Dim args = System.Tuple.Create(arg1, arg2, arg3)               Dim result As TResult               If map.TryGetValue(args, result) Then Return result               result = input_f(arg1, arg2, arg3)               map.Add(args, result)               Return result           End FunctionEnd FunctionPublic Shared Function Mize(Of TArg1 As Structure, TArg2 As Structure, TArg3 As Structure, TArg4 As Structure, TResult)(ByVal input_f As System.Func(Of TArg1, TArg2, TArg3, TArg4, TResult)) As System.Func(Of TArg1, TArg2, TArg3, TArg4, TResult)    Dim map = New System.Collections.Generic.Dictionary(Of System.Tuple(Of TArg1, TArg2, TArg3, TArg4), TResult)    Return Function(arg1 As TArg1, arg2 As TArg2, arg3 As TArg3, arg4 As TArg4)               Dim args = System.Tuple.Create(arg1, arg2, arg3, arg4)               Dim result As TResult               If map.TryGetValue(args, result) Then Return result               result = input_f(arg1, arg2, arg3, arg4)               map.Add(args, result)               Return result           End FunctionEnd FunctionPublic Shared Function Mize(Of TArg1 As Structure, TArg2 As Structure, TArg3 As Structure, TArg4 As Structure, TArg5 As Structure, TResult)(ByVal input_f As System.Func(Of TArg1, TArg2, TArg3, TArg4, TArg5, TResult)) As System.Func(Of TArg1, TArg2, TArg3, TArg4, TArg5, TResult)    Dim map = New System.Collections.Generic.Dictionary(Of System.Tuple(Of TArg1, TArg2, TArg3, TArg4, TArg5), TResult)    Return Function(arg1 As TArg1, arg2 As TArg2, arg3 As TArg3, arg4 As TArg4, arg5 As TArg5)               Dim args = System.Tuple.Create(arg1, arg2, arg3, arg4, arg5)               Dim result As TResult               If map.TryGetValue(args, result) Then Return result               result = input_f(arg1, arg2, arg3, arg4, arg5)               map.Add(args, result)               Return result           End FunctionEnd FunctionPublic Shared Function Mize(Of TArg1 As Structure, TArg2 As Structure, TArg3 As Structure, TArg4 As Structure, TArg5 As Structure, TArg6 As Structure, TResult)(ByVal input_f As System.Func(Of TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TResult)) As System.Func(Of TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TResult)    Dim map = New System.Collections.Generic.Dictionary(Of System.Tuple(Of TArg1, TArg2, TArg3, TArg4, TArg5, TArg6), TResult)    Return Function(arg1 As TArg1, arg2 As TArg2, arg3 As TArg3, arg4 As TArg4, arg5 As TArg5, arg6 As TArg6)               Dim args = System.Tuple.Create(arg1, arg2, arg3, arg4, arg5, arg6)               Dim result As TResult               If map.TryGetValue(args, result) Then Return result               result = input_f(arg1, arg2, arg3, arg4, arg5, arg6)               map.Add(args, result)               Return result           End FunctionEnd FunctionPublic Shared Function Mize(Of TArg1 As Structure, TArg2 As Structure, TArg3 As Structure, TArg4 As Structure, TArg5 As Structure, TArg6 As Structure, targ7 As Structure, TResult)(ByVal input_f As System.Func(Of TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, targ7, TResult)) As System.Func(Of TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, targ7, TResult)    Dim map = New System.Collections.Generic.Dictionary(Of System.Tuple(Of TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, targ7), TResult)    Return Function(arg1 As TArg1, arg2 As TArg2, arg3 As TArg3, arg4 As TArg4, arg5 As TArg5, arg6 As TArg6, arg7 As targ7)               Dim args = System.Tuple.Create(arg1, arg2, arg3, arg4, arg5, arg6, arg7)               Dim result As TResult               If map.TryGetValue(args, result) Then Return result               result = input_f(arg1, arg2, arg3, arg4, arg5, arg6, arg7)               map.Add(args, result)               Return result           End FunctionEnd FunctionPublic Shared Function Mize(Of TArg1 As Structure, TArg2 As Structure, TArg3 As Structure, TArg4 As Structure, TArg5 As Structure, TArg6 As Structure, targ7 As Structure, targ8 As Structure, TResult)(ByVal input_f As System.Func(Of TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, targ7, targ8, TResult)) As System.Func(Of TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, targ7, targ8, TResult)    Dim map = New System.Collections.Generic.Dictionary(Of System.Tuple(Of TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, targ7, targ8), TResult)    Return Function(arg1 As TArg1, arg2 As TArg2, arg3 As TArg3, arg4 As TArg4, arg5 As TArg5, arg6 As TArg6, arg7 As targ7, arg8 As targ8)               Dim args = New System.Tuple(Of TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, targ7, targ8)(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)               Dim result As TResult               If map.TryGetValue(args, result) Then Return result               result = input_f(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)               map.Add(args, result)               Return result           End FunctionEnd FunctionThe problem is that the memoization algorithm is repeated 6 times (the functions that accept functions with 2 arguments to 8 arguments basically have the same algorithm).I'm clearly violating DRY here, and I want to modify the code above to not violate DRY.I've tried shifting those repeating algorithm into a separate function, but since VB.NET/C# does not allow System.Delegate as a generic constraint, I'm out of ideas as to how I would do it.What should I do and how can I improve my code above?
Utility functions for supporting memoization for functions
design patterns;.net;vb.net;memoization
Unless you want to go with another approach, like code injection (see Anton's comment), you're pretty much stuck with this. I agree it is ugly and repetitive. Basically you've run up against the edges of the type system. Type parameters are a little like method parameters, and type arguments are a little like passing arguments to a method, but methods are much more flexible. Methods permit all sorts of higher-order programming, methods can be variadic, and so on. There are no variadic generic types in the .NET type system, which is really what you want to make this sort of thing work smoothly. As for violating the DRY principle, don't worry about it. The reason to not repeat yourself is because if you have the same piece of complex business logic in two different places, and one of them needs fixing, they can get out of sync easily when you forget to fix the other. (The C# compiler codebase is littered with comments that say If you change the reference type convertibility algorithm here, don't forget to also change it here, here and here...) What you're building here is a mechanism: the boring plumbing code that makes the real logic of the program more efficient. DRY is more applicable to business logic than to boring mechanisms.