C#中两个项目的循环依赖

时间:2012-12-27 01:12:33

标签: c# circular-dependency

我在一个名为ProjectA(ConsoleApplication)和ProjectB(ClassLibrary)的解决方案中有两个项目。 ProjectA引用了ProjectB。一般来说,ProjectA调用ProjectB中的方法来执行一些操作并将结果返回给ProjectA。但有时,我需要ProjectB向ProjectA发送一些“附加”信息(更具体地说是在ProjectA中调用Console.WriteLine()方法)。为此,我需要在ProjectB中引用ProjectA,但是当我尝试这样做时,我收到以下错误:

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

我理解整个耦合概念,并且获取此消息确实有意义,但是,在某些情况下,我需要向ProjectA发送其他信息。有什么想法吗?

4 个答案:

答案 0 :(得分:15)

实际上可以创建具有循环依赖关系的项目,这些项目已成功编译,但我强烈建议不要使用它。相反,组织您的项目,使他们有一个非循环依赖图。

有许多方法可以解决这个问题,其他几个问题已在其他答案中提到过。尚未发布的是完全消除项目A和项目B之间的依赖关系,并创建一个第三个​​项目C,它定义了A和B通信的接口。那就是:

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

然后使项目A和B引用项目C,并使其类实现IFoo,IBar等。当项目A中的方法需要在项目B中的对象上调用Frob时,它通过获取IFoo而不是在B中获取某个类来实现。

这有意义吗?

答案 1 :(得分:10)

我建议你使用事件和听众。例如,您可以通过Trace.WriteLine从ProjectB发送消息,而在ProjectA中,您可以为跟踪添加订户。 .NET已经提供了ConsoleTraceListener类,用于将Trace消息路由到控制台。您可以通过以下方式从ProjectA添加侦听器:

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

或者,如果您不想使用集成类,可以在ProjectB中构建一个非常简单的“源”类,它将以Action<string>作为其签名公开事件(尽管我建议您为它创建一个委托),然后从ProjectA订阅它。通常,.NET类更灵活。

<强>项目B

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

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

<强>项目A

MyTrace.MessageReceived += s =>
{
    /*Operate*/
};

答案 2 :(得分:1)

你不能这样做。如果项目互相调用,它们应该在同一个项目中。或者,ProjectB可以将其信息公开,而不是ProjectB调用ProjectA,因此ProjectA可以访问它。

您不能拥有循环依赖关系。你怎么能?编译器如何知道首先构建哪个?你有一个基本的设计问题,那就是需要解决的问题。

答案 3 :(得分: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.
   }
}