linq 表达式.PropertyOrField中出现不明确的匹配异常

slhcrj9b  于 2022-12-06  发布在  其他
关注(0)|答案(2)|浏览(155)

我正在使用反射来创建一个lambda函数。它对我尝试使用的大多数项目都有效,但是在其中一个属性上它总是抛出一个Ambiguous Match异常。
代码看起来像这样。当它遇到Expression.PropertyOrField时发生错误。我使用的属性是decimal?类型。我认为这可能与它是一个可空类型有关,但我不确定。

public static LambdaExpression CreateExpression(Type type, string propertyName, ref Type returnType)
{
    var param = Expression.Parameter(type, "x");
    Expression body = param;
    foreach (var member in propertyName.Split('.'))
    {
        body = Expression.PropertyOrField(body, member);
    }
    returnType = body.Type;
    return Expression.Lambda(body, param);
}
e3bfsja2

e3bfsja21#

我认为在这种情况下只有一种方法可以抛出这样异常:您有多个名称相同但大小写不同的属性,如下所示:

public class Test {
    public decimal? testProp { get; set; }
    public decimal? TestProp { get; set; }
}

或字段:

public class Test {
    public decimal? testProp;
    public decimal? TestProp;
}

请注意,具有相同名称的属性也可能位于任何上层父类别中:

public class BaseTest {
    public decimal? testProp { get; set; }
}

public class Test : BaseTest {        
    public decimal? TestProp { get; set; } // also fails
}

原因是Expression.PropertyOrField这样做是为了搜索所需的属性:

type.GetProperty(propertyOrFieldName, BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy);

注意BindingFlags.IgnoreCaseBindingFlags.FlattenHierarchy,所以不能让Expression.PropertyOrField以区分大小写的方式进行搜索。
然而,我认为,拥有多个同名属性是一个坏的做法,应该避免。

ahy6op9u

ahy6op9u2#

这就是我解决这个问题的方法。我在 predicate 构建器中使用Expression.PropertyOrField。我有一个扩展方法,它使用Expression构建器获得一个深度/嵌套属性。我希望它能帮助其他人。

public static Expression GetDeepProperty(this ParameterExpression param, string propertyName)
{
    if (propertyName.IndexOf('.') != -1)
    {
        return propertyName.Split('.').Aggregate<string, Expression>(param, (c, m) =>
        {
            try
            {
                return Expression.PropertyOrField(c, m);
            }
            catch (Exception ex)
            {

                var type = c.Type;
                var prop = type.GetProperty(m, BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance);
                if (prop != null)
                {
                    return Expression.Property(param, prop);
                }
                var field = type.GetField(m, BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance);
                if (field != null)
                {
                    return Expression.Field(param, field);
                }
                throw ex;
            }
        });
    }
    else
    {
        return Expression.PropertyOrField(param, propertyName);
    }
}

这是可以修复不明确匹配问题的实际代码。请根据您的要求更改属性/字段名称。我的示例基于ab

var o = new b();

var param = Expression.Parameter(o.GetType());
try
{
    var prop = Expression.PropertyOrField(param, "Entity").Dump();
}
catch
{
    //param.Dump();
    var type = param.Type;
    var prop = type.GetProperty("Entity", BindingFlags.DeclaredOnly| BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance);
    if(prop != null)
    {
        Expression.Property(param, prop).Dump();
    }
    else
    {
        var field = type.GetField("field", BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance).Dump();
        if(field != null)
        {
            Expression.Field(param, field).Dump();
        }
    }
    //type.DeclaredProperties
}


//Testing entities and re-producing ambiguity.
class a
{
    public object Entity { get; set; }  
    public object field;
}

class b:a{
    public new int Entity { get; set; }
    public new int field;
}

相关问题