从Expression <Func <T >>缓存编译

ili*_*ian 8 c# caching expression

我有一个用于检查方法参数的类,您可以在表单中调用它:

public void SomeMethod(string anArg)
{
    Ensure.ArgumentNotNull(() => anArg);
}
Run Code Online (Sandbox Code Playgroud)

如果参数为null,则ArgumentNullException抛出具有该属性名称的参数.这样做是这样的:

public static void ArgumentNotNull<T>(Expression<Func<T>> expression) where T : class 
{
    var value = expression.Compile()();
    if (value == null)
    {
        throw new ArgumentNullException(expression.GetMemberName());
    }
}
Run Code Online (Sandbox Code Playgroud)

GetMemberName我写的扩展方法在哪里.

我遇到的问题是对Compile的调用非常慢,所以我想缓存结果,但我似乎无法想出一个足够独特的缓存密钥以防止缓存冲突,但不是那么独特,缓存变得无效.

到目前为止,我的最大努力是:

internal static class ExpressionCache<T>
{
    private static readonly Dictionary<string, Func<T>> Cache = new Dictionary<string, Func<T>>();

    public static Func<T> CachedCompile(Expression<Func<T>> targetSelector)
    {
        Func<T> cachedFunc;
        var cacheKey = targetSelector + targetSelector.Body.ToString();

        if (!Cache.TryGetValue(cacheKey, out cachedFunc))
        {
            cachedFunc = targetSelector.Compile();
            Cache[cacheKey] = cachedFunc;
        }

        return cachedFunc;
    }
}
Run Code Online (Sandbox Code Playgroud)

但这仍然会导致缓存密钥冲突.什么是更好的方法?

gjv*_*amp 4

这些表达从何而来,它们是新创造的吗?如果重复使用它们,您可以使用表达式本身作为键:

internal static class ExpressionCache<T>
{
    private static readonly Dictionary<Expression<Func<T>, Func<T>> Cache = new Dictionary<Expression<Func<T>, Func<T>>();

    public static Func<T> CachedCompile(Expression<Func<T>> targetSelector)
    {
        Func<T> cachedFunc;
        if (!Cache.TryGetValue(targetSelector, out cachedFunc))
        {
            cachedFunc = targetSelector.Compile();
            Cache[targetSelector] = cachedFunc;
        }

        return cachedFunc;
    }
}
Run Code Online (Sandbox Code Playgroud)

否则你可以窥探 DLR http://dlr.codeplex.com/的源代码,我相信他们很好地解决了这类问题。