我正在構建一個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