属性 表达式 returns AmbiguousMatchException 的 C# 聚合
C# Aggregate for property Expression returns AmbiguousMatchException
我有以下(简体)classes:
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
在基础 class 和 OptionalSite
class 中都有定义(public new ...) ...
所以这里的问题是:如何使用这种(或另一种)方法获得正确的表达式?我可能需要获得相同的 Expression
结果,但使用不同的方式获取它,以便在基础 class 和实现的 class 中找到属性时,我可以为属性 在实现基础 class.
的 class 上
编辑:
SiteId
的类型由 int
更改为 int?
。实现此基础 class 的其他 classes 需要将其作为必需的 属性 (EF),但此 class 需要它是可选的 属性。
因此,我无法在我的基础 class.
中使用 virtual
关键字
有关为什么会出现 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 的问题)并且可以有多个继承级别,其中 属性 在中间的任何位置声明。但是你明白了。
我有以下(简体)classes:
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
在基础 class 和 OptionalSite
class 中都有定义(public new ...) ...
所以这里的问题是:如何使用这种(或另一种)方法获得正确的表达式?我可能需要获得相同的 Expression
结果,但使用不同的方式获取它,以便在基础 class 和实现的 class 中找到属性时,我可以为属性 在实现基础 class.
编辑:
SiteId
的类型由 int
更改为 int?
。实现此基础 class 的其他 classes 需要将其作为必需的 属性 (EF),但此 class 需要它是可选的 属性。
因此,我无法在我的基础 class.
virtual
关键字
有关为什么会出现 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 的问题)并且可以有多个继承级别,其中 属性 在中间的任何位置声明。但是你明白了。