foreachループでnullを確認する


91

以下を行うより良い方法はありますか?
ループを続行する前に、file.Headersでnullが発生するかどうかを確認する必要があります

if (file.Headers != null)
{
  foreach (var h in file.Headers)
  {
   //set lots of properties & some other stuff
  }
}

要するに、コード内で発生するインデントのレベルが原因でif内にforeachを記述するのは少し醜く見えます。

評価するものです

foreach(var h in (file.Headers != null))
{
  //do stuff
}

可能?


3
あなたはここで見ることができ:stackoverflow.com/questions/6937407/...
エイドリアンFâciu


1
@AdrianFaciu完全に違うと思います。質問では、for-eachを実行する前に、まずコレクションがnullかどうかを確認します。リンクは、コレクション内のアイテムがnullかどうかをチェックします。
rikitikitik


1
C#8は単に、ある種のnull条件付きforeach、つまり次のような構文を持つことができます:foreach?(コレクション内の変数i){}これを正当化するのに十分な一般的なシナリオだと思います、そして、ここで意味のある言語に最近のnull条件付きの追加を考えると?
mms

回答:


121

Runeの提案にちょっとした化粧品の追加と同じように、独自の拡張メソッドを作成できます。

public static IEnumerable<T> OrEmptyIfNull<T>(this IEnumerable<T> source)
{
    return source ?? Enumerable.Empty<T>();
}

それからあなたは書くことができます:

foreach (var header in file.Headers.OrEmptyIfNull())
{
}

好みに合わせて名前を変えてください:)


75

file.Headersの要素のタイプがTであると仮定すると、これを行うことができます

foreach(var header in file.Headers ?? Enumerable.Empty<T>()){
  //do stuff
}

file.Headersがnullの場合、これはTの空の列挙型を作成します。ファイルのタイプが自分が所有するタイプの場合は、Headers代わりにゲッターを変更することを検討します。nullnullの値なので、可能であれば、nullを「要素がないことを知っている」として使用する代わりに、nullを(元々)「要素があるかどうかわからない」と解釈する必要がある場合は、空のセットを使用して表示します。セットに要素がないことを知っていること。nullチェックを頻繁に行う必要がないため、これもより乾燥します。

Jons提案のフォローアップとして編集し、上記のコードを次のように変更する拡張メソッドを作成することもできます

foreach(var header in file.Headers.OrEmptyIfNull()){
  //do stuff
}

ゲッターを変更できない場合は、操作に名前(OrEmptyIfNull)を指定することで意図をより明確に表現するので、これが私の好みです。

上記の拡張方法では、オプティマイザが特定の最適化を検出できない場合があります。具体的には、これをオーバーロードするメソッドを使用してIListに関連するものを排除できます。

public static IList<T> OrEmptyIfNull<T>(this IList<T> source)
{
    return source ?? Array.Empty<T>();
}

(さえないのパフォーマンスの低下を伴う:@ kjbartelの答え(それはしていないため、「stackoverflow.com/a/32134295/401246」には、最善の解決策である)nullのLCDにループ全体を縮退)IEnumerable<T>(使用したとして?? )、b)すべてのプロジェクトに拡張メソッドを追加する必要がある、またはc)null IEnumerables(Pffft!Puh-LEAZE!SMH)で開始することを回避する必要nullがあるええと、空です。つまり、従業員は、非セールスの場合はN / Aであるコミッション、またはセールスがない場合は空のコミッションを持つことができます)。
トム

@Tomは、1つの nullチェックを除いて、列挙子がnullでない場合のペナルティはありません。enumerableがnullではないことを確認しながらそのチェックを回避することは不可能です。上記のコードでは、Headersをan IEnumerableforeach要求します。これは、要件よりも制限的ですが、List<T>リンク先の回答の要件よりも制限的ではありません。列挙型がnullかどうかをテストする場合と同じパフォーマンスペナルティがあります。
ルーンFS

私はkjbartelの回答と同じスレッドで、Vlad Bezdenの回答のEric Lippertによるコメントの「LCD」の問題に基づいていました。 List <T>または配列に対して、値タイプの列挙子を使用するようにforeachを最適化するか、実際に「for」ループを生成できます。リストまたは空のシーケンスのいずれかを強制的に列挙する場合は、「最低共通分母 "codegen。これは、場合によっては遅くなり、より多くのメモリ圧力を生成することがあります..." それが必要とすることに同意しますList<T>
トム

@tom答えの前提は、file.HeadersがIEnumerable <T>であることです。この場合、コンパイラーは最適化を実行できません。ただし、これを回避するために拡張メソッドソリューションを拡張するのはかなり簡単です。編集を参照
Rune FS

19

率直に言って、私はアドバイスをします。ただnullテストを吸ってください。nullテストがあるだけで、A brfalsebrfalse.s。他のすべては非常に多くの作業(テスト、課題、余分なメソッド呼び出し、不要に関与しようとしていますGetEnumerator()MoveNext()Dispose()イテレータに、など)。

ifテストは、簡単で明白な、かつ効率的です。


1
あなたは興味深い点をマークマークを付けますが、私は現在、コードのインデントレベルを下げることを目指しています。ただし、パフォーマンスに注意する必要がある場合は、コメントを覚えておきます。
エミネム

3
このMarcについて簡単に説明します。私がこの質問をして、いくつかのパフォーマンス強化を実装する必要があった数年後、あなたのアドバイスは非常に役に立ちました。ありがとう
エミネム

12

反復前の「if」が問題ない場合、それらの「かなり」のセマンティクスのいくつかは、コードを読みにくくする可能性があります。

とにかく、インデントが邪魔になる場合は、チェックするifを変更できます。

if(file.Headers == null)  
   return;

そして、headersプロパティにtrue値がある場合にのみ、foreachループに到達します。

私が考えることができるもう1つのオプションは、foreachループ内でnull結合演算子を使用して、nullチェックを完全に回避することです。サンプル:

List<int> collection = new List<int>();
collection = null;
foreach (var i in collection ?? Enumerable.Empty<int>())
{
    //your code here
}

(コレクションを実際のオブジェクト/タイプに置き換えます)


ifステートメントの外にコードがある場合、最初のオプションは機能しません。
rikitikitik 2012

コードの美化のためだけに、ifリストは新しいリストを作成する場合に比べて実装が簡単で安価です。
アンドレアスヨハンソン

10

使用してヌル条件演算子より速く標準foreachループよりも動作し、foreachのを()。
ただし、コレクションをリストにキャストする必要があります。

   listOfItems?.ForEach(item => // ... );

4
回答の周りにいくつかの説明を追加し、コードのワンライナーではなく、このソリューションが機能する理由を明示してください
LordWilmore

私のケースに最適なソリューション
ジョセフ・ヘン

3

私はこれらのシナリオに素敵な小さな拡張メソッドを使用しています:

  public static class Extensions
  {
    public static IList<T> EnsureNotNull<T>(this IList<T> list)
    {
      return list ?? new List<T>();
    }
  }

ヘッダーのタイプがリストの場合、次のことができます。

foreach(var h in (file.Headers.EnsureNotNull()))
{
  //do stuff
}

1
??演算子を使用して、returnステートメントをreturn list ?? new List<T>;
Rune FS

1
@wolfgangziegler、私nullがあなたのサンプルのテストを正しく理解していればfile.Headers.EnsureNotNull() != null、それは必要ではなく、さらに間違っていますか?
Remko Jansen 2012

0

場合によっては、デフォルトのコレクションコンストラクターが空のインスタンスを返すと想定して、もう少し別の一般的なバリアントを使用したい場合があります。

このメソッドに名前を付けることをお勧めしNewIfDefaultます。これはコレクションだけでなく、型制約IEnumerable<T>も冗長になる可能性があるので便利です。

public static TCollection EmptyIfDefault<TCollection, T>(this TCollection collection)
        where TCollection: class, IEnumerable<T>, new()
    {
        return collection ?? new TCollection();
    }
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.