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
)