c# - Circular reference in same assembly a bad thing? -
assume have following classes in same assembly
public class parentclass : idisposable { public childclass child { { return _child; } } } public class childclass { public parentclass parent { { return _parent; } set { _parent= value; } } public childclass (parentclass parent) { parent= parent; } }
correct me if wrong bad design. lead memory leak or other unforseen issues later on? apparently garbage collector capable of handling such kind of circular references.
edit
what if 2 classes end getting used in other class?
parentclass objp = new parentclass (); childclass objc =new childclass(objp); objp.child = objc;
thoughts please ....
don't worry garbage collector; handles reference graphs arbitrary topologies ease. worry writing objects lend creating bugs making easy violate invariants.
this questionable design not because stresses gc -- not -- rather because not enforce desired semantic invariant: if x parent of y, y must child of x.
it can quite tricky write classes maintain consistent parent-child relationships. on roslyn team build two trees. "real" tree has child references; no child knows parent. layer "facade" tree on top of enforces consistency of parent-child relationship: when ask parent node child, creates facade on top of real child , sets parent of facade object true parent.
update: commenter brian asks more details. here's sketch of how might implement "red" facade child , parent references on "green" tree contains child references. in system impossible make inconsistent parent-child relationship, can see in test code @ bottom.
(we call these "red" , "green" trees because when drawing data structure on whiteboard, marker colours used.)
using system; interface ivalue { string value { get; } } interface iparent : ivalue { ichild child { get; } } interface ichild : ivalue { iparent parent { get; } } abstract class hasvalue : ivalue { private string value; public hasvalue(string value) { this.value = value; } public string value { { return value; } } } sealed class greenchild : hasvalue { public greenchild(string value) : base(value) {} } sealed class greenparent : hasvalue { private greenchild child; public greenchild child { { return child; } } public greenparent(string value, greenchild child) : base(value) { this.child = child; } public iparent makefacade() { return new redparent(this); } private sealed class redparent : iparent { private greenparent greenparent; private redchild redchild; public redparent(greenparent parent) { this.greenparent = parent; this.redchild = new redchild(this); } public ichild child { { return redchild; } } public string value { { return greenparent.value; } } private sealed class redchild : ichild { private redparent redparent; public redchild(redparent redparent) { this.redparent = redparent; } public iparent parent { { return redparent; } } public string value { { return redparent.greenparent.child.value; } } } } } class p { public static void main() { var greenchild1 = new greenchild("child1"); var greenparent1 = new greenparent("parent1", greenchild1); var greenparent2 = new greenparent("parent2", greenchild1); var redparent1 = greenparent1.makefacade(); var redparent2 = greenparent2.makefacade(); console.writeline(redparent1.value); // parent1 console.writeline(redparent1.child.parent.value); // parent1 ! console.writeline(redparent2.value); // parent2 console.writeline(redparent2.child.parent.value); // parent2 ! // see how goes? redparent1 , redparent2 disagree on // parent of greenchild1 is, **but self-consistent**. // report parent of child themselves. } }
Comments
Post a Comment