web-dev-qa-db-ja.com

C#で「静的」を使用しないでください。

書いたアプリケーションをコードレビューのために他のアーキテクトに提出しました。そのうちの1人がすぐに返信して「staticを使用しないでください。staticクラスとメソッドを使用して自動テストを作成することはできません。staticは避けてください。 」

チェックしたところ、クラスの1/4がstaticとマークされています。クラスはコード全体で使用される単一のグローバルクラスであるため、クラスのインスタンスを作成しない場合はstaticを使用します。

彼はさらに、静的コードでは使用できないモック、IOC/DIテクニックを含むことについて言及しました。彼は、サードパーティのライブラリがテスト不可能であるために静的である場合は残念だと言います。

この他の建築家は正しいですか?

更新:ここに例があります:

APIManager-このクラスは、次に許可される時間とともに、私が呼び出しているサードパーティAPIの辞書を保持します。多くのサードパーティが利用規約に定めているAPIの使用制限が適用されます。サードパーティのサービスを呼び出す場所であればどこでも、呼び出しを行う前にThread.Sleep(APIManager.GetWait("ProviderXYZ"));を呼び出して使用します。ここにあるものはすべてスレッドセーフであり、C#のTPLでうまく機能します。

113
Infin8Loop

静的クラスが状態を維持するかどうかによって異なります。個人的には、静的クラスで一緒にスローされるステートレス関数については問題ありません。

121
Larsenal

彼はそれについてあまりにも一般的です。彼は正しいです、それはテストを妨げます。ただし、staticクラスとメソッドにはそれらの場所があり、実際にはコンテキストに依存します。コード例がなければ、実際にはわかりません。

クラスはコード全体で使用される単一のグローバルクラスであるため、クラスのインスタンスを作成しない場合はstaticを使用します。

これは、コードの臭いがひどい場合があります。クラスを何のために使用していますか?データを保持するには?データベースにアクセスするには?それから彼は正しいです。そのような静的クラスは事実上暗黙的なシングルトンであるため、その場合は依存関係注入を調べる必要があります。

状態を変更せず、指定したパラメーターを操作するだけの拡張メソッドまたはヘルパーにそれらを使用している場合、通常は問題ありません。

96
Femaref

チェックしたところ、クラス全体の1/4が「静的」とマークされています。クラスはコード全体で使用される単一のグローバルクラスであるため、クラスのインスタンスを作成しない場合はstaticを使用します。

最善の方法は、コードをユニットテストしてみることです。繰り返し可能な独立したシンプルなテストを設計し、一度に1つのメソッドのみをテストしてください。別のランダム化された順序でテストを実行してみてください。安定した「グリーン」ビルドを入手できますか?

もしそうなら、それはあなたのコードを守るための有効なポイントです。ただし、問題がある場合は、インスタンスベースのメソッドを使用する必要があります。

31
oleksii

すでに投稿された回答は、多くの本当に良い点をカバーしていますが、欠けているように見えるものがあります:

静的フィールドはneverガベージコレクションされます。

これは、多くのメモリ制約があるアプリの場合に非常に重要です。このパターンは、人々がキャッシュを実装しようとするときに非常に一般的です。

静的関数はそれほど悪くはありませんが、他の誰もがすでに十分に詳細にこれをカバーしています。

11
riwalk

IoC/DIから得られる利点の1つは、クラス間のほとんどの対話がインターフェイス間でネゴシエートされることです。これにより、インターフェースを自動的または半自動で模擬できるため、ユニットテストが容易になり、各パーツの入力と出力をテストできます。さらに、テスト可能性を超えて、すべての間にインターフェイスを配置することで、可能な限りモジュール化されたコードを作成できます。依存関係を台無しにする心配をせずに、1つの実装を簡単に置き換えることができます。

C#にはメタクラスがないため、クラスは静的機能を使用してインターフェイスを実装できません。そのため、クラスの静的機能は、純粋なIoC/DIオブジェクトモデルを実装するための労力を無駄にします。つまり、それらをテストするためのモックを作成することはできず、実際の依存関係を作成する必要があります。

会社/プロジェクトがIoCの実行に多額の投資をしている場合、これは当然のことながら懸念事項であり、あなたが経験している苦痛はすべての人の利益のためです。しかし、建築の観点からすると、私は個人的に、どのモデルも墓に従うべきだとは思いません。静的メソッドを使用して実装することが理にかなっているいくつかのものがあります-シングルトン設計戦略など。静的クラスは、OOの利点を失いがちなので、私はあまり気になりませんが、ライブラリクラスがエンジンよりも自然な表現である場合があります。


コメンターは私に拡張メソッドを思い出させます。拡張メソッドはもちろんC#の静的クラスになければなりません。これは合法であり、少なくとも言語の幅を利用しようとしている場合は、純粋なIoCがC#でうまく機能しない例です。

10
jwrush

静的クラスは誤用されることがあり、次のようにする必要があります。

  • シングルトン(非静的クラスには静的メンバーとそれを1回だけ取得/作成するためのパブリック静的インスタンス変数があります。
  • 別のクラスのメソッド(状態が重要な場合)。そのクラスのデータを使用していないメンバーがある場合、おそらくそのクラスの一部であってはなりません。

また、いわゆる「ユーティリティ」関数であり、ユーティリティクラスの一部である場合もあります。ユーティリティクラスは、静的メソッドのみを含み、コンテキストなしでヘルパー関数として機能するクラスです。

5
Michel Keijzers

静的メソッドは使用に問題がなく、プログラミングにおいて正当な位置を占めています。建築家が静的メソッドを完全にサポートしていないテストフレームワークを持っているようです。コードがより大きなプロジェクトの一部である場合、アーキテクトのガイドラインを満たすことが重要です。ただし、適切な場合に、このプロジェクトが静的メソッドの使用を妨げないようにしてください。

4
k rey

クラスのすべてのインスタンスに共通するものに静的プロパティを使用しています。また、静的メソッドを使用してクラスオブジェクトのグループを取得しています。私は決して専門家ではありませんが、これまでのところ私のために働いています。

PHPの例:

class vendorData {
  private static $data_table = 'vendor_data'; // static property
  private $id; // instance property
  private $name; // instance property

  public function __construct($vendor_id) {
    if(!self::validId($vendor_id) ) { // static method
      return false; // id doesn't exist
    }
    $this->id = $vendor_id; // id has been validated
    $this->getProperties(); // object method
  }

  private static function validId($vendor_id) {
    // send db query to find if the id exists
    // return true/false;
  }

  private function getProperties() { // object method
    $sql = "SELECT * FROM `{self::$data_table}` // using static property
        WHERE `id` = {$this->id}"; // using object instance property
    // get resultset
    foreach($result as $property => $value) {
      $this->$property = $value; // object instance properties all set
    }
  }

  // and here
  public static function getBy($property,$value) { // static method to return object array
    $sql = "SELECT `id` FROM `{self::$data_table}` // using static property
      WHERE `$property` = '$value'";
    // send query, get $ids array
    $obj_array = array();
    foreach($ids as $id) {
      // create array of current class objects using special static keyword
      // meaning of static here is different than in property/method declarations
      $obj_array[$id] = new static($id);
    }
    return $obj_array;
  }
}
1
Buttle Butkus

彼らが持っている原則は大丈夫だと言いますが、ステートメント(静的を使用しないでください)は間違っている可能性があります。コードカバレッジはいくらですか?数値が高く、アプリの単体テストに問題がなければ、問題ありません。そうでない場合は、コードを確認することをお勧めします。あなたは静的クラスが理由であるかどうかを見つけるかもしれません、それは多くのものに依存します。

1
ivowiblo