-1

Based on my answered question here(C# Sort / Order a textBox with given Values) I have another question. (Thanks to JohnG) I have now written my code to use with values the system gived to me. I don't now why, but the orderby-clause is completly ignored. The result with OrderBy and OrderByDescending is the same and nothing is sort / ordered.

Here the code which is created values by hand and working:

string[] test1 = { "2021-12-08", "2020-04-12", "2021-06-15", "2022-11-28", "2019-01-12" };
IEnumerable<string> query1 = test1.OrderBy(i => i.ToString());
foreach (string r in query1)
{
    textBox3.Text += r.ToString() + "\r\n";
}

Result:

2019-01-12
2020-04-12
2021-06-15
2021-12-08
2022-11-28

And here is the problem-code

var searcher = new ManagementObjectSearcher("SELECT * FROM Win32_QuickFixEngineering");
var managementObjectCollection = searcher.Get();

foreach (ManagementObject queryObj in searcher.Get())
{
    string stringDate = queryObj["InstalledOn"].ToString();
    string format = "M/d/yyyy";
    CultureInfo provider = CultureInfo.InvariantCulture;
    DateTimeOffset result = new DateTimeOffset();
    result = DateTimeOffset.ParseExact(stringDate, format, provider, DateTimeStyles.AssumeUniversal);
    systemLastWindowsUpdate = result.ToString("yyyy-MM-dd");

    string[] test = { systemLastWindowsUpdate };
    IEnumerable<string> query = test.OrderByDescending(g => g.ToString());

    //MessageBox.Show(query.ToString()); // Gives System.Linq.OrderedEnumerable`2[System.String,System.String]
    foreach (string t in query)
    {
        textBox2.Text += t.ToString() + "\r\n";
    }
}

Result:

2021-07-19
2020-09-27
2020-09-27
2020-09-27
2021-03-01
2020-11-17
2020-11-17
2021-03-15
2020-12-14
2021-01-18
2021-07-19
2021-07-19

Hope anyone have an idea. I don't need a perfect and efficient code. I'm learning and it's absolutely OK with working code.

  • 2
    If what you claim were true millions of developers would have noticed 19 years ago. Either you iterate over the wrong string or you're looking at the wrong rows. Clear the textbox before appending new lines. In the code you posted `test` contains only a single value, `systemLastWindowsUpdate`. Your code is trying to sort that single value, while iterating over the *original* results – Panagiotis Kanavos Aug 13 '21 at 13:36

2 Answers2

2

You are applying OrderByDescending to an array containing a single element string[] test = { systemLastWindowsUpdate };.

Instead, append the formatted dates to a list and then sort the list. Sorting must be done after the foreach loop, i.e., after all the dates have been processed, to the entire list of dates:

var searcher = new ManagementObjectSearcher(
    "SELECT * FROM Win32_QuickFixEngineering");
var dates = new List<string>();
foreach (ManagementObject queryObj in searcher.Get())
{
    string stringDate = queryObj["InstalledOn"].ToString();
    string format = "M/d/yyyy";
    CultureInfo provider = CultureInfo.InvariantCulture;
    DateTimeOffset result = new DateTimeOffset();
    result = DateTimeOffset.ParseExact(
        stringDate, format, provider, DateTimeStyles.AssumeUniversal);
    systemLastWindowsUpdate = result.ToString("yyyy-MM-dd");

    dates.Add(systemLastWindowsUpdate);
}

// Now the list contains all the dates, and you can sort it:
IEnumerable<string> query = dates.OrderByDescending(s => s);
textBox2.Text = String.Join("\r\n", query);

Also, do not append text repeatedly to a TextBox in a loop, because of the overhead involved. The TextBox might raise events each time, thus making the loop very slow. I use String.Join to create a string before assigning the final result to the TextBox once.


You can also use the Language Integrated Query (LINQ) to do the conversion and sorting in one go with no loop and no list:

var searcher = new ManagementObjectSearcher(
    "SELECT * FROM Win32_QuickFixEngineering");

string format = "M/d/yyyy";
CultureInfo provider = CultureInfo.InvariantCulture;

var query = searcher.Get()
    .Select(queryObj => DateTimeOffset.ParseExact(
        queryObj["InstalledOn"].ToString(),
        format, provider, DateTimeStyles.AssumeUniversal
     ).ToString("yyyy-MM-dd"))
    .OrderByDescending(s => s);

textBox2.Text = String.Join("\r\n", query);

See also: Query Syntax and Method Syntax in LINQ (C#)

Olivier Jacot-Descombes
  • 104,806
  • 13
  • 138
  • 188
  • 1
    The textbox will not refresh itself until this code yields back to the message loop, but it will create extra window events for the OS to deal with, and there is extra code in the `.Text` setter we can avoid, such that using `.Join()` before assigning to the textbox is definitely the better option. – Joel Coehoorn Aug 13 '21 at 14:11
  • 1
    Also: I applaud you for not falling into the trap I see so often of calling .ToList() when you don't need to – Joel Coehoorn Aug 13 '21 at 14:19
  • @JoelCoehoorn, yes, the TextBox will invalidate itself, eventually leading to a repaint. – Olivier Jacot-Descombes Aug 13 '21 at 14:21
1

Try this:

var searcher = new ManagementObjectSearcher("SELECT * FROM Win32_QuickFixEngineering");
var managementObjectCollection = searcher.Get();
var sorted = managementObjectCollection.
     Select(o => DateTimeOffset.ParseExact(o["InstalledOn"], "M/d/yyyy", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal)).
     OrderByDescending(o => o);

textBox2.Text += string.Join("\n", sorted.Select(d => d.ToString("yyyy-MM-dd"));

The problem was the test array was rebuilt to hold only a single element inside every single iteration of the loop. After we resolve this we can further improve things by letting the sort happen on date objects, which will tend to be faster than sorting on strings, and by building the final string in memory before adding it to the textbox. In addition to improving performance, these changes also reduce the amount of code we need.

Joel Coehoorn
  • 399,467
  • 113
  • 570
  • 794