c# - Confused with something looking like the curiously recursive template pattern -
i have application made of several "levels" of elements. elements parent of 0..n children elements, being parent of 0..n other elements. top level type has no parent , bottom level elements have no children.
in other words, let 3 types : a, b , c. instance of parent of multiple instances of b, being parents of multiple instances of c. each instance has (strongly typed) reference parent.
i have several methods same in parent classes, addchild, removechild, getchildindex, etc. have base class parent classes in order not duplicate these methods each parent type.
the idea that, when deriving parent base class, have provide type of children, depending on type of parent.
so far have come overly complex design :
public interface ichild<tparent> tparent : parentbase<ichild<tparent>> { tparent parent { get; set; } } public class parentbase<tchild> tchild : ichild<parentbase<tchild>> { public list<tchild> children; } public class : parentbase<b> { } public class b : parentbase<c>, ichild<a> { } public class c : ichild<b> { }
but i'm getting compile errors :
error cs0311 type 'templatetest.ichild<tparent>' cannot used type parameter 'tchild' in generic type or method 'parentbase<tchild>'. there no implicit reference conversion 'templatetest.ichild<tparent>' 'templatetest.ichild<templatetest.parentbase<templatetest.ichild<tparent>>>'. kbd2 c:\dev\kbd2\templatetest.cs 6 active error cs0311 type 'templatetest.parentbase<tchild>' cannot used type parameter 'tparent' in generic type or method 'ichild<tparent>'. there no implicit reference conversion 'templatetest.parentbase<tchild>' 'templatetest.parentbase<templatetest.ichild<templatetest.parentbase<tchild>>>'. kbd2 c:\dev\kbd2\templatetest.cs 11 active error cs0311 type 'templatetest.b' cannot used type parameter 'tchild' in generic type or method 'parentbase<tchild>'. there no implicit reference conversion 'templatetest.b' 'templatetest.ichild<templatetest.parentbase<templatetest.b>>'. kbd2 c:\dev\kbd2\templatetest.cs 16 active error cs0311 type 'templatetest.c' cannot used type parameter 'tchild' in generic type or method 'parentbase<tchild>'. there no implicit reference conversion 'templatetest.c' 'templatetest.ichild<templatetest.parentbase<templatetest.c>>'. kbd2 c:\dev\kbd2\templatetest.cs 20 active error cs1721 class 'b' cannot have multiple base classes: 'parentbase<c>' , 'ichild<a>' kbd2 c:\dev\kbd2\templatetest.cs 20 active error cs0311 type 'templatetest.b' cannot used type parameter 'tparent' in generic type or method 'ichild<tparent>'. there no implicit reference conversion 'templatetest.b' 'templatetest.parentbase<templatetest.ichild<templatetest.b>>'. kbd2 c:\dev\kbd2\templatetest.cs 24 active
i'm not sure whether can compile or not since classes depend on each other. doing wrong ? thank you.
edit : added unimplemented methods , updated error list.
edit : simplified example making child interface base class instead of interface, parent class.
edit : 1 base class allowed turned child type interface instead of class.
edit : if remove either of 2 "where" constraints, errors gone. because depend on each other ?
the problem current approach relies on kind of strange recursion. it's saying:
- a child person parent
- and parent person child has parent
- and child person parent has child has parent
- ... doesn't work!
if think again it, parent/child relationship involves 2 types:
public interface ichild<p, c> p : iparent<p, c> c : ichild<p, c> { p parent { get; set; } } public interface iparent<p, c> p : iparent<p, c> c : ichild<p, c> { ilist<c> children { get; } }
while may work, looks complicated, because in iparent
type paremeter p
not used , in ichild
type parameter c
not used.
but think we're on right track. if simplify interfaces , add generic constraint parentbase
, more understandable:
public interface ichild<p> { p parent { get; set; } } public interface iparent<c> { ilist<c> children { get; } } public class parentbase<p, c> : iparent<c> c : ichild<p> { public ilist<c> children { get; } = new list<c>(); }
with design, have separated concerns:
- an interface parents
- an interface children
- and base class implementation
your example works:
public class : parentbase<a, b> { } public class b : parentbase<b, c>, ichild<a> { public parent { get; set; } } public class c : ichild<b> { public b parent { get; set; } } public class demo { public static void test() { var = new a(); var b = new b() { parent = }; var c = new c() { parent = b }; a.children.add(b); b.children.add(c); system.console.writeline(c.parent.parent == a); } }
there minor other details note:
- for published lists, common use interface
ilist<t>
abstract implementation - public fields (like
children
inparentbase
) uncommon, people use read-only property encapsulate list itself
Comments
Post a Comment