C# 传阅;附录LystringBuilder“;
我有一个序列化任务,其中对象模型的不同部分和片段知道如何发出它们自己的字符串段,但我希望可以选择使用C# 传阅;附录LystringBuilder“;,c#,stringbuilder,C#,Stringbuilder,我有一个序列化任务,其中对象模型的不同部分和片段知道如何发出它们自己的字符串段,但我希望可以选择使用.Append对公共StringBuilder对象发出它们。基于我们不应该将我们的私有对象传递给其他人不加区别地使用的理论,这里有一个类,它包装了一个StringBuilder,使其“仅附加”在我的场景中使用 public sealed class AppendOnlyStringBuilder { private readonly StringBuilder _stringBuilder;
.Append
对公共StringBuilder
对象发出它们。基于我们不应该将我们的私有对象传递给其他人不加区别地使用的理论,这里有一个类,它包装了一个StringBuilder
,使其“仅附加”在我的场景中使用
public sealed class AppendOnlyStringBuilder {
private readonly StringBuilder _stringBuilder;
public AppendOnlyStringBuilder(StringBuilder stringBuilder)
{
_stringBuilder = stringBuilder;
}
public AppendOnlyStringBuilder Append<T>(T value)
{
_stringBuilder.Append(value);
return this;
}
}
这些ToString
方法是从主例程的序列化方法调用的,如下所示:
// MainObject class
Chunk1 _chunk1;
Chunk2 _chunk2;
Chunk3 _chunk3;
public override string ToString() {
StringBuilder sb = new StringBuilder();
sb
.Append(_chunk1.ToString()) // ToString may be unnecessary here
.Append(_chunk2.ToString())
.Append(_chunk3.ToString());
return sb.ToString();
}
我怎样才能优雅地切换到传递一个AppendOnlyStringBuilder
以用于所有这些区块类,而不是每个区块类内部创建一个新的StringBuilder
并执行ToString
我希望它能被这样使用:
// MainObject class
public override string ToString() {
StringBuilder sb = new StringBuilder();
AppendOnlyStringBuilder aosb = new AppendOnlyStringBuilder(sb);
aosb
.Append(_chunk1)
.Append(_chunk2)
.Append(_chunk3);
return sb.ToString();
}
扩展方法是获取这种语法的自然方式,但由于扩展方法需要是静态的,因此无法访问块类的私有部分,所以我遇到了问题。我希望在chunk类中保留相同的ToString
,这样它们仍然可以执行正常的“序列化仅限我”操作,但我也希望它们能够选择性地附加到我的公共AppendOnlyStringBuilder
我想我可以做到:
_chunk1.AppendTo(aosb);
_chunk2.AppendTo(aosb);
_chunk3.AppendTo(aosb);
class Chainable
{
private readonly TextWriter _textWriter;
public Chainable(TextWriter textWriter)
{
_textWriter = textWriter;
}
public Chainable Write(BaseClass obj)
{
obj.SerializeTo(_textWriter);
return this;
}
}
但这方面的一些问题让我感到困惑——我想使用一个流畅的界面,它以
AppendOnlyStringBuilder
对象开始,就像我前面的例子一样。如果你只想要一个类型的Instatitated对象,你可以使用singleton模式(谷歌会给你很多例子)
如果您有一个全局对象(类似于“myApplication”类),您可以在那里提供它
另一种方式是一个静态类“从任何地方”提供这个单例实例
您的代码将直接附加到此实例
希望这有帮助好的,下面是:
using System.IO;
abstract class BaseClass
{
protected abstract void WriteToTextWriter(TextWriter textWriter);
public void SerializeTo(TextWriter textWriter)
{
WriteToTextWriter(textWriter);
}
public sealed override string ToString()
{
var writer = new StringWriter();
SerializeTo(writer);
return writer.ToString();
}
}
abstract class ChunkBase : BaseClass
{
private readonly string _index;
protected ChunkBase(string index)
{
_index = index;
}
protected sealed override void WriteToTextWriter(TextWriter textWriter)
{
textWriter.Write("Chunk");
textWriter.Write(_index);
}
}
class Chunk1 : ChunkBase { public Chunk1() : base("1") { } }
class Chunk2 : ChunkBase { public Chunk2() : base("2") { } }
class Chunk3 : ChunkBase { public Chunk3() : base("3") { } }
class ClassWithChunks : BaseClass
{
private readonly Chunk1 _chunk1 = new Chunk1();
private readonly Chunk2 _chunk2 = new Chunk2();
private readonly Chunk3 _chunk3 = new Chunk3();
protected override void WriteToTextWriter(TextWriter textWriter)
{
_chunk1.SerializeTo(textWriter);
_chunk2.SerializeTo(textWriter);
_chunk3.SerializeTo(textWriter);
}
}
现在,如果要链接,可以执行以下操作:
_chunk1.AppendTo(aosb);
_chunk2.AppendTo(aosb);
_chunk3.AppendTo(aosb);
class Chainable
{
private readonly TextWriter _textWriter;
public Chainable(TextWriter textWriter)
{
_textWriter = textWriter;
}
public Chainable Write(BaseClass obj)
{
obj.SerializeTo(_textWriter);
return this;
}
}
然后,您的WriteToTextWriter可能是,例如:
public override void WriteToTextWriter(TextWriter textWriter)
{
new Chainable(textWriter)
.Write(_chunk1)
.Write(_chunk2)
.Write(_chunk3);
}
我不确定这是否值得:代码当然更干净,但对于某些人(包括你未来的自己)来说,由于额外的复杂性,破译将更加困难
编辑:使抽象方法受到保护在这里似乎没有什么好处,但在生产代码中,额外的一层可能会很有帮助。您还需要添加一些开关来处理格式化等问题。似乎是适配器模式的理想选择。 (未测试代码) 然后,每个块在不知道接口是如何实例化的情况下工作:
_chunk1.AppendTo(aosb);
_chunk2.AppendTo(aosb);
_chunk3.AppendTo(aosb);
但这方面的一些问题困扰着我——我想使用一个流畅的界面,它以AppendOnlyStringBuilder对象开始,就像我前面的示例一样
因此,有了这个需求(减去不必要的AppendOnlyStringBuilder类),您就可以切换接口方向了
public interface IGetString
{
string GetString();
}
public Chunk : IGetString
{
public string GetString()
{
return "MyContent";
}
}
public static class StringBuilderExtensions
{
public static StringBuilder AppendFrom(this StringBuilder instance
, IGetString getString)
{
instance.Append(getString.GetString())
return instance;
}
}
那就流畅了:
var sb = new StringBuilder;
var a = new Chunk();
var b = new Chunk();
sb.AppendFrom(a).AppendFrom(b);
各种
块
类只能访问AppendOnlyStringBuilder
。他们怎么能对主对象实例化并保持私有的底层对象做任何事情呢?我将建立一个系统,在这个系统中,对象将自己序列化为TextWriter(但如果愿意,可以继续使用StringBuilder)。然后ToString重写只创建一个新的TW(或SB),调用另一个方法,并返回结果。serialize方法可以是抽象的,并且ToString重写只能在基类中定义一次。这失去了方法链,但我不认为这是一个巨大的损失。您可以使用访问者模式来保存它。我不确定这样的努力是否值得。@phoog ATextWriter
可以,只要我们不出现重复字符串连接的问题。你能给出一些示例代码来概括你的想法吗?@ErikE正在研究它…@phoog一些直接写入流的东西(这样它就可以用来写入文件)将非常棒——不需要先在内存中序列化……这一点都没有帮助。我不想要每个区块类都可以独立访问的全局单例。请更仔细地重读这个问题。作用域必须是每个序列化,而不是每个全局应用程序/执行。使用您建议的模式重用以前未清理的StringBuilder会有很大的风险。谢谢您的建议。我想我自己也能做到。我一直想把WriteToTextWriter
方法隐藏起来,不让public
@ErikE知道,当然,你可以这样做。我可能应该这么做。我将其公开是基于这样的假设,即序列化到一个文件将需要传入StreamWriter。但是当然,应该有一个SerializeTo(StreamWriter)方法或类似的方法,它反过来调用WriteToTextWriter。我将据此进行编辑。谢谢您的建议!我会仔细考虑这些选择。这取决于哪个方向更有意义。因为这些看起来是抽象类,所以我真的可以分辨出哪个是主对象和从属对象(尽管我的直觉告诉我底部更接近)。