首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >用于比较执行过程中指定的DateTime字段的C#方法?

用于比较执行过程中指定的DateTime字段的C#方法?
EN

Stack Overflow用户
提问于 2018-06-02 01:16:39
回答 1查看 389关注 0票数 1

我的项目有许多带有日期字段的对象,我经常需要选择其中一个字段在日期范围内的所有对象。

例如:

代码语言:javascript
复制
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,事情就简单多了。我会声明一个接口...

代码语言:javascript
复制
public interface IObjectWithSignDate
{
    DateTime SignDate { get; set; }
}

...change我的其他对象以继承它,然后创建一个方法,如下所示:

代码语言:javascript
复制
    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)不会增加很多开销(我担心反射可能会这样做)

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-06-02 15:29:03

简单但具体的

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

代码语言:javascript
复制
public static class DateTimeExtensions
{
    public static bool IsBetween(this DateTime thisDateTime, DateTime start, DateTime end)
    {
        return thisDateTime >= start && thisDateTime <= end;
    }
}

您可以隔离地对其进行单元测试。

然后,您可以在任何想要检查的DateTime字段上使用它。例如:

代码语言:javascript
复制
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时间,也可以随意包括毫秒,以便包括前一天内的时间。)

创建可重用的

如果你发现自己经常需要这样做,你可以做一个扩展

代码语言:javascript
复制
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));
    }
}

并像这样使用它

代码语言:javascript
复制
 var contractsSignedBetween = contracts.SignedBetween(start, end);

这也可以在隔离中进行单元测试。

更灵活但更具体的

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

代码语言:javascript
复制
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));
    }
}

然后执行以下操作:

代码语言:javascript
复制
var contractsSignedBetween = contracts.Between(x => x.SignDate, start, end);
var contractsReleasedBetween = contracts.Between(x => x.ReleaseDate, start, end);

灵活而通用的

全力以赴去做泛型(尽管你不能把它变成一个扩展方法,因为它是泛型的):

代码语言:javascript
复制
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));
    }
}

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

代码语言:javascript
复制
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);

Making it IQueryable

因为LINQ To Entities不知道如何将方法转换为IQueryable,所以为了使其作为SQL语言工作,该方法需要转移到expression tree

代码语言:javascript
复制
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);
}

它仍然会像这样使用:

代码语言:javascript
复制
var contractsSignedBetween = contracts.Between(x => x.SignDate, start, end);

这也适用于DateTime之外的其他东西。希望这能有所帮助。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/50648265

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档