Cache compiles from the expression <Func <T>>
I have a class that I use for validation method arguments that you invoke on the form:
public void SomeMethod(string anArg) { Ensure.ArgumentNotNull(() => anArg); } If the argument is zero, then an ArgumentNullException generated with the property name. This is done as follows:
public static void ArgumentNotNull<T>(Expression<Func<T>> expression) where T : class { var value = expression.Compile()(); if (value == null) { throw new ArgumentNullException(expression.GetMemberName()); } } Where GetMemberName is the extension method I wrote.
The problem I ran into is that the Compile call is very slow, so I would like to cache the result, but I can't seem to come up with a cache key that will be unique enough to prevent cache conflicts, but not so unique that cache becomes invalid.
My best effort so far:
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; } } But this still causes cache conflicts. What could be a better approach?
Where does ekzraziya come from, are they created new? If they are reused, you can simply use the expression as a key .:
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; } } Otherwise, you can snoop around the source code for the DLR http://dlr.codeplex.com/ , I believe that they deal fairly well with similar issues.
Instead of using Dictionary<T,V> , if you're more concerned about race conditions and readability than performance (I'm not sure if this will be worse), you might consider using ConcurrentDictionary<T,V> .
It already has a GetOrAdd method that forces you to write less code, and, as is the case with .NET 4.0, it should work and be well documented.
var dict = new ConcurrentDictionary<Expression<Func<T>, Func<T>>(); ... var cacheKey = targetSelector; //or whatever as long as it unique var cachedFunc = dict.GetOrAdd(cacheKey, key => targetSelector.Compile()); In addition, it is likely to be slightly less error related to the conditions of the race. But you should know that GetOrAdd also not thread safe. And if you're interested, take a look at this question on CodeReview.SE , in which they seem to find a solution for this.
Disclaimer: I know this is an old question, which is more related to generating the correct key than a more efficient cache implementation. But I think that people who are looking for this today may be helpful.
Jeffery Zhao has some excellent posts on this subject, unfortunately they are written in Chinese. The good news is that you can download the full implementation code for ExpressionTree caching here . And personally, I have another suggestion: why not Code Contracts ?