Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Circular Dependency in Two Projects in C#

I have two projects in a solution named ProjectA (ConsoleApplication) and ProjectB (ClassLibrary). ProjectA has a reference to ProjectB. Generally speaking, ProjectA calls a method in ProjectB to do some stuff and return the results to ProjectA. Sometimes however, I need ProjectB to send some "additional" information to ProjectA (more specifically to call the Console.WriteLine() method in ProjectA). To achieve this, I need to refer ProjectA in ProjectB, but when I try to do that, I get the following error:

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

I understand the whole coupling concept and it does make sense to get this message, however, I need to send additional information to ProjectA in some cases. Any ideas?

like image 838
PoweredByOrange Avatar asked Dec 27 '12 01:12

PoweredByOrange


2 Answers

It is actually possible to create projects that have circular dependencies that compile successfully but I strongly recommend against it. Instead, organize your projects so that they have an acyclic dependency graph.

There are a number of ways to solve this problem, several of which have been mentioned in other answers. One not yet posted is to eliminate the dependency between project A and project B entirely, and create a third project, C, that defines the interfaces that A and B communicate over. That is:

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

And then make projects A and B reference project C, and make their classes implement IFoo, IBar, and so on. When a method in project A needs to call Frob on an object in project B, it does so by obtaining an IFoo, rather than obtaining some class in B.

Does that make sense?

like image 195
Eric Lippert Avatar answered Oct 27 '22 10:10

Eric Lippert


I suggest you to use events and listeners. You can, for example, send messages from ProjectB through Trace.WriteLine while, in ProjectA, you would add a subscriber for the trace. .NET already offers a ConsoleTraceListener class, to route Trace messages to the Console. You can add a listener from ProjectA through:

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

Alternatively, if you don't want to use the integrated classes, you can build a very simple "source" class in ProjectB which will exposes an event with Action<string> as its signature (although I'd suggest you to create a delegate for it), then subscribe to it from ProjectA. Generally, .NET classes are more flexible.

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*/
};
like image 36
Mir Avatar answered Oct 27 '22 12:10

Mir