C# Expression.GreaterThan在一个操作数为可空类型,另一个操作数为不可空类型时失败
我正在创建一些动态linq,但遇到以下问题: 二元运算符大于或等于 未为类型定义 'System.Nullable'1[System.DateTime]' 和“系统日期时间” 我明白为什么了,因为我的字段类型是可以为空的,我现在本质上是在传递DateTime 所以在试图解决这个问题的过程中,我尝试了C# Expression.GreaterThan在一个操作数为可空类型,另一个操作数为不可空类型时失败,c#,.net,c#-3.0,C#,.net,C# 3.0,我正在创建一些动态linq,但遇到以下问题: 二元运算符大于或等于 未为类型定义 'System.Nullable'1[System.DateTime]' 和“系统日期时间” 我明白为什么了,因为我的字段类型是可以为空的,我现在本质上是在传递DateTime 所以在试图解决这个问题的过程中,我尝试了 System.Nullable<DateTime> now; now = DateTime.Now; 我不确定您的代码到底是什么,但要获得可为null的不可为null的版本,请调用其.
System.Nullable<DateTime> now;
now = DateTime.Now;
我不确定您的代码到底是什么,但要获得可为null的不可为null的版本,请调用其
.Value
成员。在任何比较位置,按如下方式更改比较:
(nullableDT >= DT)
到
编辑:
根据您的注释,编写一个包含2个对象的函数,在函数内部检查它们是否为可空类型,并检查是否为空,然后比较值。此函数可能会使用类似于^的代码
不过,这听起来好像你有一个更大的潜在问题。要么您得到了不正确的数据(即,您在其他地方的代码返回的数据不应该是错误的,不是代码中的问题,而是逻辑中的问题),要么您可以比较这些对象的假设是无效的。这又是一个逻辑错误
我想你可能需要在这件事上退一步。如果您发布更多的代码,我们可能会为您提供更多帮助。这很有趣
我尝试了这两种代码的变体:
System.Nullable<DateTime> now = new System.Nullable<DateTime>();
now = DateTime.Now;
System.Nullable now=new System.Nullable();
现在=日期时间。现在;
及
系统。现在可以为空;
现在=日期时间。现在;
他们两人都工作得很顺利
然后我重读你的问题。实际上,答案仍然是“值”属性。初始化变量(如果可以),但如果这样做:
(现在>=DateTime.now)在Linq查询中,您将得到一个错误。它应该是(now.Value>=DateTime.now)这里的问题是,当给定两个不匹配的nullability参数时,表达式库会引发异常。这里有一个简单的复制:
Expression<Func<DateTime?>> ex1 = ()=>DateTime.Now;
Expression<Func<DateTime>> ex2 = ()=>DateTime.Now;
var ex3 = Expression.GreaterThan(ex1.Body, ex2.Body);
表达式ex1=()=>DateTime.Now;
表达式ex2=()=>DateTime.Now;
var ex3=Expression.GreaterThan(ex1.Body,ex2.Body);
我不清楚这是否是一个bug;C#的规则要求在这种情况下,将不可为null的操作数转换为可为null的操作数,并使用提升为可为null的比较形式。但是,表达式树库不需要遵循C#的规则,因为表达式树库当然可以用来表示C#表达式、Python表达式、JScript表达式、VB表达式等;它不可能遵循所有可能语言的所有规则
但无论如何,这看起来可能是一个bug,所以我将把它提交给表达式树团队,看看他们怎么说。同时,您可以通过定义自己的帮助器方法来修复操作数,从而轻松解决此问题。一个速写应该是:
static Expression MyGreaterThan(Expression e1, Expression e2)
{
if (IsNullableType(e1.Type) && !IsNullableType(e2.Type))
e2 = Expression.Convert(e2, e1.Type);
else if (!IsNullableType(e1.Type) && IsNullableType(e2.Type))
e1 = Expression.Convert(e1, e2.Type);
return Expression.GreaterThan(e1, e2);
}
static bool IsNullableType(Type t)
{
return t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Nullable<>);
}
静态表达式MyGreaterThan(表达式e1、表达式e2)
{
if(IsNullableType(e1.Type)&&!IsNullableType(e2.Type))
e2=表达式.Convert(e2,e1.Type);
如果(!IsNullableType(e1.Type)和&IsNullableType(e2.Type))
e1=表达式.Convert(e1,e2.Type);
返回表达式。大于(e1,e2);
}
静态bool IsNullableType(类型t)
{
返回t.IsGenericType&&t.GetGenericTypeDefinition()==typeof(可为null);
}
但是,请注意,这并不能检查e1和e2的类型是否仅在可空性方面不同;如果传入一个可为Null的int和一个不可为Null的double表达式,就会发生不好的事情。我把它作为一个练习,以实现更好的逻辑,检查这两个表达式的类型是否只有可为Null性不同。我找到了一个在.Net framework中工作的解决方案。这里有一个方法仍在进行中,但它确实有效,并且适用于Linq to实体:
public PagedViewModel<T> Filter<TValue>(Expression<Func<T, TValue>> predicate, FilterType filterType = FilterType.Equals) {
var name = (predicate.Body as MemberExpression ?? ((UnaryExpression)predicate.Body).Operand as MemberExpression).Member.Name;
var value = Expression.Constant(ParamsData[name].To<TValue>(), typeof (T).GetProperty(name).PropertyType);
// If nothing has been set for filter, skip and don't filter data.
ViewData[name] = m_QueryInternal.Distinct(predicate.Compile()).ToSelectList(name, name, ParamsData[name]);
if (string.IsNullOrWhiteSpace(ParamsData[name]))
return this;
var nameExpression = Expression.Parameter(typeof(T), name);
var propertyExpression = Expression.Property(nameExpression, typeof(T).GetProperty(name));
// Create expression body based on type of filter
Expression expression;
MethodInfo method;
switch(filterType) {
case FilterType.Like:
method = typeof(string).GetMethod("Contains", new[] { typeof(string) });
expression = Expression.Call(propertyExpression, method, value);
break;
case FilterType.EndsWith:
case FilterType.StartsWith:
method = typeof(string).GetMethod(filterType.ToString(), new[] { typeof(string) });
expression = Expression.Call(propertyExpression, method, value);
break;
case FilterType.GreaterThan:
expression = Expression.GreaterThan(propertyExpression, value);
break;
case FilterType.Equals:
expression = Expression.Equal(propertyExpression, value);
break;
default:
throw new ArgumentException("Filter Type could not be determined");
}
// Execute the expression against Query.
var methodCallExpression = Expression.Call(
typeof (Queryable),
"Where",
new[] { Query.ElementType },
Query.Expression,
Expression.Lambda<Func<T, bool>>(expression, new[] { nameExpression }));
// Filter the current Query data.
Query = Query.Provider.CreateQuery<T>(methodCallExpression);
return this;
}
publicpagedviewmodel过滤器(表达式谓词,FilterType FilterType=FilterType.Equals){
变量名称=(predicate.Body作为MemberExpression??((UnaryExpression)predicate.Body)。操作数作为MemberExpression)。Member.name;
var value=Expression.Constant(ParamsData[name].To(),typeof(T).GetProperty(name).PropertyType);
//如果未为筛选设置任何内容,请跳过并不筛选数据。
ViewData[name]=m_QueryInternal.Distinct(predicate.Compile()).ToSelectList(name,name,ParamsData[name]);
if(string.IsNullOrWhiteSpace(ParamsData[name]))
归还这个;
var nameExpression=Expression.Parameter(typeof(T),name);
var propertyExpression=Expression.Property(nameExpression,typeof(T).GetProperty(name));
//基于筛选器类型创建表达式正文
表达;
方法信息法;
开关(过滤器类型){
案例筛选器类型。例如:
method=typeof(string).GetMethod(“Contains”,new[]{typeof(string)});
expression=expression.Call(propertyExpression、方法、值);
打破
案例过滤器type.EndsWith:
案例过滤器type.StartsWith:
method=typeof(string).GetMethod(filterType.ToString(),new[]{typeof(string)});
expression=expression.Call(propertyExpression、方法、值);
打破
案例过滤器类型。大于:
expression=expression.GreaterThan(propertyExpression,value);
打破
案例过滤器类型。等于:
expression=expression.Equal(propertyExpression,value);
打破
违约:
抛出新ArgumentException(“无法确定筛选器类型”);
}
//对查询执行表达式。
var methodCallExpr
Expression<Func<DateTime?>> ex1 = ()=>DateTime.Now;
Expression<Func<DateTime>> ex2 = ()=>DateTime.Now;
var ex3 = Expression.GreaterThan(ex1.Body, ex2.Body);
static Expression MyGreaterThan(Expression e1, Expression e2)
{
if (IsNullableType(e1.Type) && !IsNullableType(e2.Type))
e2 = Expression.Convert(e2, e1.Type);
else if (!IsNullableType(e1.Type) && IsNullableType(e2.Type))
e1 = Expression.Convert(e1, e2.Type);
return Expression.GreaterThan(e1, e2);
}
static bool IsNullableType(Type t)
{
return t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Nullable<>);
}
public PagedViewModel<T> Filter<TValue>(Expression<Func<T, TValue>> predicate, FilterType filterType = FilterType.Equals) {
var name = (predicate.Body as MemberExpression ?? ((UnaryExpression)predicate.Body).Operand as MemberExpression).Member.Name;
var value = Expression.Constant(ParamsData[name].To<TValue>(), typeof (T).GetProperty(name).PropertyType);
// If nothing has been set for filter, skip and don't filter data.
ViewData[name] = m_QueryInternal.Distinct(predicate.Compile()).ToSelectList(name, name, ParamsData[name]);
if (string.IsNullOrWhiteSpace(ParamsData[name]))
return this;
var nameExpression = Expression.Parameter(typeof(T), name);
var propertyExpression = Expression.Property(nameExpression, typeof(T).GetProperty(name));
// Create expression body based on type of filter
Expression expression;
MethodInfo method;
switch(filterType) {
case FilterType.Like:
method = typeof(string).GetMethod("Contains", new[] { typeof(string) });
expression = Expression.Call(propertyExpression, method, value);
break;
case FilterType.EndsWith:
case FilterType.StartsWith:
method = typeof(string).GetMethod(filterType.ToString(), new[] { typeof(string) });
expression = Expression.Call(propertyExpression, method, value);
break;
case FilterType.GreaterThan:
expression = Expression.GreaterThan(propertyExpression, value);
break;
case FilterType.Equals:
expression = Expression.Equal(propertyExpression, value);
break;
default:
throw new ArgumentException("Filter Type could not be determined");
}
// Execute the expression against Query.
var methodCallExpression = Expression.Call(
typeof (Queryable),
"Where",
new[] { Query.ElementType },
Query.Expression,
Expression.Lambda<Func<T, bool>>(expression, new[] { nameExpression }));
// Filter the current Query data.
Query = Query.Provider.CreateQuery<T>(methodCallExpression);
return this;
}
var paramsData = new NameValueCollection { { "CreatedOn", DateTime.Today.ToString() } };
var model = m_data.ToPagedList(new ViewDataDictionary(), paramsData, 1, 10, null, x => x.LastName)
.Filters(Criteria<TrainerProfile>.New(x => x.CreatedOn, FilterType.GreaterThan))
.Setup();