FirstOrDefault:除null之外的默认值

时间:2012-10-19 10:25:35

标签: .net linq

据我了解,在Linq中,方法FirstOrDefault()可以返回除{null}以外的值的Default值。我没有解决的是当查询结果中没有项目时,此(和类似)方法可以返回除null之外的其他类型的东西。是否有任何特定的方法可以设置它,以便如果没有特定查询的值,一些预定义的值将作为默认值返回?

13 个答案:

答案 0 :(得分:172)

  

据我了解,在Linq中,方法FirstOrDefault()可以返回除null之外的默认值。

没有。或者更确切地说,总是返回元素类型的默认值...它是空引用,可空值类型的空值,或非自然的“全零”值-nullable值类型。

  

是否有任何特定的方法可以设置它,以便如果没有特定查询的值,某些预定义的值将作为默认值返回?

对于参考类型,您只需使用:

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

当然,如果第一个值存在,会给你“其他默认值”,但是它是一个空引用...

答案 1 :(得分:55)

您可以使用DefaultIfEmpty,然后使用First

T customDefault = ...;
IEnumerable<T> mySequence = ...;
mySequence.DefaultIfEmpty(customDefault).First();

答案 2 :(得分:39)

一般情况,不仅仅是价值类型:

static class ExtensionsThatWillAppearOnEverything
{
    public static T IfDefaultGiveMe<T>(this T value, T alternate)
    {
        if (value.Equals(default(T))) return alternate;
        return value;
    }
}

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

同样,这无法确定是否序列中的任何内容,或者第一个值是否为默认值。

如果您关心这一点,您可以执行类似

的操作
static class ExtensionsThatWillAppearOnIEnumerables
{
    public static T FirstOr<T>(this IEnumerable<T> source, T alternate)
    {
        foreach(T t in source)
            return t;
        return alternate;
    }
}

并用作

var result = query.FirstOr(otherDefaultValue);

虽然正如牛先生指出的那样,.DefaultIfEmpty(...).First()可以做到这一点。

答案 3 :(得分:18)

来自FirstOrDefault

的文档
  

[返回]默认值(TSource),如果source为空;

来自default(T)的文档:

  

default关键字,对于引用类型将返回null,对于数值类型将返回零。对于结构体,它将返回初始化为struct或null的结构的每个成员,具体取决于它们是值还是引用类型。对于可空值类型,default返回一个System.Nullable,它像任何struct一样初始化。

因此,默认值可以为null或0,具体取决于类型是引用类型还是值类型,但您无法控制默认行为。

答案 4 :(得分:6)

复制@sloth的评论

而不是YourCollection.FirstOrDefault(),您可以使用YourCollection.DefaultIfEmpty(YourDefault).First()作为示例。

示例:

var viewModel = new CustomerDetailsViewModel
    {
            MainResidenceAddressSection = (MainResidenceAddressSection)addresses.DefaultIfEmpty(new MainResidenceAddressSection()).FirstOrDefault( o => o is MainResidenceAddressSection),
            RiskAddressSection = addresses.DefaultIfEmpty(new RiskAddressSection()).FirstOrDefault(o => !(o is MainResidenceAddressSection)),
    };

答案 5 :(得分:5)

你也可以这样做

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

这只使用linq - yipee!

答案 6 :(得分:4)

实际上,当我使用集合时,我使用两种方法来避免NullReferenceException

public class Foo
{
    public string Bar{get; set;}
}
void Main()
{
    var list = new List<Foo>();
    //before C# 6.0
    string barCSharp5 = list.DefaultIfEmpty(new Foo()).FirstOrDefault().Bar;
    //C# 6.0 or later
    var barCSharp6 = list.FirstOrDefault()?.Bar;
}

对于C#6.0或更高版本:

在执行成员访问Null-conditional Operators documentation

之前,使用?.?[来测试是否为null

实施例: var barCSharp6 = list.FirstOrDefault()?.Bar;

C#旧版本:

如果序列为空,请使用DefaultIfEmpty()检索默认值。MSDN Documentation

实施例: string barCSharp5 = list.DefaultIfEmpty(new Foo()).FirstOrDefault().Bar;

答案 7 :(得分:1)

我只是遇到了类似的情况,并且正在寻找一种解决方案,它允许我在每次需要时都不会在呼叫方处返回其他默认值。如果Linq不支持我们想要的东西,我们通常会做的是编写一个新的扩展来处理它。就是我做的。这是我想出的(虽未测试):

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);
    }
}

答案 8 :(得分:0)

而不是YourCollection.FirstOrDefault(),您可以使用YourCollection.DefaultIfEmpty(YourDefault).First()作为示例。

答案 9 :(得分:0)

我知道已经有一段时间了,但根据最流行的答案,我会加一句,但我想分享一下以下内容:

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();
    }
}

这使我可以像在遇到问题的我自己的示例中那样直接内联调用:

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

所以对我来说,我只想将默认解析器用于内联,我可以进行常规检查,然后传入一个函数,这样即使未使用该类也不会实例化,而是可以在需要时执行该函数! / p>

答案 10 :(得分:0)

如果项目列表不是可空类型,请考虑将其强制转换为可空类型,然后使用您想要的默认值 firstordefault 和 null 合并运算符。

示例:

static class MyClass
{
    public enum Level { Low, Medium, High }

    public static void Dosomething()
    {
        var levels = Enum.GetValues<Level>();

        var myLevel = levels.Select(x => (Level?)x).FirstOrDefault() ?? Level.Medium; // The Default value other than null
    }
}

答案 11 :(得分:0)

这对我们有用

int valueOrDefault = myList.Find(x => x.Id == 1)?.Value ?? -1;

答案 12 :(得分:-2)

使用DefaultIfEmpty()代替FirstOrDefault()