简体   繁体   English

实现派生类的TextWriter

[英]Implementing a Derived Class of TextWriter

I have two classes, none of which I can change in any way: 我有两个课程,我不能以任何方式改变:

Class 1: Takes a TextWriter as constructor parameter and uses it as an output stream. 第1类:将TextWriter作为构造函数参数并将其用作输出流。

Class 2: Provides a method WriteLine(string) . 第2类:提供WriteLine(string)方法WriteLine(string)

I need an adapter, such that all the output of Class1 is written to Class2. 我需要一个适配器,这样Class1的所有输出都写入Class2。 Therefore I started an adapter which extends TextWriter and buffers incoming text, flushing it to the class2 instance as soon as a new line arrives. 因此,我启动了一个适配器,它扩展了TextWriter并缓冲了传入的文本,并在新行到达时将其刷新到class2实例。

However, there are many and more methods in TextWriter - which should I implement? 但是,TextWriter中有很多方法 - 我应该实现哪些方法? Output in Class1 is string only. Class1中的输出仅为字符串。

According to MSDN one should override Write(char) as a minimum, however, this enforces me to do all the \\r\\n new line handling myself as well... 根据MSDN,应该至少覆盖Write(char),但是,这强制我自己完成所有\\ r \\ n新行处理...

Q1: Do you know of a better way to reach my goal? Q1:你知道更好的方法来实现我的目标吗? Q2: If no, which TextWriter methods should I override to have minimum implementation effort. Q2:如果不是,我应该覆盖哪些TextWriter方法以实现最小的实现工作。

Implementing Write(char) on your TextWriter derived class is all you need to do. 您需要在TextWriter派生类上实现Write(char) If somebody calls WriteLine on your new class, the base class WriteLine method is called. 如果有人在您的新类上调用WriteLine ,则会调用基类WriteLine方法。 It will do the right thing: call your Write method with the individual \\r and \\n characters. 它会做正确的事情:使用单独的\\r\\n字符调用Write方法。

Actually, WriteLine(string) looks something like this: 实际上, WriteLine(string)看起来像这样:

void WriteLine(string s)
{
    Write(s);
    Write("\r\n");
}

And Write(string) is, in effect: Write(string)实际上是:

foreach (char c in s)
{
    Write(c);
}

All of the Write methods in TextWriter resolve to something that calls Write(char) in a loop. TextWriter所有Write方法都解析为在循环中调用Write(char)东西。

You really don't have to implement anything else. 你真的没有必要实现其他任何东西。 Just override Write(char) and plug it in. It will work. 只需覆盖Write(char)并将其插入即可。它可以正常工作。

You can override those other methods. 可以覆盖其他方法。 Doing so will make your class a little more efficient (faster). 这样做会使您的课程更有效(更快)。 But it's not required. 但这不是必需的。 I say do the simplest thing you can. 我说你做的最简单的事情。 Then, if you determine after profiling that your custom writer is too slow, override other methods as necessary. 然后,如果您在分析自定义编写器太慢后确定,请根据需要覆盖其他方法。

Here's a minimal TextWriter descendant: 这是一个最小的TextWriter后代:

public class ConsoleTextWriter: TextWriter
{
    public override void Write(char value)
    {
        Console.Write(value);
    }

    public override Encoding Encoding
    {
        get { return Encoding.Default; }
    }
}

If I then write: 如果我然后写:

using (var myWriter = new ConsoleTextWriter())
{
    myWriter.Write("hello, world");
    myWriter.WriteLine();
    myWriter.WriteLine();
    myWriter.WriteLine("Goodbye cruel world.");
    myWriter.Write("Fee fie foe foo!");
}

The output is: 输出是:

hello, world

Goodbye cruel world.
Fee fie foe foo!

I'm adding another answer because I couldn't get the above answer to work! 我正在添加另一个答案,因为我无法得到上述答案!

In my experience, I must override WriteLine() and WriteLine(string) in order for those functions to work. 根据我的经验,我必须覆盖WriteLine()WriteLine(string)才能使这些函数正常工作。

Here's an example that can be used to write a web page as a long-running task goes on. 这是一个可用于在长时间运行的任务中编写网页的示例。 BTW, the HttpResponse object is from ASP.net MVC. 顺便说一句,HttpResponse对象来自ASP.net MVC。

public class WebConsoleWriter : TextWriter
{
    HttpResponseBase Response { get; set; }
    bool FlushAfterEveryWrite { get; set; }
    bool AutoScrollToBottom { get; set; }
    Color BackgroundColor { get; set; }
    Color TextColor { get; set; }

    public WebConsoleWriter(HttpResponseBase response, bool flushAfterEveryWrite, bool autoScrollToBottom)
    {
        Response = response;
        FlushAfterEveryWrite = flushAfterEveryWrite;
        AutoScrollToBottom = autoScrollToBottom;
        BackgroundColor = Color.White;
        TextColor = Color.Black;
    }

    public WebConsoleWriter(HttpResponseBase response, bool flushAfterEveryWrite,  bool autoScrollToBottom, Color backgroundColor, Color textColor)
    {
        Response = response;
        FlushAfterEveryWrite = flushAfterEveryWrite;
        AutoScrollToBottom = autoScrollToBottom;
        BackgroundColor = backgroundColor;
        TextColor = textColor;
    }

    public virtual void WritePageBeforeStreamingText()
    {
        string headerFormat =
@"<!DOCTYPE html>
<html>
<head>
    <title>Web Console</title>
    <style>
        html {{
            background-color: {0};
            color: {1};
        }}
    </style>        
</head>
<body><pre>";
        string backgroundColorHex = ColorTranslator.ToHtml(BackgroundColor);
        string foregroundColorHex = ColorTranslator.ToHtml(TextColor);
        Response.Write(string.Format(headerFormat, backgroundColorHex, foregroundColorHex));

        // Add a 256 byte comment because I read that some browsers will automatically buffer the first 256 bytes.
        Response.Write("<!--");
        Response.Write(new string('*', 256));
        Response.Write("-->");
        Response.Flush();
    }

    public virtual void WritePageAfterStreamingText()
    {
        Response.Write("</pre></body></html>");
    }

    public override void Write(string value)
    {
        string encoded = Encode(value);
        Response.Write(encoded);            
        if (FlushAfterEveryWrite)
            Response.Flush();
    }

    public override void WriteLine(string value)
    {
        Response.Write(Encode(value) + "\n");
        if (AutoScrollToBottom)
            ScrollToBottom();
        if (FlushAfterEveryWrite)
            Response.Flush();
    }

    public override void WriteLine()
    {
        Response.Write('\n');
        if (AutoScrollToBottom)
            ScrollToBottom();
        if (FlushAfterEveryWrite)
            Response.Flush();
    }

    private string Encode(string s)
    {
        return s.Replace("&", "&amp;").Replace("<", "&lt;").Replace(">", "&gt;");
    }

    public override void Flush()
    {
        Response.Flush();
    }

    public void ScrollToBottom()
    {
        Response.Write("<script>window.scrollTo(0, document.body.scrollHeight);</script>");
    }

    public override System.Text.Encoding Encoding
    {
        get { throw new NotImplementedException(); }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 在基类和派生类中实现接口 - Implementing an interface in a base and derived class 在从Stream派生的类上实现Dispose - Implementing Dispose on a class derived from Stream 使用派生类型实现抽象类 - implementing abstract class using derived types 可以在派生类中覆盖抽象类,而无需在基类中实现 - Can abstract class be override in derived class without implementing in base class 实现派生类接口方法的抽象基类 - Abstract base class implementing derived class interface methods 显式地将派生类标记为基类的实现接口 - Explicitly marking derived class as implementing interface of base class 是否有System.Diagnostics.Debug类的TextWriter接口? - Is there a TextWriter interface to the System.Diagnostics.Debug class? 使用派生自 System.ComponentModel.Component 的类实现 Dispose() - Implementing Dispose() with class derived from System.ComponentModel.Component 基类实现基接口而派生/具体类实现扩展接口,为什么? - base class implementing base interface while derived/concrete class implementing extended interface, why? 实现定义基类属性的接口时,为什么类实现接口不能返回派生类类型对象? - When implementing an interface which define a base class property why can't the class implementing interface return a derived class type object?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM