如果集合不为空,则标记空集合或枚举成员 (C#)
Flag empty collection or enumerate over members if collection is not empty (C#)
(对我而言)显而易见的解决方案如下:
if (widgets.Count == 0)
{
//Handle empty collection
}
else
{
// Handle non-empty collection
foreach (widget in widgets)
{
// Process widget
}
}
这似乎是缩进的。我很想用 "else foreach" 删除一定程度的缩进,但当我有这个想法时,我的脑子里立刻响起了一声低沉的(但在不断增强)尖叫:
if (widgets.Count == 0)
{
//Handle empty collection
}
else foreach (widget in widgets)
{
// Process widget
}
还有其他想法或建议吗?
您似乎很关心代码的可读性和可维护性。像这样的代码块:
if (someCondition)
{
// do
// a
// lot
{
// moar
// nesting
}
}
else
{
// do
// something
// else
{
// possibly with even more nesting
}
}
通常被认为既不可读也不可维护。当然,您随后可以滥用语法或 use other tricks to reduce the level of nesting,但是您有如此多的嵌套这一事实应该是一个死的赠品,表明一个方法做得太多了。
至少将代码块提取到自己的方法中,自动减少嵌套。
如果将上面的代码放在它自己的方法中开始,您可以从 if()
中 return,完全删除 else
块。
public void DoSomethingWithWidgets(ICollection<Widget> widgets)
{
if (widgets.Count == 0)
{
HandleEmptyCollection();
return;
}
foreach (widget in widgets)
{
ProcessWidget(widget);
}
}
或者将代码完全放在它们自己的 class 中,让 class 自己确定它是否适用于它的输入。你可以这样实现:
public interface IVisitor
{
bool CanVisit(ICollection<Widget> widgets);
void Visit(ICollection<Widget> widgets);
}
public class EmptyCollectionVisitor : IVisitor
{
public bool CanVisit(ICollection<Widget> widgets)
{
return widgets.Count == 0;
}
public void Visit(ICollection<Widget> widgets)
{
// Handle empty collection
}
}
public class NotEmptyCollectionVisitor : IVisitor
{
public bool CanVisit(ICollection<Widget> widgets)
{
return widgets.Count > 0;
}
public void Visit(ICollection<Widget> widgets)
{
foreach (var widget in widgets)
{
// Process widget
}
}
}
然后让所有访问者访问该馆藏(如果可以的话),就完成了。 classes 本身具有更好的可测试性和可重用性。
然后您可以通过遍历注册访客来使用它:
var yourInputCollection = { either a list that is empty or not };
IVisitor[] collectionVisitors = new[] {
new EmptyCollectionVisitor(),
new NotEmptyCollectionVisitor()
};
foreach (var visitor in collectionVisitors)
{
if (visitor.CanVisit(yourInputCollection))
{
visitor.Visit(yourInputCollection);
}
}
是的,这看起来有点矫枉过正,但滥用语法以在尽可能小的水平 space 上容纳尽可能多的代码在我的规模上排名甚至更低。
在这种情况下,我很想使用你之前提到的模式:
if (myVar.Value < 1)
{
//...
}
else switch (myVar.Value)
{
case 1:
//...
break;
case 2:
//...
break;
}
问题是 Visual Studio 自动缩进会不断更改它并在 else
语句之后缩进代码。
我的建议是使用您问题中的第一个示例。消除你的 else
块对 readability/maintainability 没有多大作用。
世界上没有比一级缩进更糟糕的事情了,所以我肯定更喜欢前者而不是第二种不寻常的风格。
另一种方法是删除 foreach
:
的语法糖
using (var en = widgets.GetEnumerator())
{
if (en.MoveNext())
{
do
{
var widget = en.Current;
// process widget.
} while (en.MoveNext());
}
else
{
// Handle empty.
}
}
在语法上它更糟糕,但它确实有一些优势。
您现在可以将它与任何 IEnumerable<Widget>
一起使用,而不必坚持使用 ICollection<Widget>
这意味着您可以跳过在内存中创建集合,这样您就可以看到计数是多少。
当我们要(隐藏在foreach
中)在第一次调用中查找它是否为空时,我们跳过Count
调用和分支会稍微更有效率MoveNext()
无论如何。
当您需要为第一项做一些不同的事情时(例如,从第一项创建一个累加器,然后聚合操作将根据其余项进行更改),类似的方法非常有用。
就是说,除非它处于热路径中或者使用所有可枚举的能力是一个真正的收获,否则我只会将您问题中的第一种情况作为最传统的方法。如果缩进真的那么糟糕(因为其中代码的大小使其难以阅读),您总是可以将其分解为其他方法。
在您的特定情况下,我可能会选择一个辅助变量来跟踪枚举是否为空。
bool empty = true;
foreach (widget in widgets) {
empty = false;
// Process widget
}
if (empty) {
// Handle empty collection
}
这与 Jon Hanna 关于处理任何 IEnumerable<Widget>
而无需枚举两次的回答具有相同的优势,但在我看来,以一种更具可读性的形式,并且自然地避免了对一级块的需要。
(对我而言)显而易见的解决方案如下:
if (widgets.Count == 0)
{
//Handle empty collection
}
else
{
// Handle non-empty collection
foreach (widget in widgets)
{
// Process widget
}
}
这似乎是缩进的。我很想用 "else foreach" 删除一定程度的缩进,但当我有这个想法时,我的脑子里立刻响起了一声低沉的(但在不断增强)尖叫:
if (widgets.Count == 0)
{
//Handle empty collection
}
else foreach (widget in widgets)
{
// Process widget
}
还有其他想法或建议吗?
您似乎很关心代码的可读性和可维护性。像这样的代码块:
if (someCondition)
{
// do
// a
// lot
{
// moar
// nesting
}
}
else
{
// do
// something
// else
{
// possibly with even more nesting
}
}
通常被认为既不可读也不可维护。当然,您随后可以滥用语法或 use other tricks to reduce the level of nesting,但是您有如此多的嵌套这一事实应该是一个死的赠品,表明一个方法做得太多了。
至少将代码块提取到自己的方法中,自动减少嵌套。
如果将上面的代码放在它自己的方法中开始,您可以从 if()
中 return,完全删除 else
块。
public void DoSomethingWithWidgets(ICollection<Widget> widgets)
{
if (widgets.Count == 0)
{
HandleEmptyCollection();
return;
}
foreach (widget in widgets)
{
ProcessWidget(widget);
}
}
或者将代码完全放在它们自己的 class 中,让 class 自己确定它是否适用于它的输入。你可以这样实现:
public interface IVisitor
{
bool CanVisit(ICollection<Widget> widgets);
void Visit(ICollection<Widget> widgets);
}
public class EmptyCollectionVisitor : IVisitor
{
public bool CanVisit(ICollection<Widget> widgets)
{
return widgets.Count == 0;
}
public void Visit(ICollection<Widget> widgets)
{
// Handle empty collection
}
}
public class NotEmptyCollectionVisitor : IVisitor
{
public bool CanVisit(ICollection<Widget> widgets)
{
return widgets.Count > 0;
}
public void Visit(ICollection<Widget> widgets)
{
foreach (var widget in widgets)
{
// Process widget
}
}
}
然后让所有访问者访问该馆藏(如果可以的话),就完成了。 classes 本身具有更好的可测试性和可重用性。
然后您可以通过遍历注册访客来使用它:
var yourInputCollection = { either a list that is empty or not };
IVisitor[] collectionVisitors = new[] {
new EmptyCollectionVisitor(),
new NotEmptyCollectionVisitor()
};
foreach (var visitor in collectionVisitors)
{
if (visitor.CanVisit(yourInputCollection))
{
visitor.Visit(yourInputCollection);
}
}
是的,这看起来有点矫枉过正,但滥用语法以在尽可能小的水平 space 上容纳尽可能多的代码在我的规模上排名甚至更低。
在这种情况下,我很想使用你之前提到的模式:
if (myVar.Value < 1)
{
//...
}
else switch (myVar.Value)
{
case 1:
//...
break;
case 2:
//...
break;
}
问题是 Visual Studio 自动缩进会不断更改它并在 else
语句之后缩进代码。
我的建议是使用您问题中的第一个示例。消除你的 else
块对 readability/maintainability 没有多大作用。
世界上没有比一级缩进更糟糕的事情了,所以我肯定更喜欢前者而不是第二种不寻常的风格。
另一种方法是删除 foreach
:
using (var en = widgets.GetEnumerator())
{
if (en.MoveNext())
{
do
{
var widget = en.Current;
// process widget.
} while (en.MoveNext());
}
else
{
// Handle empty.
}
}
在语法上它更糟糕,但它确实有一些优势。
您现在可以将它与任何
IEnumerable<Widget>
一起使用,而不必坚持使用ICollection<Widget>
这意味着您可以跳过在内存中创建集合,这样您就可以看到计数是多少。当我们要(隐藏在
foreach
中)在第一次调用中查找它是否为空时,我们跳过Count
调用和分支会稍微更有效率MoveNext()
无论如何。
当您需要为第一项做一些不同的事情时(例如,从第一项创建一个累加器,然后聚合操作将根据其余项进行更改),类似的方法非常有用。
就是说,除非它处于热路径中或者使用所有可枚举的能力是一个真正的收获,否则我只会将您问题中的第一种情况作为最传统的方法。如果缩进真的那么糟糕(因为其中代码的大小使其难以阅读),您总是可以将其分解为其他方法。
在您的特定情况下,我可能会选择一个辅助变量来跟踪枚举是否为空。
bool empty = true;
foreach (widget in widgets) {
empty = false;
// Process widget
}
if (empty) {
// Handle empty collection
}
这与 Jon Hanna 关于处理任何 IEnumerable<Widget>
而无需枚举两次的回答具有相同的优势,但在我看来,以一种更具可读性的形式,并且自然地避免了对一级块的需要。