【问题标题】:C# Best way to share logic and re-use codeC# 共享逻辑和重用代码的最佳方式
【发布时间】:2015-07-10 13:10:17
【问题描述】:

给定函数返回一个 KPI 值,首先检查其缓存,然后执行其逻辑,缓存结果并返回一个值,处理失败条件。

如何最好地重用缓存、错误处理逻辑。我本质上想要创建的是一个函数,它只执行必要的逻辑,并将样板代码抽象出来并在多个类似函数中重复使用。

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"];
 }

由于样板代码被包裹在逻辑中,我很难将它们简单地推送到其他函数调用中。

【问题讨论】:

  • 公共部分可以进入单独的方法(有时是通用的),单独的部分可以作为参数传递给或委托,也可以在执行后(在方法调用之后)。另一个函数看起来如何?可以使用 lamda 委托和添加分配的新值(以防它丢失),而 name 作为参数传递。
  • 在我看来你应该使用polymorphism。不过,这是一个广泛的话题.. 并且取决于您的设置。您能解释一下您尝试过的方法以及为什么没有奏效吗?

标签: c# code-reuse


【解决方案1】:

以下是您如何创建一个通用方法来缓存您想要的任何内容并重用此逻辑。

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];
}

用法:

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

【讨论】:

  • 您可以为异常处理添加相同类型的通用帮助器,接受调用异常的函数作为第一个参数,将实际函数作为第二个参数。然后使用它来包装传递给缓存包装器的函数。这样缓存就不会有错误处理逻辑。
  • 不确定您的意思。随时发布您自己的答案以说明您的意思。
  • 嗯,我同意你的回答,只是你的例子中的缓存有两个职责——缓存和错误处理,你可以重写它以遵循“单一职责”。像这样的东西:return Cache&lt;int&gt;("CurrentEmployees", () =&gt; Error&lt;int&gt;(()=&gt; -1, () =&gt; Employee.Load())); }
  • 恕我直言,小心这类解决方案(即,将函数作为参数传递)——它们往往会增长并且更难维护,例如抽象基类和派生方法。
  • 我不太同意这一点。在这种情况下,至少,它是一个static 方法,所以它不会受到继承的影响
【解决方案2】:

同意answer from @DLeh 但我会这样写:

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);
            }
        };
    }
}

用法:

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?
    }
}

通过这种方式,我们将缓存逻辑与错误处理分开(遵循单一职责原则),并且能够分别重用/组合每个。因此,当您添加另一个这样的函数时,您不必更改缓存函数。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-13
    • 1970-01-01
    相关资源
    最近更新 更多