【问题标题】:Generics/Delegates and Passing functions with parameters泛型/委托和带参数的传递函数
【发布时间】:2013-02-18 12:21:32
【问题描述】:

我正在尝试创建一个通用的 CacheManager,我可以在整个应用程序中使用它,这将确保缓存项的所有管理都以一致的方式完成并遵守一些缓存访问模式。这将用于根据需要缓存所有类型的对象。

我知道我可以使用委托将函数传递给方法,您可以在下面看到。

public static T GetGlobalCacheitem( Func<int ,int , T> populateCacheCall )
        {
            string cacheKey = "test";
            var cachedObject = CacheFactory<T>.GlobalCache.GetGlobalCacheItem(cacheKey);

            if (cachedObject == null)
            {
                cachedObject =  populateCacheCall();
                CacheFactory<T>.GlobalCache.AddGlobalCacheItem(cachedObject, cacheKey);
            }
            return cachedObject;
        }

但是我有 2 个问题。

  1. 我想传入以填充缓存的大多数函数本身都具有他们需要的参数。在上面的例子中,这是一个需要两个 int 参数的方法。第一个问题是我怎样才能传入我希望调用函数的参数,因为它们在这个缓存处理程序中是不知道的,在这个缓存处理程序之外是知道的。也这与下一个问题二有关,无论函数需要多少参数(如果有),我如何才能在一种方法中做到这一点?

  2. 第二个问题是我需要传入的很多函数来填充缓存项是多种多样的,有些没有参数,有些只有一个,有些可能超过一个,每个参数的类型都会有所不同。那么,我如何能够使其工作而无需定义具有所有可能签名的函数,该函数将涵盖支付给我使用的所有可能的函数组合。

【问题讨论】:

    标签: c# .net function generics delegates


    【解决方案1】:

    如果函数的参数将填充到 GetGlobalCacheitem 方法之外,您可以使用另一个委托来欺骗调用函数,如下所示:

    public static T GetGlobalCacheitem<T>(Func<T> populateCacheCall)
    

    然后调用它:

    Func<int ,int , object> tempPopulateCacheCall=(a,b)=>new object();
    
    GetGlobalCacheitem(()=>tempPopulateCacheCall(1,2))
    

    或任何其他带有可变参数的函数签名

    Func<int , object> tempPopulateCacheCall=(a)=>new object();
    
    GetGlobalCacheitem(()=>tempPopulateCacheCall(1))
    

    【讨论】:

      【解决方案2】:

      您可以创建一个类,该类将封装函数参数,这样您就可以在没有任何参数的情况下从该类实例调用该函数。这些参数的参数将被放入构造函数中:

      interface ICachedFunction<out T>
      {
          T Invoke();
      }
      
      class CustomFunctionWithVariousParameters<T> : ICachedFunction<T>
      {
          private readonly Func<int, string, T> _function;
          private readonly int _parameter1;
          private readonly string _parameter2;
      
          public CustomFunctionWithVariousParameters(int parameter1, string parameter2, Func<int, string, T> function)
          {
              _function = function;
              _parameter1 = parameter1;
              _parameter2 = parameter2;
          }
      
          public T Invoke()
          {
              return _function(_parameter1, _parameter2);
          }
      }
      

      现在您可以在您的方法中使用此解决方案:

      public static T GetGlobalCacheitem( ICachedFunction<T> populateCacheCall )
      

      希望这种方法会有所帮助。

      【讨论】:

        【解决方案3】:

        您可以传递一个List&lt;P&gt; 参数作为第一个参数,或者使用Tuple&lt;P&gt; 作为您的参数。

        也尝试从函数和参数的哈希码中制作全局缓存键。

        如果我理解正确,您可能会在 Dapper SqlMapper Identity function 中找到一些代码,就像您的场景一样

        【讨论】:

          【解决方案4】:

          我认为 Reza Arab 提出的结构很好,因为它符合您的想法。但是,在我看来,拥有全局缓存是不可取的,特别是因为它使有效的垃圾收集变得困难(除非您对缓存对象使用弱引用。但是重复创建和删除的对象呢?在这种情况下,弱引用将禁止高效缓存)。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2010-09-29
            • 1970-01-01
            • 1970-01-01
            • 2016-10-31
            • 2013-11-17
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多