views:

181

answers:

1

Hi,

The point of this exercise is to make navigation between objects stateful.

For example, having Person and Address with 1-1 association it should:

  • If an address is assigned to a persons, then the person should be assigned to the address (and vice versa).
  • If address is assigned to person1 and then to person2, then the person1 will have no address and person2 will.


This is the piece of code that implements it.

public class A {
    internal B a;
    public B Value {
     get {
      return a;
     }
     set {
            if (value == null) {
                if (a != null)
                    a.a = null;
            }  else
                value.a = this;
      a = value;
     }
    }
}

public class B {
    internal A a;
    public A Value {
     get {
      return a;
     }
     set {
            if (value == null) {
                if (a != null)
                    a.a = null;
            }  else
                value.a = this;
            a = value;
     }
    }
}

This allows following tests to pass:

// For the common setup:
var a = new A();
var b = new B();

// Test 1:
a.Value = b;
Assert.AreSame(a, b.Value);

// Test 2:
b.Value = a;
Assert.AreEqual(b, a.Value);

// Test 3:
b.Value = a;
b.Value = null;
Assert.IsNull(a.Value);

// Test 4:
var a2 = new A();
b.Value = a2;
Assert.AreSame(b, a2.Value);
Assert.AreNotSame(a, b.Value);

// Test 5:
a.Value = b;
Assert.AreSame(a, b.Value);
var a1 = new A();
var b1 = new B();
a1.Value = b1;
Assert.AreSame(a1, b1.Value);

// Test 6:
var a1 = new A();
var b1 = new B();
Assert.IsNull(a.Value);
Assert.IsNull(b.Value);
Assert.IsNull(a1.Value);
Assert.IsNull(b1.Value);


Now the question is: how would you abstract the code in the setters to avoid possible mistakes when writing a lot of such classes?

The conditions are:

  • The PUBLIC interfaces of classes A and B cannot be changed.
  • Factories should not be used.
  • Statics should not be used (to persist shared info).
  • ThreadInfo or similar should not be used.
A: 

I really don't understand your challenge. What happens when you instantiate a few instances of class A and then a single instance of class B?

A a1 = new A();
A a2 = new A();
A a3 = new A();
A a4 = new A();
A a5 = new A();
B b = new B();

Which test passes? Which one fails?

You see, once A is instantiated, it has a state. This state should be somehow involved with an instance of B, an existing instance. So this instance of B must exist even before you instantiate this A class.

The same is true for an instance of B. It should hold a reference to an already existing instance of A.

As far as I understand, class A should have a constructor with a reference to an existing instance of B:

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

// Then you can have:
B b1 = new B();
A a1 = new A(b1); // here's the link

B b2 = new B();
A a2 = new A(b2); // and another link

Either this or the other way around with B.

You write that you don't want to change the public signatures of A and B, and you don't want to add factories to the code. I really can't see a consistent solution under such constraints. Or maybe the challenge itself is not clear enough?

EDIT: Taking a wild guess here, I think that what you try to achieve here can be done using Reflection: you might want to reflect existing code up to a point (in the call stack), and match a new instance of, say, A to an existing instance of B. This is can be done using reflection, but it's pretty hard and you must have a concrete and robust set of rules for the linkage between new instances of As and Bs. If this is the direction of the needed solution, then I think you should dive into reflection and see how it goes, it's a huge field.

Ron Klein
Ron, I have updated the question a bit to give an example so hopefully it will clarify things a bit. And added test 6 that shows how objects should behave if there are many of them.ATM, it sounds like under the constrains there is actually no obvious solution.
Dmytrii Nagirniak