Circular Dependency
Heyo :D,
So I have started getting into somewhat bigger projects again and needed to use Dependency Injections to loose coupling and overall tightness between classes. Since 2 of my classes (and likely in the future, more class depend on each other), it's a good approach to create abstractions to expose only a fraction of the class that other classes need to access. This way, I am not exposing it concretely. However, for some reason, I am running into a circular dependency exception which I don't seem to... really understand? I get where the issue is but I can't figure out a more plausible approach. I would appreciate some feedback on what potentially can be done.
To give the issue.. ILoggingManager depends on IYukkaifyEnvironment, which in turn depends on ILoggingManager..
37 Replies
To my eye, it looks like
LoggingManager
depends on IYukkaifyEnvironment
, but Yukkaify
(which the framework will attempt to create when you request IYukkaifyEnvironment
) depends on LoggingManager
-> circular dependency
Since 2 of my classes (and likely in the future, more class depend on each other), it's a good approach to create abstractions to expose only a fraction of the class that other classes need to accessFYI I've never heard of this practice the way you're implementing it. You should definitely have private fields / properties / methods that are implementation details and not publicly exposed, but this pattern of creating 'partial interfaces' is new to me. In your situation I would have a different concrete classes, one which implements IYukkaify and one which implements IYukkaifyEnvironment I'm not super experienced so I will stop short of saying it's wrong though
In most cases, your classes should not be dependent on one another. This is bad design.
that's true. circular dependency is bad design and i had thought about moving ClassA and ClassB function to ClassC and just use ClassC for things
but that would sort of ? be hacky and i'd rather keep things in their designated place
Not a question anyone can answer unless they know what you're using these interfaces for and what the intended functionality is.
But there's more issues than just co-dependency. Even your
ILoggingManager
interface refers to the implementation LoggerManager.DebugType
.So for instance, (and this probably sounds silly) but
Root
contains the path used to navigate the server and technically, i wouldn't need to reference the main class just to use Root
I'm assuming you're placing multiple interfaces and classes in the same file and there's really no point in doing that outside of encapsulated / hidden internal types.
i could move a new variable of
Root
to the class and just use thatOut of context this means nothing to me. I have no clue what your application does or what frameworks it is using.
currently using .NET Console Application 7.0
C# 12.0
but to explain
this is the root used to store things on the server. it acts as a path string.
i am using IYukkaify in other classes just to access
Root
without needing to copy the same Root
variable to other classes and use it privatelyAgain, what does "server' mean here? Is this a web project serving an API or remote file access?
Or some CLI utility?
the server is where the application is stored and running. in this case, an Ubuntu server
using
dotnet
to launch it and keep it up indefinitely
the Root
variable just tells me where the folders are on the server so i can read / write files on thereSounds like something that sould be set in a configuration file and passed around through some form of dependency injection.
i am actually doing something similar
Is this a web project? Are you using ASP.net?
no, a .NET console aplication
I had the pleasure to speak to someone in VC earlier and i was suggested to use ASP.NET
which seems like a great idea but I am currently not able to transition over as quick and get the hang of a ASP.NET application
especially because I would still need to learn how to utilize and manage dependencies
Well, either way, you should probably set up proper dependency injection as it will help you reduce this bad coupling and let you make better design decisions.
yes, i am reading up on stackoverflow right now but nothing gives me sort of a start on where I can improve my code in
like, i think the best thing for me is to learn how professionals manage their dependencies and how i can adapt to it
Not really an easy answer to that.
managing dependencies in a large-scale application is challenging, indeed
Well, the first thing you should do, at least in your current situation, is ask yourself why certain co-dependencies exist and then think of ways to abstract them.
is this a good starting point to learn: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/abstract
abstract - C# Reference - C#
abstract - C# Reference
IYukkaifyEnvironment
- why does this need a logger manager? And why does it need to be an interface?
This could work fine as a POCO that is read from some configuration file.so IYukkaifyEnvironment does not need a logger, what I wanna achieve is to access the variable
Root
wherever needed without doing
instead, i wanna do
Yes, that is what I was referring to when I said "This could work fine as a POCO that is read from some configuration file."
however, i have many classes such as ClassX is dependend on ClassY but ClassY has an instance of ClassB which in turn has an instance of ClassY
and it repeats the cycle
ultimately, i wanna access class functions in other classes such as the logmanager which has useful utilities
because you have a very poorly designed application
but i don't wanna create new instances whenever i need it because calling that class would also instantiate logmanager
pretty much access LogManager's functions without instantiating it so it doesn't create an instance of it when i call that class
i could make those classes
static
?No.
First things first, learn the basics around dependency injection so you know what you can and cannot do with it. Then look back at what you have and start trying to fix your design.
For example, you could do something like this:
so the purpose of YukkaifyConfiguration is to.? declare YukkaifyEnvironment or
To read the application's config from a file and create
YukkaifyConfiguration
and expose it to the rest of the application.i see.
With dependency injection you'd also be able to remove your
LoggerManager
entirely. (note this would require some additional code to configure logging properly)
isn't ILogger a part of SeriLog?
I am referring to
ILogger
from Microsoft.Extensions.Logging
.I see, but using an extension for differentl logging would only resolve the issue I have with loggingmanager's circular dependency. it wouldn't resolve future dependency issues which im trying to figure out
Designing things with the methods demonstrated above would absolutely help.
i will try to look into it
quite frankly, I ended up using
Quickwire
which is the same set up in Startup but you declare [RegisterService]
on top of your class and [InjectService]
to use it with no problem