简体   繁体   English

反射v表达

[英]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. 我在看另一个问题 ,该问题表明Expression可以比预编译快得多,因为它可以预编译为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. 这是在基类中用于值对象(在DDD意义上)使用的一些代码,其基本思想是使用所有公共属性的值来确定相等性,这是通过反射获得的。 By using this base class, you needn't implement equality for subclasses that have Value Object. 通过使用此基类,您无需为具有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? 如何使用Expression重写此代码?

Cheers, 干杯,
Berryl Berryl

You can do this by building up a nested And expression for each property you want to compare: 您可以通过为要比较的每个属性构建一个嵌套的And表达式来做到这一点:

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);
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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