简体   繁体   中英

C# Best way to share logic and re-use code

The given function returns a KPI value, first it checks its cache, then it performs its logic, caches the result and returns a value, handling a failure condition.

How am I best to re-use the caching, error handling logic. What I essentially want to create is a function that just performs the necessary logic with boiler plate code abstracted away and re-used across multiple similar functions.

public static int CurrentEmployees()
 {
     if (HttpRuntime.Cache["CurrentEmployees"] == null)
     {
         try
         {
             int CurrentEmployees = Employee.Load().Count(x => x.DateFinished == null && !x.Contractor && x.DateStarted < DateTime.Now);
             HttpRuntime.Cache.Insert("CurrentEmployees", CurrentEmployees, null, DateTime.Now.AddMinutes(20), new TimeSpan(0, 10, 0));

             return CurrentEmployees;
         }
         catch(Exception e)
         {
             //TODO: Report this
             return -1;
         }
     }
     else
         return (int)HttpRuntime.Cache["CurrentEmployees"];
 }

As the boilerplate code is wrapped around the logic it is difficult for me to simply push these into other function calls.

Here's how you could create a generic method to cache whatever you want and reuse this logic.

public static T Cache<T>(string key, Func<T> loadFunction, Func<T> errorHandler)
{
     if (HttpRuntime.Cache[key] == null)
     {
         try
         {
             T value = loadFunction();
         HttpRuntime.Cache.Insert(key, value , null, DateTime.Now.AddMinutes(20), new TimeSpan(0, 10, 0));
             return value;
         }
         catch(Exception e)
         {
             //TODO: Report this
             return errorHandler();
         }
     }
     else
         return (T)HttpRuntime.Cache[key];
}

Usage:

public static int CurrentEmployees()
{
    return Cache<int>("CurrentEmployees", 
        () => Employee.Load().Count(x => x.DateFinished == null && !x.Contractor && x.DateStarted < DateTime.Now),
        () => -1);
}

Agree with answer from @DLeh but I would write it like this:

public static class HelperFunctions
{
    public static Func<T> Cache<T>(this Func<T> inner, string cacheName)
    {
        return () =>
        {
            if (HttpRuntime.Cache[cacheName] == null)
            {
                var result = inner();
                HttpRuntime.Cache.Insert(cacheName, inner(), null, DateTime.Now.AddMinutes(20), new TimeSpan(0, 10, 0));

                return result;
            }

            return (T)HttpRuntime.Cache[cacheName];
        };
    }

    public static Func<T> OnError<T>(this Func<T> inner, Func<Exception, T> onError)
    {
        return () =>
        {
            try
            {
                return inner();
            }
            catch (Exception e)
            {
                return onError(e);
            }
        };
    }
}

Usage:

public static class Employees
{
    public static int CurrentEmployees()
    {
        return (new Func<int>(() => Employee.Load().Count(x => x.DateFinished == null && !x.Contractor && x.DateStarted < DateTime.Now)))
            .Cache("CurrentEmployees")
            .OnError(e => -1) 
            ();//TODO: log?
    }
}

This way we separate caching logic from error handling (following single responsibility principle) and are able to reuse/compose each separately. So when you add another function like this you won't have to change Caching function.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM