我有一个从XML反序列化的模型,其中所有节点对象都派生自相同的基类,并且节点可以(有些)任意嵌套。我正在尝试编写一组模块,可以将加载的模型转换为各种基于文本的格式。我认为如果每个这样的模块都是一个扩展类,这将允许我简单地调用Model.ToText(),Model.ToHtml()等,这将是非常好的。但我遇到了一些问题。
这是一个简化的例子:
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 this doesn't
Console.WriteLine(bar.ToText());
Console.ReadKey();
}
}
}
如果我跑这个,我得到:
Baz <Quux=frob>
Bar <Qux=0>
Foo <>
Foo <>
如果我试着变得棘手并改为:
public static string ToText(this Foo foo, int indent = 0)
{
return ((dynamic)foo).ToText(indent);
}
......第一次印刷工作,但第二次印刷给我例外:
{"'Sample.Baz' does not contain a definition for 'ToText'"}
我可能完全采取了错误的方法,但我可以使用一些方向。
答案 0 :(得分:1)
稍微磕磕绊绊之后,我找到了主题Virtual Extension Methods?。看起来我可以使用访问者模式干净利落地解决这个问题:
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);
}
}
然后致电:
IFooFormater fooFormater = new FooFormater();
Console.WriteLine(bar.ToText(fooFormater));
我得到了预期的输出:
Bar <Qux=0>
Baz <Quux=fred>
Bar <Qux=11>
Baz <Quux=flog>