Circular dependencies
Asked Answered
I

13

46

I have 2 projects.

Project#2 has a reference to Project#1

Now I need to reference Project#2 in Project#1, but vs.net is complaining about a circular dependency.

Is there a way out of this?

Impromptu answered 12/1, 2010 at 21:36 Comment(0)
H
85

Absolutely not. Circular dependencies are a indication of bad design. I don't mean to be harsh. There are some ways out of this.

1) You can refactor common code to another project, say Project#0

2) You can fix your design, which is probably the way to go.

Uncle Bob has a good article on Packaging Principles which includes the Acyclic Dependencies Principle. http://www.objectmentor.com/resources/articles/granularity.pdf. Read this to know why cyclic dependencies are a bad thing.

Hatten answered 12/1, 2010 at 21:41 Comment(4)
A common fix is to depend on abstractions such as interfaces rather than concrete instances, and to move those abstractions to another assembly. But, really, think about your project structure and what really belongs where.Expletive
+1 for linked article. I split my one "Logger" package which encompassed an "Application usage log" set of classes and an "error logging" class into two separate packages (Most packages don't need to log application usage!), then linked the one that WAS circular back to the original. Back to a DAG. Should be required reading for all.Maund
@Expletive You are talking about the Dependency Inversion Principle (DIP) he mentions in the article? - I agree, you should probably try to find WHY the potential for circular dependency exists, and perhaps change elements of the design (if you can) before depending on abstractions.Maund
I'd say that what follows from the linked article isn't that circular dependencies are an indication of bad design, but rather that the circular dependency is the bad design itself. It's the circular dependency in itself that have negative consequences in regards of blurred responsibility, encapsulation of modules, compilation and package updates. So if you somehow could have circular dependencies without these drawbacks, there wouldn't be a problem. Semantics maybe, but I think it's worth the verbosity.Generation
D
17

Refactor your projects to take the common elements out into a "Project #0" which both Project #1 and Project #2 reference.

Davin answered 12/1, 2010 at 21:37 Comment(0)
C
8

Merge the two into one or redesign.

Clotildecloture answered 12/1, 2010 at 21:37 Comment(0)
A
5

This points to a problem in your design. If there is a genuine need for two or more of your types to be mutually aware then they should exist in the same assembly.

Anceline answered 12/1, 2010 at 21:37 Comment(5)
And if they need to be in different languages?Kingsize
Can you give an example?Anceline
[Obsolete example:] In VS 2008, only VB .NET can use exception filters, while only C# can use Linq expressions. It is not too hard to imagine a case where these appear in conflicting setups.Kingsize
I have a live example that I hesitate to share that I'm planning on solving with ILMerge or some similar tool.Kingsize
I still think that you probably have a design problem.Anceline
C
5

A circular dependency means that these are no longer two independent projects (because there it is impossible to build only one of them).

You need to either refactor so that you have only a one way dependency or you should merge them into a single project.

Claus answered 12/1, 2010 at 21:39 Comment(0)
J
4

Circular reference can be done as seen in a previous question, but you should not do it for the reasons everybody already stated here.

Jiggle answered 12/1, 2010 at 22:30 Comment(0)
R
3

No. Structure your projects properly. Try using some sort of ordering based on abstraction - low-level to high-level.

Reptilian answered 12/1, 2010 at 21:37 Comment(0)
F
3

Everyone will tell you this is a bad design do not do it etc. However sometimes it is easier said than done and moving the implementation into a separate common code is not desirable. For such cases instead of calling the other package directly, emit an event from one package and handle it in the other. That way you do no need to make the other component a dependency in the first component.

Another way if you still want to keep the implementation in separate packages is to derive your logic classes form interfaces and define those in a separate package. This works if you have a way to instantiate the implementation, for example via dependency injection or other means.

Fusibility answered 21/9, 2019 at 6:7 Comment(0)
B
1

I really don't mean to be a smart-aleck, but better program design is the answer.

Bulganin answered 12/1, 2010 at 21:37 Comment(0)
E
1

This seems to be a design flaw, nothing else. Re-design is the solution.

Elizabethelizabethan answered 13/1, 2010 at 5:11 Comment(0)
D
1

Contrary to what's been said before, circular dependencies are sometimes unavoidable. For sure there are benefits to linear designs (maintainability, readability, debugging etc.) but it makes no sense to give up circularity/bidirectionality if it is going to make you give up on splitting projects based on their functionality (which wouldn't help you maintain or understand the code).

Solution: You have to use a project with interfaces to which both of said projects reference to. Classes from higher level projects contain implement interfaces from the interface project. This way you can expose method implementations and classes in a circular manner.

Some pseudocode:

Project Interface

interface IApple { void dropOnHead(IPerson person);}
interface IPerson { void eatApple(IApple apple);}

Project#1

using ProjectInterfaces;
class Apple : IApple{
  void dropOnHead(IPerson person) { log("bop");}
}

Project#2

using ProjectInterfaces;
class Person : IPerson{
  void dropOnHead(IApple apple) { log("crunch");}
}

Domett answered 25/4, 2022 at 21:43 Comment(0)
E
0

In C++ you can forward declare class B, if class A depends on it. Something like that.

// segment.hpp
class Polygon;  // fwd declare

class Segment {
  public:
    bool Intersects(Polygon p);
};

and

// polygon.hpp
class Segment; // fwd declare

class Polygon {
  public:
    bool Intersects(Segment s);
};

While in C# you could create an extension module, far away from both. Something like that

// Segment.cs
namespace MyLib {

public class Segment {
  // ...
}

}

and

// Polygon .cs
namespace MyLib {

public class Polygon {
  // ...
}

}

and a third file

// Extensions.cs
namespace MyLib {

public static class Extensions {

   public static bool Intersects(this Segment s, Polygon p) { //... }
   public static bool Intersects(this Polygon p, Segments) => s.Intersects(p);

}

}

and then you will haver no circular dependencies and get this result.

// Program.cs

using MyLib; // that's all you need

namespace ConsoleApp {
  internal class Program {
    static void Main(string[] args) {

       var s = new Segment(...);
       var p = new Polygon(...);
       bool intersects = p.Intersects(s);

    }
  }
}
Exploit answered 20/2, 2023 at 20:4 Comment(0)
K
-5

I don't think it is a good solution but still we can do by following these steps

  • add the reference
  • browse and
  • go to Debug folder of dll project,
  • find the .dll and Add .
Konstanz answered 29/3, 2013 at 13:42 Comment(1)
don't do that! Follow what is indicated in the accepted answer!Maillot

© 2022 - 2024 — McMap. All rights reserved.