Linq扩展方法

时间:2013-01-08 17:55:07

标签: c# linq linq-to-sql extension-methods

我经常需要按publishStartpublishEndactive

等字段限制SELECT

我在几个不同的表格中有这些字段。因此,只应选择

a: active == true;
b: publishStart < now;
c: publishEnd > now;

所以,例如:

db.myTable.SingleOrDefault(a => (a.ID == _theID 
          //now the active and start-end part:            
                      && ((a.publishEnd > DateTime.Now) || (a.publishEnd == null))
                      && ((a.publishStart <= DateTime.Now) || (a.publishStart == null))
                      && a.active == true));

这有点冗长,所以我想知道是否有可能创建一个(扩展名?) - 方法,如:

db.myTable.SingleOrDefault(a => (a.ID == _theID).isActive()

isActive()提供上述代码段的3行。

我怎么能这样做? 有没有更好的方法来清理代码?

3 个答案:

答案 0 :(得分:13)

要定义扩展,您需要一个静态类。您可以将它放在您喜欢的任何名称空间中,只需记住将其包含在您的使用中。

public static class Extensions
{
    public static IQueryable<T> Active<T>(this IQueryable<T> source)
        where T : YourEntityType
    {
        return source.Where(a => ((a.publishEnd > DateTime.Now) || (a.publishEnd == null))
                          && ((a.publishStart <= DateTime.Now) || (a.publishStart == null))
                          && a.active == true);
    }
}

请注意YourEntityType。这用于确保方法知道publishStartpublishEndactive的存在。这应该是实现这些字段的类或定义它们的契约(接口)。

然后你会这样称呼它:

var item = db.myTable.Active().SingleOrDefault(...);

有关扩展方法的更多信息,请访问:http://msdn.microsoft.com/en-us/library/bb383977.aspx


由于有很多评论突然出现,我将在这里添加一个关于界面解决方案的简要说明......

在问题中是否存在三个过滤字段的常见实现或定义它们的接口尚不清楚。如果没有,为了使上述工作,您将不会:

  1. 实现这些字段的基类。在这种情况下,您可以将YourEntityType替换为YourBaseEntityType
  2. 用于定义字段的界面。在这种情况下,您需要让您的类实现字段。如果类是自动生成的(例如,首先是实体框架模型/ db),那么您可以实现部分类,让它们实现接口。在这种情况下,您可以将YourEntityType替换为IYourContract

答案 1 :(得分:4)

只需定义一个这样的界面

public interface IHaveAActivityPeriod 
{
    Boolean active { get; }

    DateTime? publishStart { get; }

    DateTime? publishEnd { get; }
} 

并将其添加到所有相关课程中。

public class Foo : IHaveAActivityPeriod { [...] }

public class Bar : IHaveAActivityPeriod { [...] }

现在您可以使用此扩展方法

public static class Extensions
{
    public static Boolean IsActive(this IHaveAActivityPeriod item)
    {
        var now = DateTime.Now;

        return item.active &&
               (item.publishStart <= now)
               (!item.publishEnd.HasValue || (item.publishEnd > now));
    }
}

在每个实施IHaveAActivityPeriod的实例上。

var foo = new Foo();

var isFooActive = foo.IsActive();

var bar = new Bar();

var isBarActive = bar.IsActive();

我完全错过了构建扩展方法的可能性,该扩展方法执行序列的过滤而不是一次查看单个实体。只需将flem的答案中的扩展方法作为类型约束在接口中抛出。

public static class Extensions
{
    public IQueryable<T> IsActive<T>(this IQueryable<T> sequence)
        where T : IHaveAActivityPeriod
    {
        return source.Where(item =>
                   item.active &&
                   (item.publishStart <= now) &&
                   (!item.publishEnd.HasValue || (item.publishEnd > now));

    }
}

答案 2 :(得分:3)

public static class Extensions
{
    public static IEnumerable<MyClass> isActive(this IEnumerable<MyClass> list)
    {
        return list.Where(a =>  
               ((a.publishEnd > DateTime.Now) || (a.publishEnd == null))
                 && ((a.publishStart <= DateTime.Now) || (a.publishStart == null))
                 && a.active == true);
    }
}