2

SlSvcUtil.exeを使用してサービス クライアント ファイルを作成すると、次のようなコードが表示されます。

private string CategoryField;

[System.Runtime.Serialization.DataMemberAttribute()]
public string Category
{
    get
    {
        return this.CategoryField;
    }
    set
    {
        if ((object.ReferenceEquals(this.CategoryField, value) != true))
        {
            this.CategoryField = value;
            this.RaisePropertyChanged("Category");
        }
    }
}

ReSharperで検査すると、次の警告が表示されます。

「Object.ReferenceEquals」は、値型で呼び出されるため、常に false です。

文字列が immutableであることは理解していますが、すべてのプロパティに対してこの警告が表示されるようです。

ReSharperは以下を推奨します。

注:これには、単純なゲッターを1行に配置し、を反転しif、冗長なobject修飾子と!= true比較を削除するという私のカスタムスタイルが含まれます

private string CategoryField;

[DataMember]
public string Category
{
    get { return this.CategoryField; }
    set
    {
        if (Equals(this.CategoryField, value)) { return; }

        this.CategoryField = value;
        this.RaisePropertyChanged("Category");
    }
}

SlSvcUtil.exeが常に false を返すReferenceEquals代わりにEqualsifを使用するのはなぜでしょうか?ReferenceEquals

4

2 に答える 2

2

Equalsまたは文字列を使用するかどうかは議論の余地があるようですReferenceEqualsEqualsは文字列の値を比較しますが、 はReferenceEquals参照を比較しますが、文字列のインターンにより、同等の文字列リテラルが同じ参照として出力されます。例えば:

    static void Main(string[] args)
    {
        string x = "hi", y = "hi", z = string.Concat('h', 'i');
        Console.WriteLine(ReferenceEquals(x, y));   // true
        Console.WriteLine(ReferenceEquals(x, z));   // false

        Console.WriteLine(Equals(x, y));   // true
        Console.WriteLine(Equals(x, z));   // true

        Console.ReadLine();
    }

では、コード生成アルゴリズムの作成者はどのように決定したのでしょうか? 私が考えることができるいくつかの考慮事項:

  • パフォーマンス:Object.Equals仮想メソッド呼び出しが必要です。これは、静的メソッドよりもパフォーマンスが低い可能性がありますObject.ReferenceEquals(参照型としてボックス化を必要としない文字列について話していることを考えると)。
  • 通常は、参照型に使用することをお勧めしますReferenceEquals。作成者は、文字列の特殊なケースについて別のコードを維持する価値がないと判断した可能性があります。
  • この特定の例では、使用ReferenceEquals防御的な選択であることにも注意してください。UsingReferenceEqualsは、上記のケース #2 でセッターが適用されることを保証しますが、using はその場合にセッターを適用しEqualsませ。おそらく、後者の動作が非常に検出しにくいバグを引き起こす可能性がある、いくつかのまれなケースを考え出すことができます。

とにかく、Resharper の警告は明らかに間違っています。 String値型ではなく参照型であり、(上記の例で示したように)実際には文字列値をReferenceEquals返すことができます。true

于 2014-10-30T21:17:19.340 に答える
1

@マッガーナグル

ただし、文字列のインターンにより、同等の文字列リテラルが同じ参照として出てきます

文字列は常にインターンされるとは限りません。インターンするには、コンパイル時に文字列値を知る必要があります。IE は文字列リテラルのみで、連結はインターンされます。また、.NET ランタイムのバージョン/ビルドごとにさまざまなインターンがあります。Microsoft の C# コンパイラ チームに所属していた Eric Lippertは、この問題について書いています。

値が等しいかどうかの 2 つの文字列の比較について。

if (String.CompareOrdinal (strA, strB) != 0) ...おそらく最も効率的です。

于 2016-01-08T08:14:26.127 に答える