web-dev-qa-db-ja.com

循環参照を解決する方法は?

クラスAのプロパティの1つとしてクラスBがあり、クラスBのプロパティの1つとしてクラスAがあるような循環参照問題をどのように解決しますか?

これらの種類の問題をどのように設計するのですか?

NHibernateを例にとると、オブジェクト間に親子関係があります。

どのようにしてそれらの親子シナリオを処理できますか?

23
user145610

2つのものを相互に参照させる必要があったほとんどの場合、循環参照を削除するためのインターフェースを作成しました。例えば:

[〜#〜]前[〜#〜]

public class Foo
{
    Bar myBar;
}

public class Bar
{
    Foo myFoo;
}

依存関係グラフ:

Foo     Bar
 ^       ^
 |       |
Bar     Foo

FooはBarに依存していますが、BarもFooに依存しています。それらが別のアセンブリにある場合、特にクリーンな再構築を行う場合、構築に問題があります。

[〜#〜]後[〜#〜]

public interface IBar
{
}

public class Foo
{
    IBar myBar;
}

public class Bar : IBar
{
    Foo myFoo;
}

依存関係グラフ:

Foo, IBar     IBar
    ^          ^
    |          |
   Bar        Foo

FooとBarはどちらもIBarに依存しています。循環依存はなく、IBarが独自のアセンブリに配置されている場合、FooとBarが別々のアセンブリにあることは問題ではなくなります。

30
Ed Bayiates

私はあなたの友人に彼が彼のデザインを再考する必要があると言います。あなたが説明するような循環参照は、しばしば設計上の欠陥のコード臭いです。

7
John Kraft

C++(たとえば)とは異なり、C#は循環参照を解決するために前方宣言を必要としません。したがって:

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

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

ただし、これは多くの場合、疑わしい設計決定の指標です。

5
Anton Gogolev

ほとんどの場合、最善の解決策は、設計を変更して循環依存を回避することです。たとえば、次のいずれかを実行できます。

  1. 共通参照コードをソリューションのユーティリティプロジェクトに移動し、他のプロジェクトにユーティリティプロジェクトを参照させる
  2. 彼の回答で「Ed Bayiates」によって説明されているインターフェースを使用してください。
  3. 少量の単純/共通コードの場合は、クラスの1つに書き直して、循環依存関係で参照する必要がないようにします。 (私の最も好きではない)

ただし、多くのプロジェクトを含むソリューションで作業していて、コードを所有していないために上記の変更のいずれかを行うことができない場合は、実装するのが困難であるか、修正する価値がありません。次に、このメソッドを使用できます:

プロジェクト参照を右クリックし、[参照の追加...]を選択します。次に、表示されるダイアログウィンドウで、[参照]タブと[参照]ボタンに切り替えます。そこからDLL=を見つけて選択します。これはせいぜい回避策であり、特に両方のDLLが頻繁に更新されている場合や、多くの依存関係がある場合に、ビルドの問題を引き起こす可能性があります。この方法はお勧めしませんが、ピンチで機能します。

フィッシュ

1
gadildafissh

ただし、多くのことのアーキテクチャをやり直すよりも迅速な解決策を探している場合は、すべてのデータ構造を保持する1つのDLLクラスライブラリを構築してみてください。メインプロジェクトは、そのデータを必要とするUIを保持し、次に、必要な他のDLLを保持します。追加することで、データ構造dllにもアクセスできるため、実行に必要なすべての情報を取得できますが、分離することもできます。これは、トライフォース設計パターンと呼ばれます。

0
enf folife

循環参照は、2つ以上の相互依存するリソースがロック状態を引き起こしたときに発生します。これにより、リソースが使用できなくなります。

C#で循環参照の問題を処理するには、ガベージコレクションを使用する必要があります。循環参照を検出して収集します。ガベージコレクターは、ローカルおよび静的で始まり、子を介して到達できる各オブジェクトをマークします。

これにより、循環参照の問題を処理できます。

次のクラスが循環参照しているとしましょう。ここでそれらの両方は互いに依存しています-

public class A
        {
            B Two;
        }
public class B
        {
            A one;
        }

問題を解決するには、インターフェイスを作成します-

public interface myInterface {
}

public class A {
   myInterface Two;
}

public class B: myInterface {
   A one;
}
0
Anshul