26

次のコードを検討してください。

class C
{
    public int A { get; set; }
    public int B;

    public C(int a, int b)
    {
        this.A = A;    // Oops, bug! Should be `this.A = a`. No warning
        this.B = B;    // Oops, bug! Should be `this.B = b`. `warning CS1717: Assignment made to same variable; did you mean to assign something else?`
    }
}

ABほぼ同じものですが、見逃してしまうバグがあります。

コンパイル時に最初のケースをキャッチする方法はありますか?

編集:いくつかの回答とコメントは、プロパティとフィールドが同じものではないことを私に説明したいと思っています。私はすでにそれを知っています。彼らは、コンパイラがここで警告を出さない理由を説明しています。わかりました。しかし、私はバグを書きました。バグを書くのは好きではありません。だから私の質問は、「このバグを二度と書かないようにするにはどうすればよいですか?

4

7 に答える 7

6

FxCop などのツールを使用して、VisitAssignmentStatement を使用してカスタム ルールを作成することも できます


于 2012-10-26T05:44:51.060 に答える
4

あなたは言ったA = AB = B同じですが、これは真実ではありません!プロパティのゲッターとセッターA = Aを変更できるため、次の例のように変数を変更できます。

public Int32 A
{
    get { return _A++; }
    set { _A = value; }
}

したがって、コンパイラはそれが間違いかどうかわかりません。もちろん、このようなコードを扱うのは簡単ではないため (たとえば、アセンブリがあり、A が毎回変更される理由がわからない場合)、そのようなプロパティの明示的なセッターを公開することは避けます。以下のようなものを好む:

public UInt32 UniqueID { get { _UniqueID++; } }

public void Reset()
{
    _UniqueID = 0;
}

結論

コンパイル時エラーはここでは意味がありません。なぜなら、コンパイラはプロパティで何が起こるかを知らないからです (覚えておいてください:プロパティは 2 つのメソッド単純化したものにすぎset_MyPropertyget_MyPropertyません)。行動も変わるかもしれません。

(編集) 誤解を招くような命名を避ける

プロパティとパラメーターは、あなたがやっているのと同じ方法で書きます。したがって、単純なクラスがどのように見えるかの例として:

public class MyClass
{
    public Int32 Sample { get; private set; }

    public MyClass(Int32 sample)
    {
        Sample = sample;
    }
}

私はあなたと同じ罠に毎週約1回は陥っているので、名前を変えることは考えていませんでした. ただし、使用できるもののいくつかの提案があります。

  • p(arameter) をプレフィックスとして使用しますが、コードが判読不能になるため、これはお勧めしません。
  • 後置として使用valueしてください。これは私にとっては問題ないようです。そのため、(プロパティの名前)とは異なるものをsample使用する代わりに、パラメータ名の代わりにプロパティ名が使用されているかどうかを簡単に検出できます。sampleValueSample
  • _プレフィックスとして使用します。メンバーへの高速アクセスを有効にするためにメンバーのプレフィックスとして既に使用_しており、インテリセンスが奇妙に見えるようになっているため、使用しません。

これは、個人または会社のコーディングスタイルに完全に依存すると思いますが、個人的には後置として使用Valueします。

于 2012-10-29T08:37:25.430 に答える
4

ジェイ、

素晴らしい質問です。関連するポイントのほとんどはさまざまな回答でカバーされていると思いますが、要約するだけです。

  1. これを暗黙的に処理する方法はありません。.Net コンパイラは再帰的なプロパティを許可しますが、これがこの問題の核心です (それを「キャプチャ」できないという点で)。この質問に従って、変更される可能性は低いことに注意してください。
  2. そのため、この「バグ」のキャプチャを強制したい場合は、サード パーティのツールを使用して明示的に行う必要があります。私は他の多くの人と同じように ReSharper のファンであり、必要に応じてプロパティの再帰を強調することができます。また、他の人が言及したように、FXCop を効果的な単体テスト パターンと共に使用すると、そのようなバグの発生を防ぐことにも役立ちます。
  3. 命名規則は王様です。故意に「役に立たない」(!) 変数とプロパティの命名を使用した例を提供することで、効果的な命名規則を使用する必要がある理由を正確に強調しました。あなたが強調した問題は、私たち全員を捕らえたものであり、コードベースが成長するにつれてより広範になります.

あなたが望んでいた答えではないかもしれませんが、ここで最も重要な点は 3 だと思います。アイテムに適切な名前を付けることが、最も効果的な唯一の解決策です。それだけでなく、人々は ReSharper やその他のツールに頼る余裕がないかもしれません。

そのために、 StyleCopもお勧めします。少し侵略的かもしれませんが、開発者または開発者チームが一連の構文規則を順守するのに役立つ優れたツールであり、強調表示したようなバグを非常に迅速に根絶します。

ハッピーコーディング!

于 2012-11-01T16:57:10.913 に答える
4

これは鋳鉄ではありませんが、ReSharper をインストールし、「未使用のパラメーター」の検査を「エラー」に設定し、さらにソリューション全体の分析をオンにすると、コード ウィンドウに次のように表示されます。

ここに画像の説明を入力

右マージンにあるこれらの赤いインジケータの 1 つ:

ここに画像の説明を入力

そして、これはステータスバーの下にあります:

ここに画像の説明を入力

これらを組み合わせることで、ReSharper ユーザーとしてすぐに無視できなくなるコンボを作成できます :)

ただし、コンパイルを止めることはありません。

于 2012-11-01T13:56:21.137 に答える
2

上記のすべての回答に加えて、プロジェクトのプロパティのビルドタブで、特定の警告のみを入力して「警告をエラーとして扱う」を有効にすることもできます。コマンド ライン コンパイラを使用している場合は、次を使用します。

csc /warnaserror C.cs

csc /warnaserror:1717 C.cs

ドキュメントから: http://msdn.microsoft.com/en-us/library/406xhdz3.aspx

これにより、すべての警告または指定した警告でビルドが失敗します。

于 2012-11-02T20:50:02.983 に答える
1

順不同:

  1. VB.NET を使用する

  2. コードの単体テストを行います。

  3. ReSharper を使用し、「修飾子 'this' は冗長です」というプロンプトを受け入れてから、警告を探します。Assignment made to same variable; did you mean to assign something else?

  4. FxCop の提案を見て、イントロスペクションを使用したカスタム コード分析ルールは言及する価値があると思いました。

  5. より良い変数名を使用して、パラメーターとメンバーを識別します。このヒントは確かにハイテクではありません。私はよく、変数を定数、数値、または条件ステートメント内の関数の戻り値と比較します。少し読みにくいですが、左辺値として使用できないオペランドを == 演算子の左側に配置する習慣があり、== 演算子の 2 番目の等号を入力するのを忘れています。後で論理エラーを追跡する必要がある (5 分間の修正) のではなく、(明らかな以上の) コンパイラ エラー (5 秒の修正) が発生します。この点は、お尻を噛んだばかりの非常に小さな構文エラーに関連していると思います。

多くの C# 開発者は、最初の文字を小文字にすることを除いて、型の名前と同じように変数を宣言します。この習慣は、あなたが変えたいと思うものかもしれません。

于 2012-10-31T05:37:24.820 に答える
0

フィールドの自己割り当てthis.B = B;が間違っているのはなぜですか? それは何もしないからです。this.BBまったく同じことです。

プロパティの自己割り当てがthis.A = A;間違っていないのはなぜですか? の意味は、演算子Aのどちら側に立つかによって異なるためです。=コンパイラがこのコードをどのように認識するかを検討してください。

set_A(get_A());

これは、2 つの異なるメソッドの呼び出しです。電話するなら警告だと思いますFoo(Bar());か?コンパイラも同様です。getter でバッキング ストアを変更するのは良くありませんが、プロパティを考慮して、読み取り数をカウントしたり、ログを記録したり、その他のロジックを配置したりします。コンパイラがこれについて警告するのはなぜですか?

public int A
{
    get 
    {
       _log.Debug("Property A accessed by some user");
       _readingsCount++;
       // your logic goes here
       return _a;
    }    
}
于 2012-10-29T08:59:26.667 に答える