我正在构建一个Expression
应该代表一个Equals
比较属性和Nullable<long>
类型的常量。换句话说,编译表达式应该返回类似于x => (x.Id == value)
的lambda,其中Id
和value
的类型都是long?
。Linq表达式抛出InvalidOperationException
这是代码:
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:从范围
''
'SomeEntity'
引用类型的可变'x'
,但它没有被定义。
我在做什么错?
[编辑]
感谢@ 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);
}
测试(用于拉姆达编译版本):
[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 }));
}
}
我想在您的示例代码工作正常;是否有可能在* real *代码中没有向表达式提供参数(在'Lambda'调用中),或者您正在重写表达式而不替换参数? –
@Marc:实际上,我将它传递给了NHibernate(不完全是最新版本),所以它可能有可能'null'检查没有在其提供者中正确实现(如下所述)。 – Groo