我正在创建一些动态linq,并且遇到以下异常的问题:
二元运算符GreaterThanOrEqual 没有为类型定义 'System.Nullable`1 [System.DateTime的]' 和'System.DateTime'
我明白了,因为我的字段类型可以为空并且我在DateTime.Now中传递了。
因此,在尝试解决此问题时,我尝试了
System.Nullable<DateTime> now;
now = DateTime.Now;
但是结果类型是一个不可为空的对象,因此仍然给我上述异常。
有什么建议吗?!
更新:为了进一步说明, now 变量在设置时变为非可空类型,而不是保留为可空的DateTime,因此匹配会抛出异常
更新:可以在CodePlex项目中看到实际代码:
http://webquarters.codeplex.com/SourceControl/changeset/view/36529#574700
违规行是~145
fExp = Expression.GreaterThanOrEqual(fExpLeft, fExpRight);
答案 0 :(得分:55)
这里的问题是,当给出两个不匹配的可为空性的参数时,表达式库会引发异常。这是一个简单的复制品:
Expression<Func<DateTime?>> ex1 = ()=>DateTime.Now;
Expression<Func<DateTime>> ex2 = ()=>DateTime.Now;
var ex3 = Expression.GreaterThan(ex1.Body, ex2.Body);
我不清楚这是不是一个错误; C#的规则要求在这种情况下,非可空操作数转换为可空,并使用提升到可空的比较形式。 但是,表达式树库不需要遵循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<>);
}
但是,请注意,这并不会检查e1和e2的类型是否仅在可空性方面有所不同;如果你传入一个可以为空的int和一个不可为空的双重表达式,就会发生不好的事情。我把它留作练习来实现更好的逻辑,检查这两个表达式是否只有可空性的类型。< / p>
答案 1 :(得分:2)
我不确定你的代码究竟是什么,但要获得Nullable的非可空版本,请调用其.Value
成员。
答案 2 :(得分:2)
无论你的比较是什么,改变这样的比较:
(nullableDT >= DT)
要
(nullableDT != null && nullableDT.Value >= DT)
编辑:
根据你的评论,编写一个带有2个对象的函数,在函数内检查它们是否为可空类型,并检查是否为null,然后比较值。此函数可能使用类似于^。
的代码尽管如此,这开始听起来像你有一个更大的潜在问题。要么你得到的数据不正确,(你的代码在其他地方返回的数据不应该是,代码中不是问题,而是逻辑上的问题),或者你可以比较这些对象的假设是无效的。再一次,这是一个逻辑错误。
我想你可能需要退一步这一分钟。如果您发布更多代码,我们可能会为您提供更多帮助。
答案 3 :(得分:2)
我找到了一个在.Net框架内运行的解决方案。这里有一个方法仍在进行中但它确实有效,并且适用于Linq to Entities:
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();
此代码基于MVC 3,因此一些ParamsData [“”]即(Request.Params)。
答案 4 :(得分:0)
这很有趣,
我已尝试过此代码的两种变体:
System.Nullable<DateTime> now = new System.Nullable<DateTime>();
now = DateTime.Now;
和
System.Nullable<DateTime> now;
now = DateTime.Now;
并且他们都没有错误地工作。
然后我重新阅读你的问题。实际上答案仍然是“价值”属性。如果正常则初始化变量,但如果你这样做:
Linq查询中的(现在&gt; = DateTime.Now)您将收到错误消息。它应该是(now.Value&gt; = DateTime.Now)