C#代码简化查询:Null容器和Foreach循环

我经常有类似这样的代码:

if (itm != null) { foreach (type x in itm.subItems()) { //dostuff } } //do more stuff 

//do more stuff省略//do more stuff情况下,很容易避免额外的foreach循环。 通过使用适当的命令来扩展范围(取决于正在发生的事情,这通常意味着return语句或continue statement )。

这种类型的东西往往导致箭头代码。 我目前有几种方法可以解决这个问题:

  • 使用像itm = itm == null ? itm.subItems() : emptyArray这样的代码itm = itm == null ? itm.subItems() : emptyArray itm = itm == null ? itm.subItems() : emptyArray
  • 允许箭头代码
  • 使用goto
  • 使用邪恶的范围黑客(包括整个事物,如果声明,在范围内,然后突破它)。 在我看来,邪恶的范围黑客基本上等同于goto除了丑陋和更难阅读,所以我不认为这是一个有效的解决方案。
  • 将一些块重构为新方法。 实际上有一些情况下这可能一个很好的解决方案,但大多数情况下它并不合适,因为空引用主要是来自MS函数的错误条件。

任何人都愿意回答什么方法更合适?

如果您使用的是C#3,则可以随时编写扩展方法:

 public static IEnumerable SafeSubItems(this ItemType item) { return item == null ? Enumerable.Empty : source.SubItems(); } 

然后写下:

 foreach (SubItem x in itm.SafeSubItems()) { // do stuff } // do more stuff 

关键是扩展方法甚至可以调用“on”null引用。

什么是好的将是一个“null-safe dereferencing”运算符,所以我们可以写:

 // Not valid C# code! foreach (SubItem x in itm?.SubItems() ?? Enumerable.Empty()) { } 

或者只是在IEnumerable上定义一个EmptyIfNull扩展方法并使用

 // Not valid C# code! foreach (SubItem x in (itm?.SubItems()).EmptyIfNull()) { } 

您可以使用Coalesce运算符(编码为双重问号,??,。net 2向上)。 这将返回值列表中的第一个非空值,因此在此代码段中…

 MyClass o1 = null; MyClass o2 = new MyClass (); MyClass o3 = null; return o1 ?? o2 ?? o3; 

…… o2将被退回。

因此,您可以将原始代码示例重新编码为

 foreach (type x in (itm ?? emptyArray).subItems()) { //dostuff } //do more stuff 

但是,我个人不介意嵌套。 它立即清楚发生了什么。 我发现Coalesce操作员有点难以阅读,为了清晰起见,这个小窝是一个很小的代价。

我喜欢较少的嵌套,对我来说它看起来更好。 没有转到请:)

我保持方法简短,所以通常是这种情况的回报。

 if (itm == null) return; foreach (type x in itm.subItems()) { //dostuff } 

如果需要更多的东西,是简单的陈述,可以在foreach之前完成,你可以:

 if (itm == null) { //do more stuff return; } foreach (type x in itm.subItems()) { //dostuff } 

如果上述情况并非如此,那么该方法可能太长而且其中一些方法无论如何都会被移走。 大概:

 if( itm != null ) SomeActionOnSubItems(itm.subItems); // do more stuff (can be some method calls depending on level of abstraction). 

就个人而言,我可能会按照您的方式离开结构。

第一个选项(itm = itm == null?itm.subItems():emptyArray)似乎不像其他选项那么令人讨厌,但我仍然更喜欢你的原创。

问题是,从另一个开发人员的角度来看,其他任何事情都会使你的代码变得不那么明显。 如果有一个foreach在一个集合中运行,我希望该集合将(至少通常)包含在那里的项目。 如果集合可能是空的,那么对于没有注释的其他人来说这是不明显的(写入比if检查需要更长的时间)。

做任何黑客以避免if检查似乎你想要太聪明。