Why is DateTime breaking my Linq code?

时间:2015-07-08 15:43:26

标签: c# .net linq datetime

I'm facing something really weird involving DateTime.Today and a Linq IEnumerable result. I need to change the DateTime property value of a list of objects after being queried with Linq and to set it to DateTime.Today. What is happening is that at the end of the foreach loop I find the list empty! How could it be? The same goes if I use DateTime.Parse. Anybody knows what's going on here? Here a small program to quick test it if you care to try:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication1
{
    //
    public class TblItem
    {
        public string Learn { get; set; }
        public string Explain { get; set; }
        public string Topic { get; set; }
        public DateTime NextRefresh { get; set; }
        public TblItem()
        {
        }
        public TblItem(string learn, string explain, string topicsid)
        {
            Learn = learn;
            Explain = explain;
            Topic = topicsid;
            NextRefresh = DateTime.Parse("2015-12-01");
        }
    }
    //
    class Program
    {
        static void Main(string[] args)
        {
            string topic = "DEUTSCH_EASY";
            //
            IEnumerable<TblItem> sqlresult = Table()
               .Where(c => ((c.Topic == topic) && (c.NextRefresh > DateTime.Today)))
               .OrderBy(c => c.NextRefresh);
            DebugLog("sqlresult.count(start):" + sqlresult.Count());
            DebugLog("");
            foreach (TblItem item in sqlresult) {
                item.NextRefresh = DateTime.Today;
                DebugLog("sqlresult.count(while):" + sqlresult.Count());
            }
            DebugLog("");
            DebugLog("sqlresult.count(after):" + sqlresult.Count());
        }
        public static List <TblItem> Table()
        {
            string topicSid = "DEUTSCH_EASY";
            return (new TblItem[]{
                new TblItem ("spass", "divertimento", topicSid),
                new TblItem ("prost!", "salute!", topicSid),
                new TblItem ("ich hatte gerne", "mi piacerebbe", topicSid),
                new TblItem ("bitte", "prego", topicSid),
                new TblItem ("das Regen", "la pioggia", topicSid),
            }).ToList<TblItem>();
        }

        public static void DebugLog(string s)
        {
            Console.WriteLine(">>>>"+s);
        }
    }
}

4 个答案:

答案 0 :(得分:3)

You need to call .ToList() after you do the initial LINQ query. The Count() is processing the query each time and each time it does it the result is different as you have just changed the NextRefresh property.

IEnumerable<TblItem> sqlresult = Table()
               .Where(c => ((c.Topic == topic) && (c.NextRefresh > DateTime.Today)))
               .OrderBy(c => c.NextRefresh).ToList();

答案 1 :(得分:2)

使用ToList()方法将IOrderedEnumerable转换为IEnumerable类型。

Table()
    .Where(c => ((c.Topic == topic) && (c.NextRefresh > DateTime.Today)))
               .OrderBy(c => c.NextRefresh).ToList()

答案 2 :(得分:1)

Table()
           .Where(c => ((c.Topic == topic) && (c.NextRefresh > DateTime.Today)))
           .OrderBy(c => c.NextRefresh)

is not a list is only a LINQ query that is runned and evaluated when you call Count().

Table()
           .Where(c => ((c.Topic == topic) && (c.NextRefresh > DateTime.Today)))
           .OrderBy(c => c.NextRefresh).ToList()

is a list

EDIT

So, in the foreach loop you change NextRefresh and when you evaluate the LINQ query again the result of the LINQ query changes.

答案 3 :(得分:1)

Well you set: item.NextRefresh = DateTime.Today but query is c.NextRefresh > DateTime.Today, so you no entry matches the condition. The trick is that sqlresult is not solidified container, it is just definition of query which is rerun on every GetEnumerator (every foreach, ToList etc).