【问题标题】:Force convert DateTimeOffset to Nullable<DateTimeOffset>强制将 DateTimeOffset 转换为 Nullable<DateTimeOffset>
【发布时间】:2018-07-24 15:59:42
【问题描述】:

我需要编写一个动态构建 LINQ 查询表达式的函数。我无法构建将DateTimeOffsetDateTimeOffset? 进行比较的Equals 表达式(Expression.Equal 抱怨无法比较类型),我也无法将DateTimeOffset 转换为@987654326 @ 使Expression.Equal 工作,因为无论我使用什么转换策略,DateTimeOffset 都无法转换为DateTimeOffset?

MyEntity.cs:

public class MyEntity {
    public DateTimeOffset? DeliverOn;
}

Main.cs:

public void Test {
    IQueryable<MyEntity> MyEntityList = Enumerable.Empty<MyEntity>().AsQueryable();
    DateTimeOffset? dt1 = new DateTimeOffset(2018, 01, 01, 00, 00, 00, TimeSpan.Zero);
    var expr = WhereEquals(MyEntityList, t => t.DeliverOn, dt1);
}

ExpressionBuilder.cs:

public static IQueryable<TSource> WhereEquals<TSource, TValue>(IQueryable<TSource> source, Expression<Func<TSource, TValue>> selector, TValue value) {
    return source.Where(Expression.Lambda<Func<TSource, bool>>(Expression.Equal(selector.Body, Expression.Constant(value)), selector.Parameters));
}

抛出:System.InvalidOperationException: 'The binary operator Equal is not defined for the types 'System.Nullable``1[System.DateTimeOffset]' and 'System.DateTimeOffset'.'

尽管 dt1 在编译时是 DateTimeOffset?,但在运行时,C# 认为 dt1DateTimeOffset。我可以解决这个问题吗?

我试过了:

  • DateTimeOffset? dt1 = (DateTimeOffset?)new DateTimeOffset(2018, 01, 01, 00, 00, 00, TimeSpan.Zero);
  • DateTimeOffset? dt1 = (DateTimeOffset?)(object)new DateTimeOffset(2018, 01, 01, 00, 00, 00, TimeSpan.Zero);
  • DateTimeOffset? dt1 = (DateTimeOffset?)Convert.ChangeType(new DateTimeOffset(2018, 01, 01, 00, 00, 00, TimeSpan.Zero), typeof());

但是 dt1 仍然是 DateTimeOffset

【问题讨论】:

    标签: c# linq


    【解决方案1】:

    使用重载Expression.Constant(Object, Type) 指定要用于比较的值的类型。

    在不指定类型的情况下,Nullable&lt;DateTimeOffset&gt; 将被解包为简单的DateTimeOffset

    void Main()
    {
        //IQueryable<MyEntity> MyEntityList = Enumerable.Empty<MyEntity>().AsQueryable();
        var MyEntityList = new List<MyEntity>();
        MyEntityList.Add(new MyEntity { DeliverOn = new DateTimeOffset(2018, 01, 01, 00, 00, 00, TimeSpan.Zero) });
        DateTimeOffset? dt1 = new DateTimeOffset(2018, 01, 01, 00, 00, 00, TimeSpan.Zero);
        var expr = WhereEquals<MyEntity, DateTimeOffset?>(MyEntityList.AsQueryable(), t => t.DeliverOn, (DateTimeOffset?)dt1);
        Console.WriteLine($"{expr.Count()} item(s) found");
    
        // Output:
        // selector.GetType() is System.Linq.Expressions.Expression`1[System.Func`2[UserQuery + MyEntity, System.Nullable`1[System.DateTimeOffset]]]
        // typeof(TValue) is System.Nullable`1[System.DateTimeOffset]
        // value.GetType() is System.DateTimeOffset
        // 1 item(s) found
    }
    
    public class MyEntity
    {
        public DateTimeOffset? DeliverOn;
    }
    
    public static IQueryable<TSource> WhereEquals<TSource, TValue>(IQueryable<TSource> source, Expression<Func<TSource, TValue>> selector, TValue value)
    {
        Console.WriteLine($"selector.GetType() is {selector.GetType()}");
        Console.WriteLine($"typeof(TValue) is {typeof(TValue)}");
        Console.WriteLine($"value.GetType() is {value.GetType()}");
        return source.Where(Expression.Lambda<Func<TSource, bool>>(Expression.Equal(selector.Body, Expression.Constant(value, typeof(TValue))), selector.Parameters));
    }
    

    相关,虽然接受的答案使用Expression.Convert(),我认为这是不必要的。

    Working with nullable types in Expression Trees

    【讨论】:

      猜你喜欢
      • 2021-04-25
      • 1970-01-01
      • 2012-12-05
      • 1970-01-01
      • 2013-07-25
      • 1970-01-01
      • 2019-09-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多