Can I use a TryParse inside Linq Comparable?

Everyone who uses C#7 or newer scroll to the bottom, everyone else can read the original answer:


Yes, you can, if you pass the correct parameters to int.TryParse. Both overloads take the int as out-parameter and initialize it inside with the parsed value. So like this:

int note;
Documenti = Documenti
    .OrderBy(o => string.IsNullOrEmpty(o.Note))
    .ThenBy(o => Int32.TryParse(o.Note, out note)) 
    .ToList();

The clean approach is using a method that parses to int and returns int? if unparseable:

public static int? TryGetInt(this string item)
{
    int i;
    bool success = int.TryParse(item, out i);
    return success ? (int?)i : (int?)null;
}

Now you can use this query(OrderByDescending because true is "greater" than false):

Documenti = Documenti.OrderByDescending(d => d.Note.TryGetInt().HasValue).ToList();

It's cleaner than using a local variable that is used in int.TryParse as out parameter.

Eric Lippert commented another answer of me where he gives an example when it might hurt:

C# LINQ: How is string("[1, 2, 3]") parsed as an array?


Update, this has changed with C#7. Now you can declare the variable directly where you use out parameters:

Documenti = Documenti
.OrderBy(o => string.IsNullOrEmpty(o.Note))
.ThenBy(o => Int32.TryParse(o.Note, out int note)) 
.ToList();

Documenti = Documenti.OrderBy(o =>
        int.TryParse(o.Note, out int val)
            ? val
            : int.MaxValue /* or int.MinValue */
    ).ToList();

Note: Toggling between int.MaxValue and int.MinValue will either put the empty values at the front or the end of the list.

EDIT: 2020-02-07 Using an inline out variable which was introduced in C# 7


You can actually put much more complex logic in the lambda expression:

List<Doc> Documenti = new List<Doc>() {
        new Doc(""),
        new Doc("1"),
        new Doc("-4"),
        new Doc(null) };

Documenti = Documenti.OrderBy(o => string.IsNullOrEmpty(o.Note)).ThenBy(o => 
{
    int result;
    if (Int32.TryParse(o.Note, out result))
    {
        return result;
    } else {
        return Int32.MaxValue;
    }
}).ToList();

foreach (var item in Documenti)
{
    Console.WriteLine(item.Note ?? "null");
    // Order returned: -4, 1, <empty string>, null
}

Remember, o => Int32.TryParse(...) is just a shorthand for creating a delegate that just takes in o as a parameter and returns Int32.TryParse(...). You can make it do whatever you want as long as it still is a syntacticly correct method with the correct signature (ex, all code paths return an int)