What is the best way to handle circular dependencies between objects?

In my code, I have the following objects:

  • ErrorManager - determines how errors are written to the application
  • ConfigManager - determines how configuration information is received

In the project I'm working on, ErrorManager should retrieve configuration information using an instance of ConfigManager, while ConfigManager uses ErrorManager if an error occurs.

I am currently doing the following in code:

ErrorManager _errorManager = new CustomErrorManager(); ConfigManager _configManager = new CustomConfigManager(_errorManager); _errorManager.SetConfigurationManager(_configManager); 

Is there a way to clear this circular dependency link?

+6
dependency-injection dependencies
source share
4 answers

I would create the following:

 ErrorConfig _errorConfig = ...; // ErrorConfig is a new config object containing only ErrorManager Configuration ErrorManager _errorManager = new CustomErrorManager(_errorConfig); ConfigManager _configManager = new CustomConfigManager(_errorManager); 

ConfigManager can now use the ConfigManager , which is ready to run, without a boot problem, where ErrorManager not ready to handle errors.

+3
source share

Circular links are usually best cleared by refactoring the third class, on which both depend. For example, you might have something like this:

 BootstrapConfigManager _bcm = new BootstrapConfigManager(); ErrorManager _errorManager = new CustomErrorManager(_bcm); ConfigManager _configManager = new CustomConfigManager(_bcm, _errorManager); 
+2
source share

Recover your code. You can probably break up classes to isolate the part you can initialize first, and go to both classes.

0
source share

I would create extension methods for each AddRelationship called, passing another object as this object.

The passed object will add the link, and then call the AddRelationship method of another:

 static void AddRelationship(this ConfigManager configMgr, ErrorManager errMgr) { this.ErrorManager = errMgr; if (this != errMgr.ConfigManager) errMgr.AddRelationship(this); } static void AddRelationship(this ErrorManager errMgr, ConfigManager configMgr) { this.ConfigManager = configMgr; if (this != configManager.errMgr) configMgr.AddRelationship(this); } 

This means that you can add relationships using any object.

 ConfigManager cfg = new ConfigManager(); ErrorManager err = new ErrorManager(); //Assign using either: err.AddRelationship(cfg); //Or cfg.AddRelationship(err); 

You must also create RemoveRelationship extensions.

 static void RemoveRelationship(this ConfigManager configMgr, ErrorManager errMgr) { if (this.errorManager == errMgr) { this.errorManager = null; if (errManager.configManager == this) errMgr.RemoveRelationship(this); } } static void RemoveRelationship(this ErrorManager errMgr, ConfigManager cfgMgr) { if (this.ConfigManager == cfgMgr) { this.configManager = null; if (cfgMgr.errorManager == this) cfgMgr.RemoveRelationship(this); } } 

I don’t know that circular links are a particularly good coding practice, but this should solve the problem on a mission.

0
source share

All Articles