13

ProjectA(ConsoleApplication)とProjectB(ClassLibrary)という名前のソリューションに2つのプロジェクトがあります。ProjectAにはProjectBへの参照があります。一般的に、ProjectAはProjectBのメソッドを呼び出して、いくつかの処理を実行し、結果をProjectAに返します。ただし、ProjectBがProjectAに「追加の」情報を送信する必要がある場合があります(より具体的にはConsole.WriteLine()、ProjectAのメソッドを呼び出すため)。これを実現するには、ProjectBでProjectAを参照する必要がありますが、これを実行しようとすると、次のエラーが発生します。

A reference to ProjectA could not be added. Adding this project as a reference would cause a circular dependency

カップリングの概念全体を理解しており、このメッセージを受け取ることは理にかなっていますが、場合によってはProjectAに追加情報を送信する必要があります。何か案は?

4

4 に答える 4

15

正常にコンパイルされる循環依存関係を持つプロジェクトを作成することは実際には可能ですが、私は強くお勧めしません。代わりに、非循環的な依存関係グラフを持つようにプロジェクトを編成してください。

この問題を解決するにはいくつかの方法があり、そのうちのいくつかは他の回答で言及されています。まだ投稿されていないのは、プロジェクト A とプロジェクト B の間の依存関係を完全に排除し、A と B が通信するインターフェイスを定義する3 番目のプロジェクト C を作成することです。あれは:

namespace C
{
    public interface IFoo { void Frob(); }
    public interface IBar { void Qux(); }
}

次に、プロジェクト A と B がプロジェクト C を参照するようにし、それらのクラスが IFoo、IBar などを実装するようにします。プロジェクト A のメソッドがプロジェクト B のオブジェクトで Frob を呼び出す必要がある場合、B のクラスを取得するのではなく、IFoo を取得することによって行います。

それは理にかなっていますか?

于 2012-12-27T01:59:20.183 に答える
10

イベントとリスナーを使用することをお勧めします。たとえば、ProjectBからメッセージを送信できますがTrace.WriteLine、ProjectAではトレースのサブスクライバーを追加します。.NETには、メッセージをコンソールConsoleTraceListenerにルーティングするためのクラスがすでに用意されています。TraceProjectAから次の方法でリスナーを追加できます。

Trace.Listeners.Add(new ConsoleTraceListener());

または、統合クラスを使用したくない場合は、ProjectBで非常に単純な「ソース」クラスAction<string>を作成して、署名としてイベントを公開できます(ただし、そのデリゲートを作成することをお勧めします)。次に、ProjectAからサブスクライブします。一般に、.NETクラスはより柔軟です。

ProjectB

public static class MyTrace
{
    public static event Action<string> MessageReceived;

    internal static void Broadcast(string message)
    {
        if (MessageReceived != null) MessageReceived(message);
    }
}

ProjectA

MyTrace.MessageReceived += s =>
{
    /*Operate*/
};
于 2012-12-27T01:15:01.670 に答える
1

あなたはこれを行うことはできません。プロジェクトが相互に呼び出す場合、それらは同じプロジェクト内にある必要があります。または、ProjectBがProjectAを呼び出す代わりに、ProjectBはその情報を公開して、ProjectAがそれにアクセスできるようにすることができます。

循環依存を持つことはできません。なんてことするんですか?コンパイラはどのようにして最初にビルドするかを知るのでしょうか?基本的な設計上の問題があり、それを修正する必要があります。

于 2012-12-27T01:15:20.547 に答える
0

私は実際に ClassB で独自のイベントを作成します

public event EventHandler MySpecialHook;

EventHandler は、の標準デリゲートです。

public delegate void EventHandler(object sender, EventArgs e);

次に、クラス A で ClassB のインスタンスを作成した後、イベント ハンドラーにフックして、A が知っておくべき何かが B で発生したときに通知します。OnActivated、OnLostFocus、OnMouseMove などのイベントによく似ています (ただし、デリゲートのシグネチャは異なります)。

public class ClassB {

public event EventHandler MySpecialHook;

public void SomeMethodDoingActionInB()
{

    // do whatever you need to.
    // THEN, if anyone is listening (via the class A sample below)
    // broadcast to anyone listening that this thing was done and 
    // they can then grab / do whatever with results or any other 
    // properties from this class as needed.
    if( MySpecialHook != null )
        MySpecialHook( this, null );
 } 
}

public class YourClassA
{

   ClassB YourObjectToB;

   public YourClassA
   {
      // create your class
      YourObjectToB = new ClassB();
      // tell Class B to call your "NotificationFromClassB" method
      // when such event requires it
      YourObjectToB += NotificationFromClassB;
   }

   public void NotificationFromClassB( object sender, EventArgs e )
   {
      // Your ClassB did something that your "A" class needs to work on / with.
      // the "sender" object parameter IS your ClassB that broadcast the notification.
   }
}
于 2012-12-27T01:35:55.507 に答える