For brevity's sake in my code, i'd like to be able to do the following: having a collection, find the first element matching a lambda expression; if it exists, return the value of a property or function. If it doesn't exist, return null.
Updated examples w. classes
Let's have a collection of stuff
class Stuff
{
public int Id { get; set; }
public string Value { get; set; }
public DateTime? ExecutionTime { get; set; }
}
What I am aiming for is a way to return nicely when calling this
var list = new Stuff[] { new Stuff() { Id = 1, Value = "label", ExecutionTime = DateTime.Now } };
// would return the value of ExecutionTime for the element in the list
var ExistingTime = list.FirstOrDefault(s => s.Value.Contains("ab")).ExecutionTime;
// would return null
var NotExistingTime = list.FirstOrDefault(s => s.Value.Contains("zzz")).ExecutionTime;
Is it possible with some linq-syntax-fu or do I have to check explicitly for the return value before proceeding?
Original example w. strings
var stuff = {"I", "am", "many", "strings", "obviously"};
// would return "OBVIOUSLY"
var UpperValueOfAString = stuff.FirstOrDefault(s => s.contains("bvi")).ToUpper();
// would return null
var UpperValueOfAStringWannabe = stuff.FirstOrDefault(s => s.contains("unknown token")).ToUpper();
Comment: I shouldn't have used strings in my original example, since it slightly skews the question by centering it on the ToUpper method and the string class. Please consider the updated example
When you want a default value is returned if the result set contains no record, use SingleOrDefault. When you always want one record no matter what the result set contains, use First or FirstOrDefault. When you want a default value if the result set contains no record, use FirstOrDefault.
The major difference between First and FirstOrDefault is that First() will throw an exception if there is no result data for the supplied criteria whereas FirstOrDefault() will return the default value (null) if there is no result data.
FirstOrDefault<TSource>(IEnumerable<TSource>, Func<TSource,Boolean>, TSource) Returns the first element of the sequence that satisfies a condition, or a specified default value if no such element is found.
Use the FirstorDefault() method to return the first element of a sequence or a default value if element isn't there. List<double> val = new List<double> { }; Now, we cannot display the first element, since it is an empty collection.
Why not just do:
stuff.Where(s => s.contains("bvi"))
.Select(s => s.ToUpper())
.FirstOrDefault()
If you have a "non-default default", you can do:
stuff.Where(s => s.contains("bvi"))
.Select(s => s.ToUpper())
.DefaultIfEmpty("Something Else")
.First()
I like this as an extension method:
public static U SelectMaybe<T, U>(this T input, Func<T,U> func)
{
if (input != null) return func(input);
else return default(U);
}
And usage:
var UpperValueOfAString = stuff.FirstOrDefault(s => s.Contains("bvi")).SelectMaybe(x => x.ToUpper());
var UpperValueOfAStringWannabe = stuff.FirstOrDefault(s => s.Contains("unknown token")).SelectMaybe(x => x.ToUpper());
This will chain return the default value (null
in this case, but as is correct for that type), or call the relevant function and return that.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With