结构集合的 FirstOrDefault() 结果?

Posted

技术标签:

【中文标题】结构集合的 FirstOrDefault() 结果?【英文标题】:FirstOrDefault() result of a struct collection? 【发布时间】:2013-03-14 10:46:39 【问题描述】:

所以我收集了structs 的集合(它实际上是一个 WCF 数据合同,但我认为这与这里无关)。

List<OptionalExtra> OptionalExtras;

OptionalExtrastruct

public partial struct OptionalExtra

现在我正在运行以下语句:

OptionalExtra multiOptExtra = OptionalExtras.Where(w => w.Code == optExtra.Code).FirstOrDefault();
if (multiOptExtra != null)



现在这不会编译:

运算符 != 不能应用于 OptionalExtra 类型的操作数 和'&lt;null&gt;'

经过一番谷歌搜索后,我意识到这是因为 OptionalExtrastruct。除非定义为可空类型,否则我认为哪个不可为空?

所以我的问题是,如果我的where 语句没有返回任何结果,那么FirstOrDefault 调用的结果是什么?会不会抛出异常?

顺便说一句,这不应该永远不会发生,但总比抱歉更安全。

【问题讨论】:

【参考方案1】:

如果您的集合为空,FirstOrDefault 将返回 default(OptionalExtras)。结构的默认值是其所有值依次默认初始化的结构(即零、空等)。

如果您假设会有一个元素并且您的代码不适用于空集合,请改用First(),因为当您的集合为空时会引发异常。快速失败通常比返回错误数据要好。

如果你不能假设会有一个元素,又不能处理结构体默认初始化,你可以将集合中的结构体设为nullable value type,例如如下:

OptionalExtras
    .Where(w => w.Code == optExtra.Code)
    .Cast<OptionalExtra?>()
    .FirstOrDefault();

这样,即使是结构,您也可以获得空返回。这里的关键思想是扩展可能值集以包含OptionalExtra 以外的其他内容,以允许检测空列表。如果您不喜欢可空值,您可以改用 Maybe&lt;&gt; 实现(不是 .NET 内置),或使用空列表或单例列表(例如 .Take(1).ToArray()。但是,可空结构可能是您的最佳选择.

TL;DR;

如果序列为空,.FirstOrDefault&lt;T&gt;() 返回default(T) 如果您认为列表不为空,请改用.First()。 当您不能假定列表非空时,转换为可为空,然后使用 .FirstOrDefault&lt;T&gt;()

【讨论】:

【参考方案2】:

正如其他人所说,当没有元素匹配时,您的代码结果将是:

default( OptionalExtra )

如果您希望返回 null,您可以将列表转换为 OptionalExtra?

OptionalExtra? multiOptExtra = OptionalExtras.Cast<OptionalExtra?>().Where( ...

然后您可以测试null

【讨论】:

我无法控制该结构,它是来自第三方的 WCF DataContract。还是谢谢 您不需要控制结构 - 您只是暂时将 List&lt;OptionalExtra&gt; 的元素转换为有效的 LINQ 的 OptionalExtra? 我想我更喜欢@EamonNerbonne 的回答。如果它不存在,我宁愿它失败,而不是花费权力铸造。在这种情况下,失败应该是非常罕见的,因此最好针对最可能的情况进行优化。就像我说的,无论如何,ta +1 当您知道列表是否为非空时,这是要走的路。【参考方案3】:

如果default(OptionExtra) 仍然是有效值,最好将您的代码更改为此

var results = OptionalExtras.Where(w => w.Code == optExtra.Code).Take(1).ToList();
if (results.Any()) 
   multiOptExtra = results[0]

【讨论】:

首选ToArray 而不是ToList - 数组更快,使用更少的内存,更严格(即很少有意外错误),并且语法更短。如果您使用 LINQ,几乎没有理由使用 List&lt;&gt; @EamonNerbonne 除非您想将项目添加到结果中。 @EamonNerbonne 这似乎是夸大其词(请参阅***.com/a/1106012/83171)和微优化的味道。 ToArrayToList 方法之间的性能差异是微不足道的,List&lt;T&gt; 提供了更多功能,使用语法相似并且实际上比数组更安全,因为它们的协方差被破坏,允许像 var x = new string[1]; ((object[])x)[0] = 1; 这样的代码。在这种情况下,当您有许多单元素数组时,这是有道理的,但我不会说“几乎从不将 List 与 LINQ 一起使用”是正确的。 性能差异不在.ToList.ToArray;但在每次后续使用该集合时(以及 GC 对象计数加倍)。其次,如果你正在铸造,你总是会导致异常(但你所说的可能会导致问题,不可否认)。然而,在实践中,List.Add 的存在更可能导致问题,List.Reverse 的存在隐含地替换了 LINQ 的Reverse 我明白你的意思,并且我同意数组的性能更高 - 它们被用作许多其他集合的基础集合。当然List&lt;&gt; 有它的问题。我仍然不同意您的说法,即几乎没有理由将它们与 LINQ 一起使用。作为旁注,我对.ToArray().ToList() 方法进行了微基准测试,在我的笔记本电脑上,.ToArray() 方法似乎触发了更多的垃圾回收。你可以自己试试 - gist.github.com/vas6ili/5164182.【参考方案4】:

结果将是你的结构的默认值,例如default(OptionalExtras).

而对于引用类型,默认值为null

【讨论】:

【参考方案5】:

它为您的结构提供默认值,如下所示

int[] numbers =  ;
int first = numbers.FirstOrDefault();
Console.WriteLine(first);//this print 0 as output 

其他处理选项是使用默认值,如下所示

List<int> months = new List<int>  ;
// Setting the default value to 1 by using DefaultIfEmpty() in the query. 
int firstMonth2 = months.DefaultIfEmpty(1).First();
Console.WriteLine("The value of the firstMonth2 variable is 0", firstMonth2);

【讨论】:

【参考方案6】:

如果要检查 null,请使用 System.Nullable 集合:

var OptionalExtras = new List<OptionalExtra?>();
/* Add some values */
var extras = OptionalExtras.FirstOrDefault(oe => oe.Value.Code == "code");
if (extras != null)

    Console.WriteLine(extras.Value.Code);

请注意,您必须使用 Value 来访问元素。

【讨论】:

但结构永远不能为空? 那个?表示法将结构转换为 Nullable 对象,因此是 myStructVar.Value 要求。不确定这样做是否是一个好的设计,但它很简单。 但这并不能回答问题。我问一个结构(值类型)的 FirstOrDefault 的结果是什么。你说如果我使我的结构可以为空(将其更改为引用类型),我将得到一个空值。这不是我要求的。 这不是对您问题的直接回答,但由于您已批准(且正确)答案,我添加了一个案例,您可以安全检查您的 LINQ 查询是否为空。【参考方案7】:

假设 Code 是我回答的目的的字符串,您应该能够测试该值的默认值。

OptionalExtra multiOptExtra = OptionalExtras.Where(w => w.Code == optExtra.Code).FirstOrDefault();
if (multiOptExtra.Code != null)



【讨论】:

如果Where 返回null multiOptExtra.Code != null 会抛出一个nullReferenceExcepetion,这实际上也不能回答这个问题,这就是firstordefault() 返回一个struct收藏。 @Liam:不会返回 Null。我只是采用了您的代码的变体,运行它,FirstOrDefault 返回了一个不为空的空结构。见:harriergroup.com/mll/imagesonweb/struct.png 嗯,实际上你的权利......我忘了这是一个结构。仍然没有回答我的问题。

以上是关于结构集合的 FirstOrDefault() 结果?的主要内容,如果未能解决你的问题,请参考以下文章

根据结构列表上的条件查找 FirstOrDefault

FirstOrDefault:除 null 以外的默认值

我如何处理 .FirstOrDefault 方法?

何时使用 .First 以及何时将 .FirstOrDefault 与 LINQ 一起使用?

NHibernate 3.0:没有使用QueryOver的FirstOrDefault()?

dotnet C# 多线程集合的 Linq 获取值同时写入集合将会抛出异常