tags:

views:

1150

answers:

7

I have created the following LINQ query to demonstrate the problem:

string[] dateStrings = new string[] { "2009-07-20 13:00:00", "2009-07-20 16:00:00", "2009-07-20 09:00:00" };

DateTime dateValue = DateTime.MinValue;    

var results =
    from dateString in dateStrings
    where DateTime.TryParse(dateString, out dateValue)
    orderby dateValue descending
    select dateValue;

You'd expect the result to be a list of DateTimes in the reversed order:
20-7-2009 16:00:00
20-7-2009 13:00:00
20-7-2009 9:00:00

However all I get is this:
20-7-2009 9:00:00
20-7-2009 9:00:00
20-7-2009 9:00:00

What am I doing wrong? If you remove the orderby statement you'll notice a normal list of DateTime's.

+7  A: 

Where is dateValue declared? Observe that it can only hold one value.

Try this instead:

string[] dateStrings = new string[] { "2009-07-20 13:00:00",
  "2009-07-20 16:00:00", "2009-07-20 09:00:00" };

var results =
dateStrings.Select(s => 
{
  DateTime v;
  bool parsed = DateTime.TryParse(s, out v);
  return new {Parsed = parsed, Value = v };
})
.Where(x => x.Parsed)
.Select(x => x.Value)
.OrderByDescending(d => d);
David B
Sorry forget to type that in this example. I've updated the question. Without the orderby all is well.
Zyphrax
The orderby must eagerly resolve the query above that point before ordering may proceed. After all three records have been processed by your where clause, dateValue's value has obtain it's final value. Then orderby operates and sorts by that one value. Then select operates and projects that one value 3 times.
David B
Thnx! I can keep the query the same. However instead of making the orderby part of my Linq query, I can do the ordering just before setting it to my DataSource.
Zyphrax
+2  A: 

This is caused by deferred execution.

dateValue can only have one value, which will be the last value in dateStrings.

Read the following article on Closures to understand why:

http://diditwith.net/2007/09/25/LINQClosuresMayBeHazardousToYourHealth.aspx

Winston Smith
A: 

var results = from dateString in dateStrings where DateTime.TryParse(dateString, out dateValue) orderby dateValue descending select dateValue;

I believe that Linq is using delayed execution for the query, but not for the TryParse so you are getting only the last value of the Date from the TryParse when the query actually exectues.

Try moving parsing the dates into an array, then use the appropriate Linq construct to perform your logic against that.

automatic
Consider formatting the code next time.
chikak
+3  A: 

try the method

       var results =
            from dateString in dateStrings
            orderby (Convert.ToDateTime(dateString)) descending
            select (Convert.ToDateTime(dateString));
Edwin Tai
+1  A: 

The orderby clause requires that the where clause is executed first. The orderby is being applied after the where and it needs all it's results to perform the orderby operation. Hence dateValue will contain always the last where result.

Here's a solution:

        var results = from date in
                           (
                               from dateString in dateStrings
                               where DateTime.TryParse(dateString, out dateValue)
                               select dateValue
                           )
                      orderby date descending
                      select date;
bruno conde
A: 

I was reading the topics on the Start Page of Visual Studio 2008 and noticed a topic about the "let" keyword. This brought me to the solution below:

string[] dateStrings = new string[] { "2009-07-20 13:00:00", "2009-07-20 16:00:00", "2009-07-20 09:00:00" };

DateTime dateVal = DateTime.MinValue; 

var results =
from dateString in dateStrings
where DateTime.TryParse(dateString, out dateVal)
let dateValue = dateVal
orderby dateValue descending
select dateValue;

Notice that all I did was add the line and rename the variables accordingly:

let dateValue = dateVal

Quite simple and effective.

Zyphrax
A: 

my this query does not work can any body help me it very eargent

DateTime dt = DateTime.Now; List dateTimes = new List(); dateTimes.Add(dt); dateTimes.Add(dt); dateTimes.Add(dt); string str = dt.ToString(); DateTime myDateTime = DateTime.Parse(str);

        var query = from d in dateTimes
                    where d == myDateTime
                    select d;
        foreach (var result in query)
        {
            Console.WriteLine(result);
        }
        Console.Read();
Rahat Ali