简体   繁体   中英

reflection v expression

I was looking at another question that stated how Expression can be significantly faster than reflection since it can be precompiled to IL.

I'm not really sure how to use it though. Here is some code used in a base class for a Value Oject (in the DDD sense) where the basic idea is to use the values of all public properties to determine equality, which it gets via reflection. By using this base class, you needn't implement equality for subclasses that have Value Object.

protected virtual bool HasSameObjectSignatureAs(BaseObject compareTo) 
{
var signatureProperties = GetType().GetProperties();
foreach (var property in signatureProperties)
{
    var valueOfThisObject = property.GetValue(this, null);
    var valueOfCompareTo = property.GetValue(compareTo, null);

    if (valueOfThisObject == null && valueOfCompareTo == null) {
        continue;
    }

    if ((valueOfThisObject == null ^ valueOfCompareTo == null) ||
        (!valueOfThisObject.Equals(valueOfCompareTo))) {
            return false;
    }
}

How would this code be re-written using Expression?

Cheers,
Berryl

You can do this by building up a nested And expression for each property you want to compare:

protected Expression<Func<BaseObject, bool>> CreatePropertiesEqualExpression(BaseObject other)
{
    if (! other.GetType().IsSubclassOf(this.GetType())) throw new ArgumentException();

    var properties = this.GetType().GetProperties();
    Expression trueExpr = Expression.Constant(true);
    Expression thisExpr = Expression.Constant(this);
    ParameterExpression paramExpr = Expression.Parameter(typeof(BaseObject), "compareTo");
    Expression downCastExpr = Expression.Convert(paramExpr, other.GetType());

    MethodInfo eqMethod = typeof(object).GetMethod("Equals", BindingFlags.Public | BindingFlags.Static);

    Expression propCompExpr = properties.Aggregate(trueExpr, (expr, prop) =>
    {
        Expression thisPropExpr = Expression.Property(thisExpr, prop);
        Expression compPropExpr = Expression.Property(downCastExpr, prop);
        Expression eqExpr = Expression.Call(null, eqMethod, Expression.Convert(thisPropExpr, typeof(object)), Expression.Convert(compPropExpr, typeof(object)));

        return Expression.And(expr, eqExpr);
    });

    return Expression.Lambda<Func<BaseObject, bool>>(propCompExpr, paramExpr);
}

You can then use it like this:

public class SubObject : BaseObject
{
    public int Id { get; set; }
    public string Name { get; set; }
    private Func<BaseObject, bool> eqFunc;

    public bool IsEqualTo(SubObject other)
    {
        if(this.eqFunc == null)
        {
            var compExpr = this.CreatePropertiesEqualExpression(other);
            this.eqFunc = compExpr.Compile();
        }
        return this.eqFunc(other);
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM