代码之家  ›  专栏  ›  技术社区  ›  casillas

筛选列表中的可空项-linq

  •  0
  • casillas  · 技术社区  · 6 年前

    我有以下列表项要显示。我可以想象下面的小列表,可能是几百行。 StartDate 而且 EndDate 可以是 nullable 如果 结束日期 为空,表示课程仍然开放。

    CourseId    ClassName    StartDate   EndDate      isActiveinDB
    --------    ---------    ---------   -------      ------------
    12321       Math         08-25-2017  12-02-2017      Y
    32342       Math         08-25-2017  12-02-2017      N
    25325       Math         01-25-2018     -            Y
    

    如果我使用以下方法通过了今天(2018年6月6日)的考试,它将返回所有课程,而不是仅返回最后一门未过期且未开放的课程(数学25325)。 isActiveinDB .

    我想知道下面的实现有什么不正确的地方。

    public List<Courses> GetClassesByDate( DateTime date, List<Courses> allCourses)
    {
       List<Courses> courses  = allCourses.Where( x => x.StartDate.HasValue ? x.StartDate <= date : true 
                                && x.EndDate.HasValue ? x.EndDate.Value >= date : true 
                                && x.isActiveinDB.Equals("Y")).ToList();
       return courses;
    }
    

    感谢@davidg,实现如下 link

    2 回复  |  直到 6 年前
        1
  •  5
  •   xanatos    6 年前

    尝试(如果) StartDate 可以为空,正如您所说的):

    List<Courses> courses  = allCourses.Where( x =>  
                            (x.StartDate.HasValue ? x.StartDate.Value <= date : true)
                            && (x.EndDate.HasValue ? x.EndDate.Value >= date : true) 
                            && x.isActiveinDB.Equals("Y")).ToList();
    

    你看到了 () 我加了?我觉得你所做的其实是

    x.EndDate.HasValue ? x.EndDate.Value : (true && isActiveinDB.Equals("Y"))
    

    你明白了吗?这个 true 不是单个值,而是子表达式 true && isActiveinDB.Equals("Y")

        2
  •  1
  •   Yas Ikeda    6 年前

    运算符按顺序在表达式中求值。解释如下 https://msdn.microsoft.com/en-us/library/2bxt6kc4.aspx . 有一个表按表的顺序显示运算符。

    从列表中可以看到,条件表达式(?):)的优先级相当低。所以,我建议在条件表达式周围的任何时候都加上括号,这样就可以避免发生这种意外。

    以下代码是用于验证运算符顺序的nunit测试代码。希望唱片课和你的案子很接近。

    执行此测试时,第一个断言通过,但第二个断言失败。它证明了括号在这种表达式中的作用。

    [TestFixture]
    public class SyntaxTest
    {
        public class Record
        {
            public string Id;
            public DateTime? StartDate;
            public DateTime? EndDate;
            public string isActiveinDB;
        }
    
        [TestCase]
        public void TestConditionalSyntax()
        {
            var list = new List<Record>
            {
                new Record { Id = "0000", StartDate = DateTime.Parse("2018-01-01"), EndDate = DateTime.Parse("2018-06-01"), isActiveinDB = "Y" },
                new Record { Id = "0001", StartDate = DateTime.Parse("2018-01-01"), EndDate = DateTime.Parse("2018-09-01"), isActiveinDB = "N" },
                new Record { Id = "0002", StartDate = DateTime.Parse("2018-01-01"), EndDate = DateTime.Parse("2018-08-01"), isActiveinDB = "Y" },
                new Record { Id = "0003", StartDate = DateTime.Parse("2018-01-01"), EndDate = null, isActiveinDB = "Y" },
                new Record { Id = "0004", StartDate = DateTime.Parse("2018-08-01"), EndDate = null, isActiveinDB = "Y" },
                new Record { Id = "0005", StartDate = null, EndDate = DateTime.Parse("2018-06-01"), isActiveinDB = "Y" },
                new Record { Id = "0006", StartDate = null, EndDate = DateTime.Parse("2018-08-01"), isActiveinDB = "Y" },
            };
    
            var date = DateTime.Parse("2018-06-15");
            var result1 = list.Where(x => ( x.StartDate.HasValue ? x.StartDate <= date : true )
                                     && ( x.EndDate.HasValue ? x.EndDate >= date : true )
                                     && x.isActiveinDB.Equals("Y")).ToList();
            Assert.That(result1.Count, Is.EqualTo(3));
    
            var result2 = list.Where(x => x.StartDate.HasValue ? x.StartDate <= date : true
                                     && x.EndDate.HasValue ? x.EndDate >= date : true
                                     && x.isActiveinDB.Equals("Y")).ToList();
            Assert.That(result2.Count, Is.EqualTo(3));
        }
    }