Method overload with Func <T> parameter
I would like to create some overloaded methods that accept a Func parameter. Overloaded methods must invoke the method with the most common types defined in the parameter. The following is a brief example of my methods, and what I would like to call them:
public static TResult PerformCaching<TResult, T1>(Func<T1, TResult> func, T1 first, string cacheKey) { return PerformCaching((t, _, _) => func, first, null, null, cacheKey); } public static TResult PerformCaching<TResult, T1, T2>(Func<T1, T2, TResult> func, T1 first, T2 second, string cacheKey) { return PerformCaching((t, t2, _) => func, first, second, null, cacheKey); } public static TResult PerformCaching<TResult, T1, T2, T3>(Func<T1, T2, T3, TResult> func, T1 first, T2 second, T3 third, string cacheKey) { Model data = Get(cacheKey); if(data == null) { Add(cacheKey); data = func.Invoke(first, second, third); Update(data); } return data; } Is it possible to make it work like this? Another question is what happens to func when it reaches the final method. Will it execute it with one parameter (when the first method is called) or is it called with all three parameters.
No, this approach will not work. You are trying to pass Func<T1, TResult> method that accepts Func<T1, T2, T3, TResult> , and it just doesn't work. I would suggest changing to something like this:
public static TResult PerformCaching<TResult>(Func<TResult> func, string cacheKey) { // Do real stuff in here // You may find ConcurrentDictionary helpful... } public static TResult PerformCaching<T1, TResult> (Func<T1, TResult> func, T1 first, string cacheKey) { return PerformCaching(() => func(first), cacheKey); } public static TResult PerformCaching<T1, T2, TResult> (Func<T1, T2, TResult> func, T1 first, T2 second, string cacheKey) { return PerformCaching(() => func(first, second), cacheKey); } public static TResult PerformCaching<T1, T2, T3, TResult> (Func<T1, T2, T3, TResult> func, T1 first, T2 second, T3 third, string cacheKey) { return PerformCaching(() => func(first, second, third), cacheKey); } You need to project from Func<T, T1, T2> to Func<T, T1, T2, T3> . This is not difficult, but I'm not sure if this is the best approach. You also have other common problems, such as casting in Model (which I converted to a string). A better approach is likely to be similar to Cache.Retrieve<TResult>(string cashKey, Func<TResult> missingItemFactory) . Then you would call Cache.Retrieve("model1", () => repository.Get<Model>(myId)) , and then just call if (data == null) data = missingItemFactory(); inside your method.
Despite this, the solution is lower.
void Main() { Func<string, string> f1 = s => "One"; Func<string, string, string> f2 = (s1, s2) => "Two"; Func<string, string, string, string> f3 = (s1, s2, s3) => "Three"; Console.WriteLine(PerformCaching(f1, "one", "f1")); Console.WriteLine(PerformCaching(f1, "one", "f1")); Console.WriteLine(PerformCaching(f2, "one", "two", "f2")); Console.WriteLine(PerformCaching(f2, "one", "two", "f2")); Console.WriteLine(PerformCaching(f3, "one", "two", "three", "f3")); Console.WriteLine(PerformCaching(f3, "one", "two", "three", "f3")); } // Define other methods and classes here public static TResult PerformCaching<TResult, T1>(Func<T1, TResult> func, T1 first, string cacheKey) { return PerformCaching<TResult, T1, string, string>((t, t2, t3) => func(t), first, null, null, cacheKey); } public static TResult PerformCaching<TResult, T1, T2>(Func<T1, T2, TResult> func, T1 first, T2 second, string cacheKey) { return PerformCaching<TResult, T1, T2, string>((t, t2, t3) => func(t, t2), first, second, null, cacheKey); } public static TResult PerformCaching<TResult, T1, T2, T3>(Func<T1, T2, T3, TResult> func, T1 first, T2 second, T3 third, string cacheKey) { TResult data = Get<TResult>(cacheKey); if(data == null) { Add(cacheKey); data = func.Invoke(first, second, third); Update(data); } return data; } public static T Get<T>(string CashKey) { return default(T); } public static void Add(string CashKey) { } public static void Update<T>(T data) { }