为了账号安全,请及时绑定邮箱和手机立即绑定

比较执行期间指定的日期时间字段的 C# 方法?

比较执行期间指定的日期时间字段的 C# 方法?

C#
尚方宝剑之说 2021-07-09 10:01:54
我的项目有许多带有日期字段的对象,我经常需要选择一个这样的字段在日期范围内的所有内容。例如:public class Contract{    public DateTime SignDate { get; set; }    public DateTime ReleaseDate { get; set; }}public class PersonalCheck{    public DateTime SignDate { get; set; }    public DateTime ProcessDate { get; set; }    public DateTime VoidDate { get; set; }}如果我只关心 SignDate,那会很容易。我会声明一个接口...public interface IObjectWithSignDate{    DateTime SignDate { get; set; }}...更改我的其他对象以从它继承,然后创建一个这样的方法:    public static IQueryable<T> SignedWithin<T>(this IQueryable<T> items, DateTime start, DateTime end) where T : IObjectWithSignDate    {        return items.Where(q => q.SignDate >= start && q.SignDate <= end);    }如何避免为 ReleaseDate、ProcessDate、VoidDate 等重写此函数?我可以让这个方法接受任何对象的 IQueryable 和一个告诉它运行这个选择器的日期字段的变量吗?请注意,这必须能够 a) 在 LinqToEntities 中执行以针对数据库运行并且 b) 不会增加大量开销(因为我担心反射可能会这样做)
查看完整描述

1 回答

?
红糖糍粑

TA贡献1815条经验 获得超6个赞

简单但具体


您可以添加这样的扩展方法:


public static class DateTimeExtensions

{

    public static bool IsBetween(this DateTime thisDateTime, DateTime start, DateTime end)

    {

        return thisDateTime >= start && thisDateTime <= end;

    }

}

您可以单独进行单元测试。


然后您可以在要检查的任何日期时间字段上使用它。例如:


var start = new DateTime(2017, 1, 1);

var end = new DateTime(2017, 12, 31, 23, 59, 59);

IList<Contract> contracts = new List<Contract>(); // or anything enumerable

var contractsSignedBetween = contracts.Where(x => x.SignDate.IsBetween(start, end));

var contractsReleasedBetween = contracts.Where(x => x.ReleaseDate.IsBetween(start, end));

(请注意我如何将开始日期时间设置为 00:00:00 时间,将结束日期时间设置为 23:59:59 时间[也可以包括毫秒],以便包括最后一天的时间。)


使其可重用


如果你发现自己需要做很多事情,你可以做一个扩展


public static class EnumerableContractsExtensions

{

    public static IEnumerable<Contract> SignedBetween(this IEnumerable<Contract> contracts, DateTime start, DateTime end)

    {

        return contracts.Where(x => x.SignDate.IsBetween(start, end));

    }

}

并像这样使用它


 var contractsSignedBetween = contracts.SignedBetween(start, end);

也可以单独进行单元测试。


更灵活但更具体


使用表达式说出您想要的日期...


public static class EnumerableContractsExtensions

{

    public static IEnumerable<Contract> Between(this IEnumerable<Contract> contracts, Func<Contract, DateTime> selector, DateTime start, DateTime end)

    {

        return contracts.Where(x => selector(x).IsBetween(start, end));

    }

}

然后做:


var contractsSignedBetween = contracts.Between(x => x.SignDate, start, end);

var contractsReleasedBetween = contracts.Between(x => x.ReleaseDate, start, end);

灵活通用


全力以赴并通用(尽管您不能将其设为扩展方法,因为它是通用的):


public static class EnumerableExtensions

{

    public static IEnumerable<T> Between<T>(IEnumerable<T> items, Func<T, DateTime> selector, DateTime start, DateTime end)

    {

        return items.Where(x => selector(x).IsBetween(start, end));

    }

}

同样,这本身就是可测试的,可以像这样使用:


IList<Contract> contracts = new List<Contract>();

IList<PersonalCheck> personalChecks = new List<PersonalCheck>();

var contractsSignedBetween = EnumerableExtensions.Between(contracts, x => x.SignDate, start, end);

var checksSignedBetween = EnumerableExtensions.Between(personalChecks, x => x.SignDate, start, end);

使其可查询


为了使该方法起作用,IQueryable需要转向表达式树,因为 LINQ to Entities 不知道如何将方法转换为 SQL。


public static IQueryable<TSource> Between<TSource, TKey>(

    this IQueryable<TSource> source,

    Expression<Func<TSource, TKey>> keySelector,

    TKey low,

    TKey high)

    where TKey : IComparable<TKey>

{

    Expression key = keySelector.Body;

    Expression lowerBound = Expression.LessThanOrEqual(Expression.Constant(low), key);

    Expression upperBound = Expression.LessThanOrEqual(key, Expression.Constant(high));

    Expression and = Expression.AndAlso(lowerBound, upperBound);

    Expression<Func<TSource, bool>> lambda =

        Expression.Lambda<Func<TSource, bool>>(and, keySelector.Parameters);

    return source.Where(lambda);

}

仍然会像这样使用:


var contractsSignedBetween = contracts.Between(x => x.SignDate, start, end);

这也适用于DateTimes以外的事物。希望这可以帮助。


查看完整回答
反对 回复 2021-07-18
  • 1 回答
  • 0 关注
  • 159 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信