c# - Resolving subclass extension method when iteration over base class collection -
i have model, deserialized xml, in node objects derive same base class, , nodes can nested (somewhat) arbitrarily. trying write collection of modules can translate loaded model various text based formats. thought nifty if each such module extension class allow me call model.totext(), model.tohtml(), etc. running problems.
here simplified example:
using system; using system.collections.generic; using system.text; namespace sample { public abstract class foo { } public class bar : foo { public list<foo> children = new list<foo>(); public int qux; } public class baz : foo { public string quux; } public static class extension { public static string totext(this foo foo, int indent = 0) { return string.format("{0}foo <>\n", new string(' ', indent)); } public static string totext(this bar bar, int indent=0) { stringbuilder sb = new stringbuilder(); sb.append(string.format("{0}bar <qux={1}>\n", new string(' ', indent), bar.qux)); foreach (var child in bar.children) { sb.append(child.totext(indent + 1)); } return sb.tostring(); } public static string totext(this baz baz, int indent=0) { return string.format("{0}baz <quux={1}>\n", new string(' ', indent), baz.quux); } } class program { static void main(string[] args) { baz baz = new baz { quux = "frob" }; bar bar = new bar { children = new list<foo>() { new baz {quux = "fred"}, new bar { qux = 11, children = new list<foo>() { new baz() {quux = "flog"} } } } }; //this works console.writeline(baz.totext()); //but doesn't console.writeline(bar.totext()); console.readkey(); } } }
if run get:
baz <quux=frob> bar <qux=0> foo <> foo <>
if try , tricky , instead:
public static string totext(this foo foo, int indent = 0) { return ((dynamic)foo).totext(indent); }
... first print works, second gives me exception:
{"'sample.baz' not contain definition 'totext'"}
i taking wrong approach entirely, use direction.
after stumbling around bit found topic virtual extension methods?. looks can solve cleanly visitor pattern:
public interface ifooformater { string format(foo foo, int indent); string format(bar bar, int indent); string format(baz baz, int indent); } public class fooformater : ifooformater { public string format(foo foo, int indent) { return ""; } public string format(bar bar, int indent) { stringbuilder sb = new stringbuilder(); sb.append(string.format("{0}bar <qux={1}>\n", new string(' ', indent), bar.qux)); foreach (var child in bar.children) { sb.append(this.format((dynamic)child , indent + 1)); } return sb.tostring(); } public string format(baz baz, int indent) { return string.format("{0}baz <quux={1}>\n", new string(' ', indent), baz.quux); } } public static class extension { public static string totext(this foo foo, ifooformater fooformater) { return fooformater.format((dynamic)foo, 0); } }
then calling:
ifooformater fooformater = new fooformater(); console.writeline(bar.totext(fooformater));
i expected output:
bar <qux=0> baz <quux=fred> bar <qux=11> baz <quux=flog>
Comments
Post a Comment