views:

90

answers:

3

I am developing a C# application and have an Employee class and an Organisation class.

An Employee object has an Organisation as an internal member and an Organisation object has an Employee member to indicate the Org leader.

Will there be any problems with this setup that can lead to an infinite circular instantiations?

Edit:

I just tried it running the code and there seems to be a problem. The employee object instantiates an Organisation object and an Organisation object tries to instantiate an employee object. They both connect to a database to fill in their details

This keeps happening until my SQL server runs out of connections. Is there any alternative to what I am doing?

+4  A: 

No. It will compile fine. The C# compiler is smart enough to take all the types into account even if they are "not yet compiled". Like Java, the Definition/Declaration are one-and-the-same (this differs from, say, C/C++).

pst
It compiles file, but it keeps running until my SQL server runs out of connections. See edit
TP
While your answer is correct, with respect to default initialization of reference types, you missed a key component of his question: "Will there be any problems with this setup that can lead to an infinite circular instantiations?"
Merlyn Morgan-Graham
@Merlyn Good point.
pst
+2  A: 

Will there be any problems with this setup that can lead to an infinite circular instantiations?

Reference types are null by default. Unless you instantiate a new instance and assign it to that variable, then no code is called for that type.

Do each of the constructors construct an instance of the other object? Is it possible that they could in the future (possibly on accident)? If so, then yes, you can hit the scenario you are talking about:

class A
{
  public A()
  {
    this.B = new B();
  }
  public B B;
}

class B
{
  public A A = new A(); // This is the same as instantiating the object in the ctor
}

// ...

A obj = new A(); // This calls new B, which calls new A, repeat ad infinitum

You can break a cycle like this by instantiating the instance of the other object outside of the constructor. For example, on first access:

class A
{
  public A()
  {
  }

  public B B
  {
    get
    {
      if(b == null)
        b = new B();
      return b;
    }
  }

  private B b;
}

class B
{
  public B()
  {
  }

  public A A
  {
    get
    {
      if(a == null)
        a = new A();
      return a;
    }
  }

  private A a;
}

// ...

A obj = new A(); // new B doesn't get called yet
obj.B.Something(); // ... Now it does...

You'll still have to be careful that class A doesn't access it's own this.B property inside its constructor, and vice-versa. You can access these properties in methods all you want, though, as long as those methods aren't called inside the constructor.

Another option is to do dependency injection. This is where you pass a dependency to an object, instead of letting it instantiate the object itself:

class A
{
  public A(B b)
  {
    this.B = b;
  }

  public B B;
}

class B
{
  public B(A a)
  {
    this.A = a;
  }

  public A A;
}

// ...

A someA = new A(
  new B(
    null)); // You have to break the cycle somewhere...
someA.B.A = someA;

// or ...

class ABFactory
{
  public static A CreateA(/* options for a */, /* options for b */)
  {
    A result = new A(
      new B(
        null));
    result.B.A = result;
    return result;
  }
}

Note that dependency injection wasn't invented to solve this problem, but it would work in this scenario. With it, you could rest easy, knowing that you would never hit this issue again.

Merlyn Morgan-Graham
Why not `A someA = new A(new B(someA))`? Does that work in C#?
Christian Mann
@Christian Mann: I don't know for sure (and it might be undefined behavior?) but it would probably do the same thing - pass `null` to `new B()`, because `someA` is not constructed until *after* `new B` is executed.
Merlyn Morgan-Graham
+1  A: 

The problem you are experiencing is unlikely to be C# itself, but probably that your code is getting into an infinite loop where the Organisation is asking the Employee for information that causes the Employee to ask the Organisation for the same information again...

All you should need to do is break this link, so that requesting information on the Organisation does not chain the call on to its Employees (and vice versa). i.e If you want the full information on an organisation, instead of

org.GetAbsolutelyAllInformation();

you would call

org.GetOrganisationInformation();
org.Leader.GetEmployeeInformation();

If you must return the information in one lump, then rather than returning the information in a new object, pass in a "blank" object to be filled in. If you are called with an object that is already filled in, return the cached information rather than fetching it from the database again. That way, it won't matter which order your methods are called, they will just fill in the org or leader information in the object you pass in, and the "loop" will be stopped on the next iteration when it's found that all the information has been filled in.

In general, one way to reduce the risk of this sort of loop happening in the first place would be for the organisation's "Leader" to be an ID (e.g. employee number) rather than a direct reference. This encourages any programmer using this code to get the leader ID and then look up the leader's information as a separate step.

Jason Williams
If you read his question closely, he shows that it is (currently) just a problem with instantiation. But you are right that this is a problem he will need to look out for in the future, and is a danger with any sort of cyclic dependency.
Merlyn Morgan-Graham