views:

191

answers:

4

In my code, I have the the following objects:

  • ErrorManager - controls how errors are logged in the application
  • ConfigManager - controls how the configuration information is obtained

On the project I'm working on, the ErrorManager needs to pull configuration information using the ConfigManager instance while the ConfigManager uses the ErrorManager incase an error occurs.

At the moment, I'm doing the following in code:

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

Is there a way for me to clean up this circular reference of dependencies?

+1  A: 

Circular references are usually best cleaned up by refactoring a third class that both depend on. For instance, you might have something like this:

BootstrapConfigManager _bcm = new BootstrapConfigManager();
ErrorManager _errorManager = new CustomErrorManager(_bcm);
ConfigManager _configManager = new CustomConfigManager(_bcm, _errorManager);
Travis Jensen
A: 

Refactor your code. You can probably break up the classes to isolate a portion that you can initialize first and pass on to both the classes.

dirkgently
A: 

I would create a extension methods for each called AddRelationship, passing in the other object as the parameter.

The object passed would add the relationship and then call the AddRelationship method of the other:

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 the relationship using either object.

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

You should 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 references are a particularly good coding practice, but this should solve the question as asked.

BenAlabaster
While this would work as a possible solution, it wouldn't work from an IoC container standpoint from what I can tell; however, I'm still in the process of learning a couple different IoC containers so I could be wrong.
JamesEggers
Ah, you didn't specify that in your original question or I might not have posted. I haven't yet had time to investigate IoC containers or dependency injection due to other project requirements.
BenAlabaster
+2  A: 

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);

Now, the ConfigManager can can use the ready-to-run ErrorManager without a bootstrapping problem where the ErrorManager is not ready to handle errors.

Alex B