173

据我了解,在 Linq 中,该方法FirstOrDefault()可以返回Defaultnull 以外的值。我没有弄清楚的是,当查询结果中没有项目时,这个(和类似的)方法可以返回除了 null 之外的什么东西。是否有任何特定的方法可以设置它,以便如果特定查询没有值,则某些预定义值将作为默认值返回?

4

14 回答 14

228

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

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

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

对于引用类型,您可以使用:

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

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

于 2012-10-19T10:30:43.873 回答
81

您可以使用DefaultIfEmpty后跟First

T customDefault = ...;
IEnumerable<T> mySequence = ...;
mySequence.DefaultIfEmpty(customDefault).First();
于 2014-06-03T07:34:06.370 回答
53

一般情况,不仅适用于值类型:

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

尽管正如 Steak 先生指出的那样,这也可以由.DefaultIfEmpty(...).First().

于 2012-10-19T10:34:48.507 回答
20

来自FirstOrDefault的文档

[返回] default(TSource) 如果源为空;

default(T)的文档中:

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

因此,根据类型是引用类型还是值类型,默认值可以为 null 或 0,但您无法控制默认行为。

于 2012-10-19T10:33:46.183 回答
7

从@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)),
    };
于 2015-01-16T10:51:44.497 回答
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!

于 2015-01-02T20:02:15.603 回答
5

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 或更高版本:

在执行成员访问之前使用?.or测试是否为 null空条件运算符文档?[

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

C# 旧版本:

DefaultIfEmpty()如果序列为空,则用于检索默认值。MSDN 文档

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

于 2017-05-09T19:11:50.820 回答
3

代替YourCollection.FirstOrDefault(),您可以使用YourCollection.DefaultIfEmpty(YourDefault).First()例如。

于 2017-04-06T08:53:27.553 回答
2

我刚刚遇到了类似的情况,并且正在寻找一种解决方案,该解决方案允许我在每次需要时都返回替代默认值,而无需在调用方处理它。如果 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);
    }
}
于 2017-08-11T07:39:00.020 回答
1

这对我们有用

int valueOrDefault = myList.Find(x => x.Id == 1)?.Value ?? -1;
于 2021-06-09T17:28:22.910 回答
1

.NET6 / c#10 解决方案

.NET6 / c#10 通过向 *OrDefault LINQ 方法添加新功能解决了这个问题。新的重载允许您指定在序列为空时使用的默认值。

public static TSource FirstOrDefault<TSource> (this System.Collections.Generic.IEnumerable<TSource> source, Func<TSource,bool> predicate, TSource defaultValue);

返回满足条件的序列的第一个元素,如果没有找到这样的元素,则返回指定的默认值。

这是一个例子;

var nums = new List<int> { 1, 2, 3 };
var target = 4;

var value = nums.FirstOrDefault(x => x == target, -1); // value becomes -1.

来源:https ://docs.microsoft.com/en-us/dotnet/api/system.linq.enumerable.firstordefault?view=net-6.0#System_Linq_Enumerable_FirstOrDefault__1_System_Collections_Generic_IEnumerable___0____0 _

于 2021-11-19T12:31:55.067 回答
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())

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

于 2018-10-31T14:22:11.913 回答
0

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

例子:

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
    }
}
于 2021-04-21T11:50:22.633 回答
-1

使用DefaultIfEmpty()而不是FirstOrDefault().

于 2016-06-16T10:04:27.513 回答