58

ここでの基本的な質問-次のようなコード行がたくさんあります。

var a = (long_expression == null) ? null : long_expression.Method();

この関数では、同様の行が何度も繰り返されます。long_expression毎回異なります。私は繰り返しを避ける方法を見つけようとしていますlong_expressionが、これをコンパクトに保ちます。の反対のようなものoperator ??。今のところ、私はただ諦めて、次のように複数の行に配置することを検討しています。

var temp = long_expression;
var a = (temp == null) ? null : temp.Method();

しかし、私が知らない巧妙な構文があれば、これがより簡潔になるのではないかと思いました。

4

7 に答える 7

77

さて、あなたはこのような拡張方法を使うことができます:

public static TResult NullOr<TSource, TResult>(this TSource source,
    Func<TSource, TResult> func) where TSource : class where TResult : class
{
    return source == null ? null : func(source);
}

それで:

var a = some_long_expression.NullOr(x => x.Method());

または(C#のバージョンによって異なります)

var a = some_long_expression.NullOr(Foo.Method);

Fooのタイプはどこですかsome_long_expression

私はこれをするつもりはないと思います。2行バージョンを使用します。これは単純で賢くありません。「賢い」はStackOverflowにとっては楽しいものですが、実際のコードにとっては通常は良い考えではありません。

于 2012-06-29T19:09:11.363 に答える
49

この答えは洞察に満ちていると思いました。

この割り当てを行うことにより、ヌルをシステムのより深いところに伝播します。これらの伝播を処理するには、null処理条件を何度も(そして何度も)記述する必要があります。

nullを使用して実行を続行できるようにする代わりに、nullをより適切な表現に置き換えます(リンクから引用)

  1. nullが空のコレクションを表す場合は、空のコレクションを使用します。
  2. nullが例外的なケースを表す場合は、例外をスローします。
  3. nullが誤って初期化されていない値を表す場合は、明示的に初期化してください。
  4. nullが正当な値を表す場合は、それをテストします。または、null操作を実行するNullObjectを使用することをお勧めします。

特に、nullコレクション参照を空のコレクションに置き換えることで、多くのnullテストを節約できました。

于 2012-06-29T19:27:22.570 に答える
5
var x = "";

/* try null instead */
string long_expression = "foo";

var a = ((x = long_expression) == null) ? null : x.ToUpper();

/* writes "FOO" (or nothing) followed by newline */
Console.WriteLine(a);

の初期化値のタイプは、のxタイプと互換性がある必要がありますlong_expression(ここでは:) stringMono C#コンパイラバージョン2.10.8.1 (Debianパッケージmono-gmcs = 2.10.8.1-4から)で動作します。

于 2012-06-30T07:02:46.640 に答える
5

C#言語は、この種のロジックに新しい演算子を実際に使用できると思います。これは非常に一般的であり、演算子は数え切れないほどのコード行を単純化します。

「??」に沿った何かが必​​要です または「ifnullthen」演算子ですが、これは特別な「。」として機能します。「nullでない場合」の条件を持つドット演算子。「??」の場合、最初の「?」「?:」if-thenの「if」部分と2番目の「?」のようなものです。null許容型のように「null」を表します。「。?」が必要だと思います '。'と同じように機能する演算子。ただし、例外をスローするのではなく、左側の式がnullの場合にnullと評価されるだけです。私はそれが「nullではないドット」演算子になると思います(OK、おそらく「。!?」はより論理的ですが、そこには行かないでください)。

したがって、非常に一般的な例では、次のような冗長なシンボル名が失われる可能性があります。

var a = long_expression.?Method();

ネストされたnullチェックを備えたC#コードがたくさんあり、非常に役立ちます。これがあればどれだけいいか考えてみてください。

if (localObject != null)
{
    if (localObject.ChildObject != null)
    {
        if (localObject.ChildObject.ChildObject != null)
            localObject.ChildObject.ChildObject.DoSomething();
    }
}

ちょうどなる可能性があります:

localObject.?ChildObject.?ChildObject.?DoSomething();

また、存在するはずのnullチェックが欠落しているコードが大量にあり、実行時エラーが発生することがあります。したがって、実際には新しい「。?」を使用します 演算子はデフォルトでそのような問題を排除します...「。」の動作を元に戻すことができなかったのはおそらく残念です。と '。?' この時点では、新しい「。?」のみです。左側がnullの場合、例外をスローします。これは、よりクリーンで論理的な方法ですが、変更を壊すのは非常に悪いことです。ただし、この特定の変更により、多くの隠れた問題が修正される可能性が高く、何かが壊れる可能性は低いと主張することもできます(null ref例外がスローされることを期待するコードのみ)。ああ、まあ...いつでも夢を見ることができます...

nullをチェックすることの唯一の欠点は、実際にはわずかなパフォーマンスの低下です。これが最も確実な理由です。nullをチェックしません。しかし、私は本当に「。?」を使用する能力を考えています。パフォーマンスを気にするとき(そして左側がnullになることは決してないことを知っているとき)は、より良い方法でした。

同様に、'foreach'でnullコレクションをチェックして無視することも、はるかに優れていたでしょう。ほとんどの「foreach」ステートメントを「if(collection!= null)」でラップする必要はありません。さらに悪いことに、nullの代わりに常に空のコレクションを使用するという一般的な習慣を身に付ける必要があります...これは場合によっては問題ありませんが、さらに悪いことですコレクションの大部分が空である複雑なオブジェクトツリーでこれが行われる場合のnullチェックよりもパフォーマンスの問題(これは私がよく見たものです)。ほとんどの場合、パフォーマンスを向上させるためにnullの「foreach」チェックを行わないという善意は裏目に出たと思います。

アンダース、そのような変更を加えるのに遅すぎることは決してなく、それらを有効にするためにコンパイラスイッチを追加してください!

于 2012-07-03T19:30:16.330 に答える
1

long_expressionが評価するタイプに関係なく、拡張メソッドを記述できます。

public static object DoMethod(this MyType pLongExpression)
{
   return pLongExpression == null ? null : pLongExpression.Method();
}

これは、参照がである場合でも、任意のMyType参照で呼び出すことができnullます。

于 2012-06-29T19:11:47.447 に答える
0

短い名前の関数を入れlong_expression == nullて、毎回その関数を呼び出すことができます。

于 2012-06-29T19:07:10.357 に答える
0

if(!String.IsNullOrEmpty(x))x.func()

于 2016-05-11T11:56:41.243 に答える