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.
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?
Which test passes? Which one fails?
You see, once
Ais instantiated, it has a state. This state should be somehow involved with an instance ofB, an existing instance. So this instance ofBmust exist even before you instantiate thisAclass.The same is true for an instance of
B. It should hold a reference to an already existing instance ofA.As far as I understand, class A should have a constructor with a reference to an existing instance of B:
Either this or the other way around with
B.You write that you don’t want to change the public signatures of
AandB, 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,
Ato an existing instance ofB. 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 ofAs andBs. 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.