0

前の質問では、IEnumerableと、null値のコレクションの代わりに空のコレクションを使用する規則について説明しました。多くの間違いを起こしやすいnullチェックを排除するので、これは良い習慣です。

しかし、答えはケースの1つに完全には対応していません。多くの場合、特に配列が外部メソッドから返される場合は、null値を処理する必要があります例:

(foreignObj.GetPeople() ?? Enumerable.Empty<Person>())
  .Where(p => p.Name != "John")
  .OrderBy(p => p.Name)
  .Take(4);

読みやすさをいくらか改善するヘルパーメソッドを作成しました。

public class SafeEnumerable
{
    public static IEnumerable<T> From<T>(T[] arr)
    {
        return arr ?? Enumerable.Empty<T>();
    }
}

その結果:

SafeEnumerable.From(foreignObj.GetPeople())
  .Where(p => p.Name != "John")
  .OrderBy(p => p.Name)
  .Take(4);

私はこれを気にしませんが、私はより良いアイデアを探しています。すでにあるはずの何かを追加しているようです。

4

4 に答える 4

2

IEnumerable の一連の拡張メソッドを作成しました。その最初のメソッドは EmptyIfNull です。

例えば。

public static class EnumerableExtensions {

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

}

これにより、私はすることができます

var q = foreignObj.GetPeople().EmptyIfNull().Where(p=>p.Name != "John").OrderBy(p => p.Name).Take(4);   

次に、「安全な」拡張機能を追加して、コードを入力するのを少し短くしたり、読みやすくしたりできます

例えば

 public static IEnumberable<T> SafeWhere<T>(this collection<T> source,Func<T,bool> predicate) {
   return source==null ? Enumerable.Empty<T>() : source.Where(predicate);
 }

与える

var q = foreignObj.GetPeople().SafeWhere(p=>p.Name != "John").OrderBy(p => p.Name).Take(4);   
于 2011-09-21T09:09:50.057 に答える
2

問題は、コレクション ( IEnumerable<T>) を取得した場所を特定します。nullコレクションの値のチェックで常に忙しい場合は、ソースの変更を検討する必要があります。例えば:

public User GetUser(long id) { }
public List<User> GetUsers(long companyId) { }

最初のメソッドは、nullユーザーが見つからないときに a を返す場合に意味があり、null戻り値はnot foundを意味します。nullしかし、私の意見では、2 番目のメソッドは、通常の状況では決して a を返すべきではありません。ユーザーが見つからない場合は、null値の代わりに空のリストが返されます。これは、プログラムの何かが正しくないことを意味します。directoryInfo.GetFiles("*.txt")そして、あなたの質問の例では、ファイルが見つからない場合は null を返すとは思わずtxt、代わりに空のコレクションを返す必要があります。

于 2011-09-21T08:45:11.110 に答える
1

ソースを変更して null を返すメソッドを修正できない場合、そのアプローチは理にかなっています。

より慣用的な LINQy の方法で使用できるように、拡張メソッドにすることもできます。

var query = foreignObj.GetPeople()
                      .AsNonNullEnumerable()
                      .Where(p => p.Name != "John")
                      .OrderBy(p => p.Name)
                      .Take(4);

// ...

public static class EnumerableExtensions
{
    public static IEnumerable<T> AsNonNullEnumerable<T>(this IEnumerable<T> source)
    {
        return source ?? Enumerable.Empty<T>();
    }
}
于 2011-09-21T09:10:13.680 に答える
-1

残念ながら、これには何も組み込まれていないと思います。あなたが自分自身を繰り返さない限り:

foreach(var item in (GetUsers() ?? new User[0])) // ...

少し「より良い」実装 (C# コンパイラがyield returnsytnax 用に生成するものから例をとります)。メモリの無駄がわずかに少なくなります。

class SafeEnumerable<T> : IEnumerable<T>, IEnumerator<T>
{
    private IEnumerable<T> _enumerable;
    public SafeEnumerable(IEnumerable<T> enumerable) { _enumerable = enumerable; }

    public IEnumerator<T> GetEnumerator()
    {
        if (_enumerable == null)
            return this;
        else
            return _enumerable.GetEnumerator();
    }
    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return GetEnumerator(); }

    public T Current { get { throw new InvalidOperationException(); } }
    object System.Collections.IEnumerator.Current { get { throw new InvalidOperationException(); } }

    public bool MoveNext() { return false; }
    public void Reset() { }
    public void Dispose() { }
}
于 2011-09-21T09:09:28.767 に答える