属性表达式的C#聚合返回AmbiguousMatchException

时间:2018-10-31 09:43:15

标签: c# reflection linq-expressions

我有以下(简化的)课程:

public abstract class BaseSite
{
    public int SiteId { get; set; }
    public string Name { get; set; }
}

public class OptionalSite : BaseSite
{
    public new int? SiteId { get; set; }
}

以及以下方法:

    public static Expression<Func<T, bool>> PredicateExtension<T>(this IQueryable<T> source, string member, object value, string expression)
    {
        ParameterExpression item = Expression.Parameter(typeof(T), "item");
        Expression memberValue = member.Split('.').Aggregate((Expression)item, Expression.PropertyOrField);
        Type memberType = memberValue.Type;
        if (value != null && value.GetType() != memberType)
            value = Convert.ChangeType(value, memberType);
        Expression condition = null;
        switch (expression)
        {
            case "==":
                condition = Expression.Equal(memberValue, Expression.Constant(value, memberType));
                break;
            case "!=":
                condition = Expression.NotEqual(memberValue, Expression.Constant(value, memberType));
                break;
            case "<":
                condition = Expression.LessThan(memberValue, Expression.Constant(value, memberType));
                break;
            case ">":
                condition = Expression.GreaterThan(memberValue, Expression.Constant(value, memberType));
                break;
            case "<=":
                condition = Expression.LessThanOrEqual(memberValue, Expression.Constant(value, memberType));
                break;
            case ">=":
                condition = Expression.GreaterThanOrEqual(memberValue, Expression.Constant(value, memberType));
                break;
            default:
                break;
        }
        if (condition == null)
            condition = Expression.Equal(memberValue, Expression.Constant(value, memberType));
        var predicate = Expression.Lambda<Func<T, bool>>(condition, item);

        return predicate;
    }

现在使用以下参数调用方法时:

LinqExtentions.PredicateExtension<OptionalSite>(SiteDbSet, "SiteId", 1, "==");

我有以下问题: 方法的第二行有一个Aggregate调用,但这给了我AmbiguousMatchException。 原因是属性SiteId是在基类和OptionalSite类(public new ...)中定义的。

所以这里的问题是:如何使用此(或其他)方法获取正确的Expression?我可能需要获得相同的Expression结果,但使用不同的获取方法,以便在基类和已实现的类中找到属性时,可以为实现基类的属性选择属性课。

编辑:

SiteId的类型从int变为int?。实现此基类的其他类需要将其作为必需属性(EF),但此类需要将其作为可选属性。 因此,我无法在基类中使用virtual关键字。

1 个答案:

答案 0 :(得分:3)

有关为何获得AmbiguousMatchException以及如何解决的信息,您可以查看this的答案。

您将不得不使用更高级的功能:

Expression memberValue = member.Split('.').Aggregate((Expression)item, (expr, name) =>
{
    // get all properties with matching name
    var properties = expr.Type.GetProperties().Where(p => p.Name == name);
    // if only one found, use that, else use the one that is declared in the derived type
    var property = properties.Count() == 1 ? properties.First() : properties.Single(p => p.DeclaringType == expr.Type);
    // make expression from this PropertyInfo
    return Expression.Property(expr, property);
});

请注意,这只是一种基本方法。它不考虑字段(对于EF而言不成问题),并且可能有多个继承级别,并且在两者之间的任何位置声明了该属性。但是你明白了。