据我了解,在 Linq 中,该方法FirstOrDefault()
可以返回Default
null 以外的值。我没有弄清楚的是,当查询结果中没有项目时,这个(和类似的)方法可以返回除了 null 之外的什么东西。是否有任何特定的方法可以设置它,以便如果特定查询没有值,则某些预定义值将作为默认值返回?
14 回答
据我了解,在 Linq 中,方法 FirstOrDefault() 可以返回 null 以外的默认值。
不。或者更确切地说,它总是返回元素类型的默认值......它可以是空引用、可空值类型的空值,或者不可空值类型的自然“全零”值。
是否有任何特定的方法可以设置它,以便如果特定查询没有值,则某些预定义值将作为默认值返回?
对于引用类型,您可以使用:
var result = query.FirstOrDefault() ?? otherDefaultValue;
当然,如果第一个值存在,这也会给你“其他默认值”,但它是一个空引用......
您可以使用DefaultIfEmpty后跟First:
T customDefault = ...;
IEnumerable<T> mySequence = ...;
mySequence.DefaultIfEmpty(customDefault).First();
一般情况,不仅适用于值类型:
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()
.
[返回] default(TSource) 如果源为空;
从default(T)的文档中:
默认关键字,对于引用类型将返回 null,对于数值类型将返回零。对于结构,它将返回结构的每个成员,根据它们是值类型还是引用类型,初始化为零或空。对于可为空的值类型,默认返回一个 System.Nullable,它像任何结构一样被初始化。
因此,根据类型是引用类型还是值类型,默认值可以为 null 或 0,但您无法控制默认行为。
从@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)),
};
你也可以这样做
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!
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;
代替YourCollection.FirstOrDefault()
,您可以使用YourCollection.DefaultIfEmpty(YourDefault).First()
例如。
我刚刚遇到了类似的情况,并且正在寻找一种解决方案,该解决方案允许我在每次需要时都返回替代默认值,而无需在调用方处理它。如果 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);
}
}
这对我们有用
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 ://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 _
我知道已经有一段时间了,但我会根据最流行的答案添加这一点,但有一点扩展我想分享以下内容:
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 和空合并运算符与您想要的任何默认值进行合并。
例子:
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
}
}
使用DefaultIfEmpty()
而不是FirstOrDefault()
.