6

私はコードを次のように書くことに慣れています(単なる例)

Request.QueryString["xxxx"] != null

最近誰かが言ってた

null != Request.QueryString["xxxx"]

より良いパフォーマンスを提供します。

それが実際に違いをもたらすかどうかを知りたいのですが、そうであればどうですか?

注〜上記は一例です。一般的に言えば

どうにか

Constant [Operator] Actual Value (e.g. 1 == Convert.ToInt32(textbox1.text))

よりも良い

Actual Value [Operator] Constant (e.g. Convert.ToInt32(textbox1.text) == 1)

ありがとう

4

4 に答える 4

15

これは、多くの暗黙的な型変換を伴う言語で使用されるコーディング スタイルです ( OSVの語順から、スター ウォーズのキャラクターに由来するフレンドリーな名前のヨーダ)。タイプミスに起因するある種のエラーを防ぐために、プロジェクトのガイドラインによって強制されたり、要求されたりすることさえあります。言語が異なれば、このスタイルのバリエーションと拡張も異なりますが、この回答は C と C# に限定します。

なぜいいの

たとえば、C では次のように記述できます。

int a = CalculateValue();
if (a = CalculateAnotherValue()) {
    /* Do something */
}

aこのコードは、返された値に代入しCalculateValue()、結果で値を上書きし、CalculateAnotherValue()ゼロでない場合はコードを実行します。おそらくそれは意図したものではなく、式の割り当てがif間違っています。あなたの例から、NULLあなたは持っているかもしれません:

if (pBuffer = NULL)

繰り返しますが、おそらくそれはあなたが望むものではありません (そして、これは非常によくある間違いです)。ポインターに NULL を割り当てると、条件は常に false になります。あなたが書く場合:

if (NULL = pBuffer)

(値をリテラルに代入できないため) コンパイルされず、コンパイル時エラーが発生します。

この種のコンパイル時チェックは、このコーディング スタイルを使用する唯一の理由ではありません。次の C# (非常に一般的な) コードを見てください。

if (text != null && text.Equals("something", StringComparison.InvariantCulture)
    DoSomething();

次のように契約できます。

if ("something".Equals(text, StringComparison.InvariantCulture))
    DoSomething();

なんでだめなの

C#では、通常は問題になりません。これは C/C++ から継承されたプラクティスです。C# では式が自動的に変換されないためbool、次のコードはコンパイルされません。

if (Request.QueryString["PartnerID"] = null)

次に、この慣行はC#では役に立ちません(コメントで@IlianPinzonが指摘した例外を除いて)、パフォーマンスについては何もありません。このような間違いを避けるためだけに使用されました。

なぜそうかのセクションの最後の例については、問題は読みやすさ"something".Equals(text)です。

パフォーマンス

これらの関数から始めます:

static bool TestRight(object value)
{ return value == null; }

static bool TestLeft(object value)
{ return null == value; }

以下の IL を生成します。

.maxstack 2
.locals init ([0] bool CS$1$0000)
L_0000: nop 
L_0001: ldnull 
L_0002: ldarg.0 
L_0003: ceq 
L_0005: stloc.0 
L_0006: br.s L_0008
L_0008: ldloc.0 
L_0009: ret 

唯一の違いは、L_0001 と L_0002 の行です。これらは入れ替わっているだけですが、オペランドの順序によって の動作が変わることはありませんceq。メソッドをオーバーライドしてもEquals()、JIT コンパイラは両方の式に対して同じアセンブリ コードを生成します (比較は常にEquals(), nullis typelessによって行われるため)。

比較にユーザー定義の等値比較子が含まれる場合、事態はさらに複雑になる可能性があります。この場合、ルールはなく、効果的なop_Equals実装に依存します。たとえば、この==実装:

public static bool operator==(MyType lhs, MyType rhs)
{
    if (Object.ReferenceEquals(lhs, rhs))
        return true;

    if (Object.ReferenceEquals(lhs, null))
        return false;

    return lhs.Equals(rhs);
}

この場合、最初のオペランドが実行である場合null、実行はわずかに高速になりますが (MyType.Equals()呼び出されないため)、このパフォーマンスの向上は非常に小さく、1 つの比較、いくつかのジャンプ、および仮想関数呼び出しを節約できます。さらに、逆の場合に関数をより高速に書き直すことができます (これが本当に重要な場合)。

ここでは、パラメーター以外の値をMyType.Equals(object)単純に返す小さなテストを示します。テストはループ回数になります。truenullInt32.MaxValue

操作合計時間 (ミリ秒)
lhs == null 10521
null == lhs 2346

の不要な呼び出しを回避する「最適化された」バージョンEquals()は 5 倍速いようですが、ループ回数が非常に多く、実際の実装Equals()は空であることに注意してください。真の実装では、関数呼び出しの相対的なオーバーヘッドが削減されます (おそらく、このマイクロ最適化以外にやるべきことがあります)。システム クラスの場合、この詳細に依存することはできません。たとえば、String.Equals()常にオペレーターによって呼び出されます (順序は関係ありません)。ただし、1 つのコード パスの方が高速であると想定することはできず、この事実はフレームワークの将来のバージョンでも変更されません。 (または異なる CPU アーキテクチャの場合)。

于 2012-05-30T07:00:07.157 に答える