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检查似乎你想要太聪明。