【发布时间】:2011-09-15 18:52:40
【问题描述】:
假设我有以下代码:
public class Deck {
[NotNull IEnumerable<Card> cards = new List<Cards>();
[NotNull] public IEnumerable<Card> Cards { get; private set; }
public void AddCard([NotNull] Card card) { cards.Add(card); }
...
}
public static IEnumerable<int> CardValuesOfColor(this Deck deck, Color color)
{
var cards = deck.Cards;
return cards.Where(c => c.Color == color).Select(c => c.Value);
}
在运行 ReSharper 代码检查时,它正确地抱怨“deck.Cards”处可能出现 System.NullReferenceException,因为此代码中的 deck 可能为 null。这是个好东西,我想保留它。
但是,它也会抱怨 c.Color 和 c.Value,因为它感觉 c 在这些情况下可能为空。这似乎太过分了,而且没有什么帮助。
我可以通过将 lambda 从“c.Color == color”更改为“c != null && c.Color == color”来“修复”c.Color,尽管这对于每个 Where 子句来说都很痛苦,尤其是当我从类设计中知道 deck.Cards 不会包含空值时。
这并不能解决 c.Value 问题,尽管很明显在修改了“where”子句之后,c 不可能为空。
似乎没有办法在不触发此警告的情况下编写 Select(...)、OrderBy(...) 等子句。
当我打开在我的项目中寻找可能的空引用时,我得到了数百个带有“问题”的文件。我们广泛使用 LINQ,这些“问题”中有很多(但不是全部)是虚假的,但不可能关闭。
我的选择似乎是关闭可能的空引用检查或在每次使用 LINQ 的 Select() 扩展时添加注释。这两种方法都不适合我。
有没有第三种选择可以解决这个问题?
【问题讨论】:
-
我知道一个可枚举可以包含空项。在这种情况下,我知道它不会,通过类的构造。我首选的解决方案是有办法告诉 ReSharper,这样它就会知道。
-
如何向“cards.Select(c => c.Value)”添加空检查? ReSharper 想要将整个语句(包括cards.Select() 调用本身)包装在一个 if 中,这根本行不通。
-
Alt+Enter 和 c (c|.Color) 之后的光标为您提供了一个上下文操作来生成正确的空检查
-
不,它没有。至少不在 ReSharper 5.1 中。 Alt+Enter at c|.Color 提供了添加一个空检查,但它将整个 return 语句包装在一个 if (c != null) {...} 中,它 (a) 尝试在其范围之外访问 c , 和 (b) 添加不返回值的可能执行路径。
-
那么有充分的理由升级到 v6 )