FirstOrDefault: Default value other than null

后端 未结 11 1151
-上瘾入骨i
-上瘾入骨i 2020-12-12 21:37

As I understand it, in Linq the method FirstOrDefault() can return a Default value of something other than null. What I haven\'t worked out is wha

相关标签:
11条回答
  • 2020-12-12 21:54

    From the documentation for FirstOrDefault

    [Returns] default(TSource) if source is empty;

    From the documentation for default(T):

    the default keyword, which will return null for reference types and zero for numeric value types. For structs, it will return each member of the struct initialized to zero or null depending on whether they are value or reference types. For nullable value types, default returns a System.Nullable, which is initialized like any struct.

    Therefore, the default value can be null or 0 depending on whether the type is a reference or value type, but you cannot control the default behaviour.

    0 讨论(0)
  • 2020-12-12 21:58

    As I understand it, in Linq the method FirstOrDefault() can return a Default value of something other than null.

    No. Or rather, it always returns the default value for the element type... which is either a null reference, the null value of a nullable value type, or the natural "all zeroes" value for a non-nullable value type.

    Is there any particular way that this can be set up so that if there is no value for a particular query some predefined value is returned as the default value?

    For reference types, you can just use:

    var result = query.FirstOrDefault() ?? otherDefaultValue;
    

    Of course this will also give you the "other default value" if the first value is present, but is a null reference...

    0 讨论(0)
  • 2020-12-12 21:58

    You can also do this

        Band[] objects = { new Band { Name = "Iron Maiden" } };
        first = objects.Where(o => o.Name == "Slayer")
            .DefaultIfEmpty(new Band { Name = "Black Sabbath" })
            .FirstOrDefault();   // returns "Black Sabbath" 
    

    This uses only linq - yipee!

    0 讨论(0)
  • 2020-12-12 22:04

    Instead of YourCollection.FirstOrDefault(), you could use YourCollection.DefaultIfEmpty(YourDefault).First() for example.

    0 讨论(0)
  • 2020-12-12 22:05

    I just had a similar situation and was looking for a solution that allows me to return an alternative default value without taking care of it at the caller side every time I need it. What we usually do in case Linq does not support what we want, is to write a new extension that takes care of it. That´s what I did. Here is what I came up with (not tested though):

    public static class EnumerableExtensions
    {
        public static T FirstOrDefault<T>(this IEnumerable<T> items, T defaultValue)
        {
            foreach (var item in items)
            {
                return item;
            }
            return defaultValue;
        }
    
        public static T FirstOrDefault<T>(this IEnumerable<T> items, Func<T, bool> predicate, T defaultValue)
        {
            return items.Where(predicate).FirstOrDefault(defaultValue);
        }
    
        public static T LastOrDefault<T>(this IEnumerable<T> items, T defaultValue)
        {
            return items.Reverse().FirstOrDefault(defaultValue);
        }
    
        public static T LastOrDefault<T>(this IEnumerable<T> items, Func<T, bool> predicate, T defaultValue)
        {
            return items.Where(predicate).LastOrDefault(defaultValue);
        }
    }
    
    0 讨论(0)
  • 2020-12-12 22:09

    I know its been a while but Ill add to this, based on the most popular answer but with a little extension Id like to share the below:

    static class ExtensionsThatWillAppearOnIEnumerables
    {
        public static T FirstOr<T>(this IEnumerable<T> source, Func<T, bool> predicate, Func<T> alternate)
        {
            var thing = source.FirstOrDefault(predicate);
            if (thing != null)
                return thing;
            return alternate();
        }
    }
    

    This allows me to call it inline as such with my own example I was having issues with:

    _controlDataResolvers.FirstOr(x => x.AppliesTo(item.Key), () => newDefaultResolver()).GetDataAsync(conn, item.ToList())
    

    So for me I just wanted a default resolver to be used inline, I can do my usual check and then pass in a function so a class isn't instantiated even if unused, its a function to execute when required instead!

    0 讨论(0)
提交回复
热议问题