Dryadwoods
Dryadwoods

Reputation: 2929

Reflection Performance - Create Delegate (Properties C#) With Conditional Parameters

I am using the solution of the question: Reflection Performance - Create Delegate (Properties C#)

Where I have the following code:

private static Action<object, object> BuildSetAccessor(string name, MethodInfo method)
{
    if (method == null) return null;
    if (method.DeclaringType == null) return null;
    var obj = Expression.Parameter(typeof(object), name);
    var value = Expression.Parameter(typeof(object));
    var expr = Expression.Lambda<Action<object, object>>(Expression.Call(Expression.Convert(obj, method.DeclaringType), method, Expression.Convert(value, method.GetParameters()[0].ParameterType)), obj, value);
    return expr.Compile();
}

private static Func<object, object> BuildGetAccessor(string name, MethodInfo method)
{
    if (method.DeclaringType == null) return null;
    var obj = Expression.Parameter(typeof(object), name);
    var expr = Expression.Lambda<Func<object, object>>(Expression.Convert(Expression.Call(Expression.Convert(obj, method.DeclaringType), method), typeof(object)), obj);
    return expr.Compile();
}

Code in use...

var cacheProperty = new CacheForReflectionClassProperty()
                {
                    Name = p.Name,
                    SetValue = BuildSetAccessor(p.Name, p.GetSetMethod()),
                    GetValue = BuildGetAccessor(p.Name, p.GetGetMethod())
                };
if (Attribute.IsDefined(p, typeof(IsIdentityColumn)))
{
    // TODO: Instead of just getting the old value, 
    // I need to verify if the value is NULL
    // in that case I need to create a new value of ID type....
    // and at the end I need to use the SetValue() method as well
    GetValue = .... // TODO: 
}
else if (Attribute.IsDefined(p, typeof(IsCreatedOnColumn)))
                {
    // TODO: Instead of just getting the old value, 
    // I need to verify if the value is NULL
    // in that case I need to create a new value with DateTime.UtcNow
    // and at the end I need to use the SetValue() method as well
    GetValue = .... // TODO:
                }

I know that I will need to create the following methods:

private static Func<object, object> BuildGetAccessorForIdentityColumn(string name, MethodInfo method)

private static Func<object, object> BuildGetAccessorForCreatedOnColumn(string name, MethodInfo method)

I have tried to learn on how to use Expression trees but I have not found a way where my BuildGetAccessor is not only getting the value but also comparing the result with something and if needed also needs to use the BuildSetAccessor.

How can I do this?

Upvotes: 1

Views: 401

Answers (1)

Evk
Evk

Reputation: 101453

You are doing this because reflection has impact on perfomance. But after you are done with reflection part - you don't need to use compiled expressions any more - just use regular code:

    var getAccessor = BuildGetAccessor(p.Name, p.GetGetMethod());
    var setAccessor = BuildSetAccessor(p.Name, p.GetSetMethod());
    // if IsCreatedOnColumn
    cacheProperty.GetValue = (instance) =>
    {
        var value = getAccessor(instance);
        if (value == null)
        {
            value = DateTime.UtcNow;
            setAccessor(instance, value);
        }
        return value;
    };

Upvotes: 2

Related Questions