是否可以在没有第三方库的情况下拦截控制台输出?

时间:2014-11-25 14:23:13

标签: .net console-application

首先,this question似乎是一个骗局,但它不是。

我正在寻找一种拦截控制台输出的方法,这样我就可以在将它写入控制台的输出流之前进行一些字符串预处理。例如,我编写了一个将字符串包装为X个字符的方法,但是每次我认为可能需要它时,我都不想调用它。我链接的问题满足接收输出流的第一个条件,但它不允许我在应用预处理后执行我自己的Console.Write()

所以我提出了创建我自己的类的想法,该类继承自StringWriter并覆盖Write(string value)重载,但我的断点似乎没有被击中。

class MyWriter : StringWriter
{
    public override void Write(string value)
    {
        var o = Console.Out;
        Console.SetOut(new StreamWriter(Console.OpenStandardOutput()));
        Console.WriteLine(value);
        Console.SetOut(o);
    }
}

static MyWriter output = new MyWriter();

static void Main(string[] args)
{
    Console.SetOut(output);

    Console.WriteLine("woooo");

    string s = output.ToString();
}

它正在写入流,但我的超载并没有被击中。但是,如果我调用output.Write("woooo"),它确实会触及断点。这告诉我控制台没有调用我重载的特定方法。我究竟做错了什么?此外,在我的重写方法中交换输出对象似乎不起作用,但这是我必须解决的另一个问题。

如果可能的话,我想避免使用任何第三方库。

3 个答案:

答案 0 :(得分:0)

您似乎在假设WriteLine最终会调用Writer的Write方法。你需要覆盖Write&的WriteLine。这个问题有一个工作示例:Redirect console.writeline from windows application to a string

答案 1 :(得分:0)

是的。
我通常只创建一个类,可以将其包装在IDisposable中的main周围。
因此,我可以将控制台输出记录到文件中,而无需修改其余代码。
这样,我既在控制台中获得了输出,又在文本文件中提供了以后参考。

public class Program
{

    public static async System.Threading.Tasks.Task Main(string[] args)
    {
        using (ConsoleOutputMultiplexer co = new ConsoleOutputMultiplexer())
        {
            // Do something here
            System.Console.WriteLine("Hello Logfile and Console 1 !");
            System.Console.WriteLine("Hello Logfile and Console 2 !");
            System.Console.WriteLine("Hello Logfile and Console 3 !");
        } // End Using co 


        System.Console.WriteLine(" --- Press any key to continue --- ");
        System.Console.ReadKey();

        await System.Threading.Tasks.Task.CompletedTask;
    } // End Task Main 

}

使用

public class MultiTextWriter
    : System.IO.TextWriter
{

    protected System.Text.Encoding m_encoding;
    protected System.Collections.Generic.IEnumerable<System.IO.TextWriter> m_writers;


    public override System.Text.Encoding Encoding => this.m_encoding;


    public override System.IFormatProvider FormatProvider
    {
        get
        {
            return base.FormatProvider;
        }
    }


    public MultiTextWriter(System.Collections.Generic.IEnumerable<System.IO.TextWriter> textWriters, System.Text.Encoding encoding)
    {
        this.m_writers = textWriters;
        this.m_encoding = encoding;
    }


    public MultiTextWriter(System.Collections.Generic.IEnumerable<System.IO.TextWriter> textWriters)
        : this(textWriters, textWriters.GetEnumerator().Current.Encoding)
    { }


    public MultiTextWriter(System.Text.Encoding enc, params System.IO.TextWriter[] textWriters)
        : this((System.Collections.Generic.IEnumerable<System.IO.TextWriter>)textWriters, enc)
    { }


    public MultiTextWriter(params System.IO.TextWriter[] textWriters)
        : this((System.Collections.Generic.IEnumerable<System.IO.TextWriter>)textWriters)
    { }


    public override void Flush()
    {
        foreach (System.IO.TextWriter thisWriter in this.m_writers)
        {
            thisWriter.Flush();
        }
    }

    public async override System.Threading.Tasks.Task FlushAsync()
    {
        foreach (System.IO.TextWriter thisWriter in this.m_writers)
        {
            await thisWriter.FlushAsync();
        }

        await System.Threading.Tasks.Task.CompletedTask;
    }


    public override void Write(char[] buffer, int index, int count)
    {
        foreach (System.IO.TextWriter thisWriter in this.m_writers)
        {
            thisWriter.Write(buffer, index, count);
        }
    }


    public override void Write(System.ReadOnlySpan<char> buffer)
    {
        foreach (System.IO.TextWriter thisWriter in this.m_writers)
        {
            thisWriter.Write(buffer);
        }
    }


    public async override System.Threading.Tasks.Task WriteAsync(char[] buffer, int index, int count)
    {
        foreach (System.IO.TextWriter thisWriter in this.m_writers)
        {
            await thisWriter.WriteAsync(buffer, index, count);
        }

        await System.Threading.Tasks.Task.CompletedTask;
    }


    public async override System.Threading.Tasks.Task WriteAsync(System.ReadOnlyMemory<char> buffer, System.Threading.CancellationToken cancellationToken = default)
    {
        foreach (System.IO.TextWriter thisWriter in this.m_writers)
        {
            await thisWriter.WriteAsync(buffer, cancellationToken);
        }

        await System.Threading.Tasks.Task.CompletedTask;
    }


    protected override void Dispose(bool disposing)
    {
        foreach (System.IO.TextWriter thisWriter in this.m_writers)
        {
            thisWriter.Dispose();
        }
    }


    public async override System.Threading.Tasks.ValueTask DisposeAsync()
    {
        foreach (System.IO.TextWriter thisWriter in this.m_writers)
        {
            await thisWriter.DisposeAsync();
        }

        await System.Threading.Tasks.Task.CompletedTask;
    }

    public override void Close()
    {

        foreach (System.IO.TextWriter thisWriter in this.m_writers)
        {
            thisWriter.Close();
        }
        
    } // End Sub Close 


} // End Class MultiTextWriter 



public class ConsoleOutputMultiplexer
    : System.IDisposable
{

    protected System.IO.TextWriter m_oldOut;
    protected System.IO.FileStream m_logStream;
    protected System.IO.StreamWriter m_logWriter;

    protected MultiTextWriter m_multiPlexer;


    public ConsoleOutputMultiplexer()
    {
        this.m_oldOut = System.Console.Out;

        try
        {
            this.m_logStream = new System.IO.FileStream("./Redirect.txt", System.IO.FileMode.OpenOrCreate, System.IO.FileAccess.Write);
            this.m_logWriter = new System.IO.StreamWriter(this.m_logStream);
            this.m_multiPlexer = new MultiTextWriter(this.m_oldOut.Encoding, this.m_oldOut, this.m_logWriter);

            System.Console.SetOut(this.m_multiPlexer);
        }
        catch (System.Exception e)
        {
            System.Console.WriteLine("Cannot open Redirect.txt for writing");
            System.Console.WriteLine(e.Message);
            return;
        }

    } // End Constructor 


    void System.IDisposable.Dispose()
    {
        System.Console.SetOut(this.m_oldOut);

        if (this.m_multiPlexer != null)
        {
            this.m_multiPlexer.Flush();
            if (this.m_logStream != null)
                this.m_logStream.Flush();

            this.m_multiPlexer.Close();
        }
        
        if(this.m_logStream != null)
            this.m_logStream.Close();
    } // End Sub Dispose 


} // End Class ConsoleOutputMultiplexer 

答案 2 :(得分:-1)

您在MyWriter课程中创建了一个重载,但您仍在调用Console.WriteLine()。就像你在问题中提到的那样,你需要致电output.Write()来使用你的超载。