泛型/代理和带参数的函数传递

时间:2013-02-18 12:21:33

标签: c# .net function generics delegates

我正在尝试创建一个通用的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;
        }
然而,我有两个问题。

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

  2. 第二个问题是,我需要传递以填充缓存项目的许多功能会有所不同,因为有些功能没有参数,有些会有一个,有些可能会超过一个和这些参数的每个类型将会有所不同。那么我怎样才能使它能够工作而不必定义一个具有所有可能签名的函数,这些签名将涵盖支付我使用的所有可能的函数组合。

4 个答案:

答案 0 :(得分:3)

如果函数的参数将填充在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))

答案 1 :(得分:0)

您可以将List<P>参数作为第一个参数传递,或使用Tuple<P>作为您的参数。

还尝试从函数和参数的哈希码中创建全局缓存键。

如果我理解这一点,您可以在Dapper SqlMapper Identity function

中找到一些代码。

答案 2 :(得分:0)

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

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 :(得分:0)

我认为Reza Arab提出的结构很好,因为它考虑到了你所考虑的结构。但是,在我看来,有一个全局缓存是不可取的,特别是因为它使有效的垃圾收集变得困难(除非你使用对缓存对象的弱引用。但是那些重复创建和删除的对象呢?在这种情况下,弱引用将禁止有效的缓存。)