我正在构建一个Expression
,它应该代表Equals
属性和类型Nullable<long>
的常量的比较。换句话说,编译表达式应返回类似于x => (x.Id == value)
的lambda,其中Id
和value
都是long?
类型。
这是代码:
private static Expression<Func<T, bool>> GetNullableIdEqualsQuery(long? value)
{
var type = typeof(T);
var idProperty = type.GetProperty("Id");
var xParam = Expression.Parameter(type, "x");
var block = Expression.Block(
typeof(bool),
Expression.Equal(
Expression.Property(xParam, idProperty),
Expression.Constant(value, typeof(long?)))
);
return Expression.Lambda<Func<T, bool>>(block, xParam);
}
但是在查询中使用时,它会失败并显示InvalidOperationException
:
System.InvalidOperationException:从作用域
'x'
引用的'SomeEntity'
类型的变量''
,但未定义。
我做错了什么?
[编辑]
感谢@ MarcGravell的回答,我修复了代码。我假设NHibernate的LINQ提供程序中有些东西被破坏了,但是现在我没有时间进一步调查。
如果有人需要一个通用版本(好吧,应该)适用于任何属性类型,这里是:
public static Expression<Func<Tobj, bool>> GetEqualsQuery<Tobj, Tprop>(Tprop value, string propertyName)
{
var type = typeof(Tobj);
var property = type.GetProperty(propertyName);
var propertyType = property.PropertyType;
if (propertyType != typeof(Tprop))
throw new InvalidOperationException("Property type ({0}) does not match the value type ({1})"
.FormatWith(propertyType, typeof(Tprop)));
var xParam = Expression.Parameter(type, "x");
var body = Expression.Equal(
Expression.Property(xParam, property),
Expression.Constant(value, propertyType)
);
return Expression.Lambda<Func<Tobj, bool>>(body, xParam);
}
测试(仅适用于lambda编译版本):
[TestClass]
public class ExpressionHelperTest
{
class Test
{
public long Id { get; set; }
}
[TestMethod]
public void GetEqualsQueryWorksForSimpleTypes()
{
// create a query for the lambda x => x.Id == 5
var lambda = ExpressionHelper
.GetEqualsQuery<Test, long>(5, "Id")
.Compile();
Assert.IsTrue(lambda(new Test() { Id = 5 }));
Assert.IsFalse(lambda(new Test() { Id = 8 }));
}
}
答案 0 :(得分:4)
请勿使用Expression.Block
:
var body = Expression.Equal(
Expression.Property(xParam, idProperty),
Expression.Constant(value, typeof(long?)));
return Expression.Lambda<Func<T, bool>>(body, xParam);
另请注意,当值为null
时,某些提供程序无法正确实现上述内容。如果您需要查找null
个匹配项,则可能需要特殊情况并明确检查HasValue
:
private static Expression<Func<T, bool>> GetNullableIdEqualsQuery<T>(long? value)
{
var xParam = Expression.Parameter(typeof(T), "x");
Expression body;
if (value == null)
{
body = Expression.Not(
Expression.Property(
Expression.Property(xParam, "Id"),
"HasValue"));
}
else
{
body = Expression.Equal(
Expression.Property(xParam, "Id"),
Expression.Constant(value, typeof(long?)));
}
return Expression.Lambda<Func<T, bool>>(body, xParam);
}