FirstOrDefault: 非空的默认值

据我所知,在 Linq 中,方法 FirstOrDefault()可以返回非 null 的 Default值。我还没有弄清楚的是,当查询结果中没有项时,这个(和类似的)方法可以返回除 null 以外的哪些内容。有没有什么特别的方法可以设置它,以便在特定查询没有值的情况下,将一些预定义的值作为默认值返回?

179840 次浏览

据我所知,在 Linq 中,FirstOrDefault ()方法可以返回非 null 的 Default 值。

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

有没有什么特别的方法可以设置它,以便在特定查询没有值的情况下,将一些预定义的值作为默认值返回?

对于引用类型,只需使用:

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

当然,如果第一个值存在,还有会给出“其他默认值”,但这是一个空引用..。

来自 FirstOrDefault的文档

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

来自 默认值(T)的文档:

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

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

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

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()也可以做到这一点。

你可以使用 默认为空后跟 首先:

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

你也可以这么做

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

这个只用林克-伊比!

从@Sloth 的评论中复制过来的

例如,您可以使用 YourCollection.DefaultIfEmpty(YourDefault).First()而不是 YourCollection.FirstOrDefault()

例如:

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

使用 DefaultIfEmpty()代替 FirstOrDefault()

例如,您可以使用 YourCollection.DefaultIfEmpty(YourDefault).First()而不是 YourCollection.FirstOrDefault()

实际上,在处理集合时,我使用了两种方法来避免使用 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或更高版本:

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

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

C # 旧版本:

如果序列为 empty.MSDN 文档,则使用 DefaultIfEmpty()检索默认值

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

我只是有一个类似的情况,并正在寻找一个解决方案,允许我返回一个替代的默认值,而不必在每次需要它的时候在调用方处理它。如果 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);
}
}

我知道已经有一段时间了,但是我还是要补充一下,基于最流行的答案,但是有一个小的扩展,我想分享下面的内容:

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

所以对我来说,我只是想要一个默认的解析器被内联使用,我可以做我通常的检查,然后传入一个函数,这样一个类就不会被实例化,即使没有使用,它是一个函数,当需要的时候执行!

如果条目列表不是可空类型,可以考虑强制转换为可空类型,那么 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
}
}

我们成功了

int valueOrDefault = myList.Find(x => x.Id == 1)?.Value ?? -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://learn.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 _