[英]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
}
}
通常被認為既不可讀也不可維護。 當然,您可以濫用語法或使用其他技巧來減少嵌套的水平 ,但是嵌套太多的事實應該是一種方法無法勝任的事實。
至少將代碼塊提取到自己的方法中,從而自動減少嵌套。
如果首先將上述代碼放在自己的方法中,則可以從if()
返回,完全刪除else
塊。
public void DoSomethingWithWidgets(ICollection<Widget> widgets)
{
if (widgets.Count == 0)
{
HandleEmptyCollection();
return;
}
foreach (widget in widgets)
{
ProcessWidget(widget);
}
}
或者改為將代碼完全放在自己的類中,然后讓一個類自行確定它是否適用於其輸入。 您可以這樣實現:
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
}
}
}
然后,如果可以的話,讓所有訪問者訪問集合,然后完成。 附加的好處是,類本身可以更好地測試和重用。
然后,通過遍歷已注冊的訪問者來利用它:
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);
}
}
是的,這似乎有些矯kill過正,但是濫用語法以在盡可能少的水平空間容納盡可能多的代碼,在我看來,其優雅程度甚至更低。
在這種情況下,我很想使用您所說的模式:
if (myVar.Value < 1)
{
//...
}
else switch (myVar.Value)
{
case 1:
//...
break;
case 2:
//...
break;
}
問題是Visual Studio自動縮進將不斷更改它,並在else
語句后縮進代碼。
我的建議是使用您問題中的第一個例子。 消除else
塊對可讀性/可維護性幾乎沒有幫助。
世界上存在比縮進級別更糟糕的事情,因此,我絕對更希望前者比后者更不尋常。
另一種方法是刪除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>
,這意味着您可以跳過內存中的創建集合,以便查看計數。
這是稍微更高效,我們跳過Count
的呼叫和分支的時候,我們要(隱藏在foreach
)發現,如果在第一個電話是空MoveNext()
的任何方式。
當您需要對第一項執行不同的操作時(例如,從第一項創建累加器,然后累加操作將基於其余項進行更改),類似的方法非常有用。
就是說,除非真正走上正軌,要么能夠使用所有可枚舉對象的能力是真正的收獲,我只想將問題中的第一種情況視為最常規的方法。 如果縮進確實很糟糕(由於縮進的代碼太大,很難閱讀),您可以隨時將其分解為其他方法。
在您的特殊情況下,我可能會選擇一個輔助變量來跟蹤枚舉是否為空。
bool empty = true;
foreach (widget in widgets) {
empty = false;
// Process widget
}
if (empty) {
// Handle empty collection
}
這具有與喬恩·漢納(Jon Hanna)的答案相同的優勢,即無需枚舉兩次即可處理任何IEnumerable<Widget>
,但是在我看來,這是以可讀性更高的形式,並且自然避免了對一級塊的需求。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.