9

私は次のようなコードを持っています。

class MyController
{
    [ThreadStatic] private DbInterface db;

    public void ImportAllData()
    {
        using (db = new DbInterface())
        {
            var records = PullData();
            PushData(records);
        }
    }

    private DbRecord[] PullData()
    {
        return db.GetFromTableA();
    }

    private void PushData(DbRecord[] records)
    {
        db.InsertIntoTableB(records);
    }
}

代替案は、維持するのがはるかに面倒です。

class MyController
{
    public void ImportAllData()
    {
        using (var db = new DbInterface())
        {
            var records = PullData(db);
            PushData(records, db);
        }
    }

    private DbRecord[] PullData(DbInterface db)
    {
        return db.GetFromTableA();
    }

    private void PushData(DbRecord[] records, DbInterface db)
    {
        db.InsertIntoTableB(records);
    }
}

私が見る限り、私の最初の実装は次のとおりです。

  • スレッドセーフです(スレッドセーフであると仮定しDbInterfaceます)、
  • 他のプロセスがdb変数に触れるのを防ぎ、
  • db例外が発生した場合でも、常に破棄されます。

usingクラススコープを持つ変数でステートメントを使用するのは悪い習慣ですか?私は何かを逃したことがありますか?

4

4 に答える 4

10

個人的には、あなたの 2 番目のオプションをお勧めします。

最初の設計の問題は、設計に不要なカップリングを効果的に追加することです。PullDataメソッドとPushDataメソッドを単独で使用することはできません。変数をセットアップして適切にクリーンアップするメソッドまたはその他のメソッドを最初に呼び出す必要があります。ImportAllDatadb

2 番目のオプションは、わずかにコードが増えますが (それほど多くはありません)、すべてのメソッドの意図が非常に明確になります。DbInterface各メソッドは、渡された外部インスタンスで動作する必要があることを認識しています。これが将来悪用される可能性はほとんど、またはまったくありません。

于 2013-02-12T00:51:59.863 に答える
8

最初のバリアントは、ブロックdbによって管理されるスコープ外に公開されます。usingこれにより、意図しない副作用の可能性が生じます。たとえば、別のメソッドが db を使用したり、破棄したりする場合があります。これは、あなたまたは後のメンテナーが暗黙の契約を忘れた場合、dbまたはコードのタイプミスによって発生する可能性があります。

最初のバリアントは使用しません。

于 2013-02-12T00:52:02.193 に答える
4

代替案は次のとおりです。

sealed class MyImporter
{
    private readonly DbInterface db;

    public MyImporter(DbInterface db)
    {
        this.db = db;
    }

    public void ImportAllData()
    {
        var records = PullData();
        PushData(records);
    }

    private DbRecord[] PullData()
    {
        return db.GetFromTableA();
    }

    private void PushData(DbRecord[] records)
    {
        db.InsertIntoTableB(records);
    }
}

この場合、参照を保持することは、クラスの責任の明確な部分です。また、廃棄の責任をユーザーに押し付けています。このより明示的な構成により、「コントローラー」に追加機能を追加する誘惑が減ります。これは、最初のアプローチが長期的にはうまくいかない可能性がある方法です。基本的に、共有フィールド アクセスが問題にならないように、Import 関数を別のクラスにリファクタリングしました。

于 2013-02-12T00:58:47.843 に答える
0

それが、コンストラクトが存在する理由です。プロパティへの using の挿入には注意が必要です。慣例により、プロパティへのアクセスは軽量であり、変数にアクセスしているだけだとユーザーが考えるときに、必ずしも作成と破棄のサイクルをトリガーしたくないからです。

ただし、コードの構造に関する以下のコメントは重要です。一度インポートを実行したい場合は、ユーザーが知っておく必要があるセットアップ手順になります。さまざまなアクセス パターンを想定できる場合、依存性注入の設定により、ユーザーは接続の作成と破棄を制御できます。

于 2013-02-12T01:15:04.500 に答える