Geeks With Blogs
.Nettuce Code Salad
 public static class ExpressionCache
    {
        static readonly ConcurrentDictionary<stringAction<objectobject>> Setters = new ConcurrentDictionary<stringAction<objectobject>>();
        static readonly ConcurrentDictionary<stringFunc<objectobject>> Getters = new ConcurrentDictionary<stringFunc<objectobject>>();

        public static void SetProperty(this object obj, string propertyName, object value)
        {
            CreateSetter(obj, propertyName).Invoke(obj, value);
        }

        public static T GetProperty<T>(this object obj, string propertyName)
        {
            return (T)CreateGetter(obj, propertyName).Invoke(obj);
        }

        public static object GetProperty(this object obj, string propertyName)
        {
            return obj.GetProperty<object>(propertyName);
        }

        static Action<objectobject> CreateSetter(object obj, string propertyName)
        {
            var type = obj.GetType();
            var property = type.GetProperty(propertyName);
            var key = type.Name + propertyName;
            if (Setters.ContainsKey(key))
                return Setters[key];
            var instance = Expression.Parameter(typeof(object));
            var value = Expression.Parameter(typeof(object));
            var instanceCast = (!property.DeclaringType.IsValueType) ? Expression.TypeAs(instance, property.DeclaringType) : Expression.Convert(instance, property.DeclaringType);
            var valueCast = (!property.PropertyType.IsValueType) ? Expression.TypeAs(value, property.PropertyType) : Expression.Convert(value, property.PropertyType);
            var methodCallExpression = Expression.Call(instanceCast, property.GetSetMethod(), valueCast);
            var setter = Expression.Lambda<Action<objectobject>>(methodCallExpression, instance, value).Compile();
            Setters.TryAdd(key, setter);
            return setter;
        }

        static Func<objectobject> CreateGetter(object obj, string propertyName)
        {
            var type = obj.GetType();
            var property = type.GetProperty(propertyName);
            var key = type.Name + propertyName;
            if (Getters.ContainsKey(key))
                return Getters[key];
            var instance = Expression.Parameter(typeof(object));
            var instanceCast = (!property.DeclaringType.IsValueType) ? Expression.TypeAs(instance, property.DeclaringType) : Expression.Convert(instance, property.DeclaringType);
            var getMethodCast = Expression.TypeAs(Expression.Call(instanceCast, property.GetGetMethod()), typeof(object));
            var getter = Expression.Lambda<Func<objectobject>>(getMethodCast, instance).Compile();
            Getters.TryAdd(key, getter);
            return getter;
        }
    }
Posted on Tuesday, February 5, 2013 4:02 PM | Back to top


Comments on this post: Caching Set and Get Expressions

# re: Caching Set and Get Expressions
Requesting Gravatar...
Could you basically explain what the coding "Caching Set and Get Expressions" does. I tried to understand it. Sorry about my ignorance of your abstract coding but I want to learn it. Thanks.

Jian w. Cheng
Left by Jian W. Cheng on Feb 05, 2013 6:23 PM

# re: Caching Set and Get Expressions
Requesting Gravatar...
public class MyTestReflectionObj
{
public long Id { get; set; }
public string Name { get; set; }
}

[TestMethod]
public void ReflectionUtils_Objects()
{
var obj = new MyTestReflectionObj();
ExpressionCache.SetProperty(obj, "Id", 1);
}

System.InvalidCastException

Wont work, and I don't know why...
Left by Yuri on Nov 20, 2015 5:40 AM

# re: Caching Set and Get Expressions
Requesting Gravatar...
I basically discovered the problem: the value format must be exact or it will throw this exception. It was my fault. Your code works like a charm!

Jian w. Cheng,

He does an access to the dictionary first. If nothing is there, then he creates a getter and a setter to a property by using Expressions and caches it in a Dictionary protected from race conditions on multithreading (which is basic for using this widely in a framework, for example), than returns the new getter/setter to be used.

So, the first time this code is called for a type/property, it is slow, due to the getter/setter creation. But then they are cached and it is faster to the next calls until your app terminates.

Nice work and thanks for sharing
Left by Yuri on Nov 20, 2015 5:52 AM

Your comment:
 (will show your gravatar)


Copyright © Jon Canning | Powered by: GeeksWithBlogs.net