C#で「変数!= null」の代わりに「null!=変数」がよく表示されるのはなぜですか?


103

c#では、条件を述べる順序の実行速度に違いはありますか?

if (null != variable) ...
if (variable != null) ...

最近から最初の方をよく見ましたが、2番目に慣れてから気になりました。

違いがない場合、最初のものの利点は何ですか?



一部のプログラミング言語は、if条件で値を初期化することをサポートしています。このような言語では、LValueとRValueを比較する場合、if(1 == i)のように左側にリテラルを使用することをお勧めします。したがって、誤って=ではなく==を指定すると、コンパイラエラーが発生します。
Jugal Panchal 2017

回答:


160

これはCからの持ち越しです。Cでは、不適切なコンパイラを使用するか、警告が十分に高くならない場合、警告なしでコンパイルされます(実際に正当なコードです)。

// Probably wrong
if (x = 5)

あなたが実際におそらく意味したとき

if (x == 5)

Cでこれを回避するには、次のようにします。

if (5 == x)

ここにタイプミスがあると、コードが無効になります。

さて、C#ではこれはすべて簡単です。あなたは(まれで、IME)2つのブール値を比較している場合を除き文がで開始するブール式を必要とする「場合」、および「の種類として、あなたは、より読みやすいコードを書くことができるx=5」であるInt32、ではありませんBoolean

同僚のコードでこれを目にした場合は、現代の言語の方法でそれらを教育し、将来、より自然な形式を書くことをお勧めします。


6
私の同僚は皆、これで私を狂わせ、ifの後の1つのステートメントでも中括弧を必要としています... F#とBoo(およびYAML)を使い、インデントなしで言語が読めない場合は、それを言語の一部にしてください。
Benjol 2008年

48
中かっこを追加すること合理的です。IMO-C#は、問題が発生するのを止めようとはしません。これは、「定数==変数」の問題とは大きく異なります。
Jon Skeet、

6
if(this!= that){performAsSuch(); }実はかなり健康です。「後で追加する」という議論は、(a = 5)タイプミスの場合、回避/スポッティングしないのと同じぐらい壊れやすいくらいに私に繋がります
jpinto3912

3
@jpinto:ここで何を言おうとしているのかよくわかりません。単一のステートメントを中括弧で囲むの好きなのか、そうでないのですか?これと問題の変数ビジネスの違いは、C#ではタイプミスのあるコードは無効なコードであるため、コンパイラーがそれを停止することです。同じことはないで括弧を入れていないため、真。
ジョンスキート

3
@Benjol else { }誰かが後で何かを追加する必要があり、else自分でキーワードを書くのを忘れた場合に備えて、常に空の句を提供することを忘れないでください。(ジョーク)
Jeppe Stig Nielsen 2013

12

最初にnullを使用するのには十分な理由があります。 if(null == myDuck)

あなたの場合はclass Duck上書き==オペレータは、if(myDuck == null)無限ループに入ることができます。

使用してnull最初の用途をデフォルト平等のコンパレータを、実際にあなたが意図したものを行います。

(私はあなたが最終的にそのように書かれたコードを読むことに慣れると聞きます-私はまだその変換を経験していません)

次に例を示します。

public class myDuck
{
    public int quacks;
    static override bool operator ==(myDuck a, myDuck b)
    {
        // these will overflow the stack - because the a==null reenters this function from the top again
        if (a == null && b == null)
            return true;
        if (a == null || b == null)
            return false;

        // these wont loop
        if (null == a && null == b)
            return true;
        if (null == a || null == b)
            return false;
        return a.quacks == b.quacks; // this goes to the integer comparison
    }
}

11
これは間違っています。反対投票。==オペレーターの上にマウスを置くだけで、その上に置くと、両方のケースでユーザー定義のオーバーロードが使用されていることがわかります。もちろん、a前に確認してから、右側のオペランドから左側のオペランドにb位置を入れ替えると、微妙な違いが生じますa。しかし、あなたはbaにチェックすることもでき、それからb == null順序を逆にしたものになります。これは、オペレーターが自分自身を呼び出すのを混乱させるものです。代わりに、いずれかのオペランド(または両方)をキャストobjectして、目的のオーバーロードを取得します。同様if ((object)a == null)if (a == (object)null)
Jeppe Stig Nielsen

10

すでに述べたように、それは多かれ少なかれ2番目の等号を忘れた場合に誤ったコードを取得する可能性があるC言語から来ています。しかし、C#にも一致する別の理由があります。それは、読みやすさです。

この単純な例を見てみましょう:

if(someVariableThatShouldBeChecked != null
   && anotherOne != null
   && justAnotherCheckThatIsNeededForTestingNullity != null
   && allTheseChecksAreReallyBoring != null
   && thereSeemsToBeADesignFlawIfSoManyChecksAreNeeded != null)
{
    // ToDo: Everything is checked, do something...
}

すべてのヌルワードを最初に置き換えるだけであれば、すべてのチェックを簡単に見つけることができます。

if(null != someVariableThatShouldBeChecked
   && null != anotherOne
   && null != justAnotherCheckThatIsNeededForTestingNullity
   && null != allTheseChecksAreReallyBoring
   && null != thereSeemsToBeADesignFlawIfSoManyChecksAreNeeded)
{
    // ToDo: Everything is checked, do something...
}

したがって、この例はおそらく悪い例ですが(コーディングのガイドラインを参照)、コードファイル全体をすばやくスクロールすることを考えてください。パターンを見るだけで

if(null ...

次に何が起こるかすぐにわかります。

逆の場合は、常に行末までスキャンして無効性チェックを確認する必要があります。そこでつまずいて、そこで行われているチェックの種類を確認します。したがって、構文の強調表示が役立つ場合がありますが、これらのキーワードが先頭ではなく行末にある場合は常に遅くなります。


9

これは言語を切り替えたCプログラマだと思います。

Cでは、次のように記述できます。

int i = 0;
if (i = 1)
{
    ...
}

そこでは、単一の等号の使用に注意してください。これは、コードが変数iに1を割り当て、次に1(割り当ては式)を返し、ifステートメントで1を使用します。これはtrueとして処理されます。つまり、上記はバグです。

ただし、C#ではこれは不可能です。確かに両者には違いはありません。


1
"C#では、これは不可能です。" ifステートメントにはブール式が必要であり、提供される式はint型であるため、コンパイラーは不平を言いません。
Robert Harvey、

4

以前は、人々は「!」を忘れていました。(または、等号の場合は追加の '='で、これを見つけるのはより困難です)、比較の代わりに割り当てを行います。nullを前に配置すると、nullはl値ではない(つまり、割り当てられない)ため、バグの可能性がなくなります。

最近のほとんどのコンパイラでは、条件付きで割り当てを行うと警告が表示され、C#では実際にエラーが発生します。一部の人にとっては読みやすいので、ほとんどの人はvar == nullスキームに固執します。


すべてのC#コンパイラ(これはC#の質問です)は、式がブール値ではない "if"ステートメントのコンパイルに失敗するはずです...
Jon Skeet

4

この慣習に従うことには何の利点もありません。ブール型が存在しないCでは、次のように書くと便利です。

if( 5 == variable)

のではなく

if (variable == 5)

等号のいずれかを忘れると、

if (variable = 5)

これは変数に5を割り当て、常にtrueと評価します。しかし、Javaでは、ブール値はブール値です。そして!=の場合、理由はまったくありません。

ただし、1つの良いアドバイスは、

if (CONSTANT.equals(myString))

のではなく

if (myString.equals(CONSTANT))

NullPointerExceptionsを回避するのに役立ちます。

私のアドバイスは、ルールの正当化を求めることです。ない場合は、なぜそれをフォローするのですか?それは読みやすさを助けません


0

私にとっては常にあなたが好むスタイルでした

@恥ずかしがり屋-次に、演算子を混乱させると、コンパイルエラーが発生するか、バグでコードを実行する必要があります-バグは戻ってきて、予期せぬ動作を引き起こしたため、後であなたを噛んでしまいます


私は私が今まで「定数==変数」形式を好むだれでも聞いたとは思わない他の既にC#で対処されている安全上の理由のためによりを。
Jon Skeet、

私は「変数==定数」の方を好みますが、プログラマがより自然に読むと感じるため、プログラマが逆を採用するのを見てきました。
TheCodeJunkie 2008年

1
彼らは何年もCを何年も洗脳していたのでしょうか、それとも本当の選択でしたか?
Jon Skeet、

0

多くの人が指摘したように、コンパイラはそれを合法として受け入れたので、それは主にコンパイルエラーを識別するために使用された古いCコードにあります

Javaのような新しいプログラミング言語、goは、そのようなコンパイルエラーをキャプチャするのに十分スマートです

コード内の条件のように「null!=変数」を使用することはできません。


-4

もう1つ...変数を定数(ex。の場合は整数または文字列)と比較する場合は、定数を左側に置くことをお勧めします。

int i;
if(i==1){        // Exception raised: i is not initialized. (C/C++)
  doThis();
}

一方

int i;
if(1==i){        // OK, but the condition is not met.
  doThis();
}

さて、デフォルトではC#はすべての変数をインスタンス化するので、その言語ではそのような問題はないはずです。


1
コードの最初のビットに使用しているコンパイラはわかりませんが、コンパイルする必要があります(通常は警告付き)。iの値は未定義ですが、いくつかの値があります。
イルカ

もちろん、両方のコードがコンパイルされます!それがまさに問題です。最初のコードを実行してみてください。「例外が発生しました」の意味を理解できます...
karlipoppins 09/09/06

また、2つの間の違いを取得しないでください。エラボレートできますか?
mfazekas

C / C ++でint * iを宣言しない限り、例外はありません。その場合でも、ポインターを比較して例外をスローしません... Dolphinが述べたように、値は未定義ですが、例外は生成されません。
Cobusve 2010年

例外はありませんi。適切な初期化なしのランダムな値であるとしましょう。式の意味はc / c ++でもまったく同じです
Raffaello
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.