5

一連のオブジェクトをチェックして、どれも null でないことを確認したいとします。

if (obj != null &&
    obj.Parameters != null &&
    obj.Parameters.UserSettings != null) {

    // do something with obj.Parameters.UserSettings
}

可変数の引数を受け入れ、この種のチェックを簡素化するヘルパー関数を作成することは魅力的な見通しです。

static bool NoNulls(params object[] objects) {
    for (int i = 0; i < objects.Length; i++)
        if (objects[i] == null) return false;

    return true;
}

次に、上記のコードは次のようになります。

if (NoNulls(obj, obj.Parameters, obj.Parameters.UserSettings)) {
    // do something
}

右?違う。objが null の場合、NullReferenceExceptionに渡そうとするとobj.Parametersが取得されNoNullsます。

したがって、上記のアプローチは明らかに見当違いです。しかし、演算子ifを使用したステートメント&&は短絡されているため、問題なく機能します。だから:メソッド内で明示的に参照されるまでその引数が評価されないように、メソッドを短絡させる方法はありますか?

4

3 に答える 3

9

うーん、醜いけど…

static bool NoNulls(params Func<object>[] funcs) {
    for (int i = 0; i < funcs.Length; i++)
        if (funcs[i]() == null) return false;

    return true;
}

次に、次のように呼び出します。

if (NoNulls(() => obj,
            () => obj.Parameters,
            () => obj.Parameters.UserSettings)) {
    // do something
}

基本的に、値自体ではなく値を遅延評価するデリゲートを提供しています (これらの値を評価すると例外が発生するため)。

いいとは言いませんが、オプションとしてあります...

編集:これは実際に(そして偶然にも)ダンが求めていたものの核心に達すると思います。メソッド自体が実行される前に、すべてのメソッドの引数が評価されます。デリゲートを効果的に使用すると、メソッドがデリゲートを呼び出して値を取得する必要があるまで、その評価を遅らせることができます。

于 2009-12-16T20:45:48.710 に答える
1

式ツリーを受け入れ、そのツリーを null をチェックする形式に変換する関数を記述し、Func<bool>安全に評価して null があるかどうかを判断できる を返すことができます。

結果として得られるコードはクールかもしれませんが、混乱を招くだけでなく、短絡的なa != null && a.b != null...チェックをたくさん書くよりもはるかにパフォーマンスが低いのではないかと思います。実際、すべての値をチェックしてキャッチするよりもパフォーマンスが低下する可能性がありますNullReferenceException(制御メカニズムのフローとして例外処理を推奨しているわけではありません)。

このような関数のシグネチャは次のようになります。

public static Func<bool> NoNulls( Expression<Func<object>> expr )

使用法は次のようになります。

NoNulls( () => new { a = obj, 
                     b = obj.Parameters, 
                     c = obj.Parameters.UserSettings } )();

時間があれば、このような式ツリーの変換を行う関数を作成し、投稿を更新します。しかし、Jon Skeet や Mark Gravell なら、片目を閉じて片手を後ろに向けてこのような関数を書くことができるはずです。

.?また、Eric がほのめかしている演算子がC# に実装されることを期待しています。別のエリック(カートマン)が言うように、それは「お尻を蹴る」でしょう.

于 2009-12-16T21:21:31.100 に答える
0

静的型の安全性を失うことを気にしない場合は、リフレクションを使用できます。気にしないので、最初の短絡構造を使用します。エリックが言及したような機能は大歓迎です:)

私はこの問題について何度か考えました。Lispには、評価をカスタマイズできるため、あなたが言及した方法で問題を解決するマクロがあります。

この問題を解決するために拡張メソッドを使用することも試みましたが、元のコードほど醜いものはありません。

編集:(返信ではコードブロックを挿入できないため、投稿を編集します)

おっと、これについていけませんでした。申し訳ありません:)

リフレクションを使用して、文字列を介してメンバーまたはプロパティを検索および評価できます。私の友人の 1 人が書いたクラスは、次のような構文を取っていました。

new ReflectionHelper(obj)["Parameters"]["UserSettings"]

メソッド チェーンを介して機能し、各レベルで ReflectionHelper を返します。その例では NullReferenceException が問題であることを知っています。評価を実行時に延期する方法を示したかっただけです。

参考に少し近い例:

public class Something
{
  public static object ResultOrDefault(object baseObject, params string[] chainedFields)
  {
    // ...
  }
}

繰り返しますが、この構文は悪臭を放っています。しかし、これは文字列 + リフレクションを使用して評価を実行時まで延期することを示しています。

于 2009-12-16T21:21:43.983 に答える