2

First off, there's this question which appears to be a dupe, but it isn't.

I am looking for a way to intercept console output so that I can do some string pre-processing before it's written to the console's output stream. For example, I wrote a method that wraps a string at X characters, but I don't want to call it every time I think I might need it. The question I linked to satisfies the first condition of receiving the output stream, but it doesn't allow me to execute my own Console.Write() after the pre-processing has been applied.

So I came up with the idea to create my own class that inherits from StringWriter and override the Write(string value) overload, but my breakpoint doesn't appear to get hit.

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();
}

It's writing to the stream, but my overload isn't being hit. If I call output.Write("woooo"), though, it does hit the breakpoint. This tells me that the console is not calling the particular method that I overloaded. What am I doing wrong? Also, swapping the output object in my overridden method doesn't appear to work, but that's another problem I'll have to resolve.

I want to avoid using any third party libraries if at all possible.

Community
  • 1
  • 1
oscilatingcretin
  • 10,457
  • 39
  • 119
  • 206
  • 1
    Your code is too confusing. Why do you create new stream for every write operation? Also I don't understand what is the question. When your write is not called? Did you tried overloading the other methods? Also I suspect this is a [XY problem](http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem). Can you explain what you're trying to achieve instead? – Sriram Sakthivel Nov 25 '14 at 14:33

3 Answers3

1

You appear to be making an assumption that WriteLine will end up calling the Writer's Write method. You need to override Write & WriteLine. This question has a working example: Redirect console.writeline from windows application to a string

Community
  • 1
  • 1
Robert Levy
  • 28,747
  • 6
  • 62
  • 94
0

Yes it is.
I usually just create a class, which I can wrap around main in an IDisposable.
So I can log the console output to a file without modifying the rest of the code.
That way, I have the output in both the console and for later reference in a text-file.

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 

}

with

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 
Stefan Steiger
  • 78,642
  • 66
  • 377
  • 442
-2

You created an overload in the MyWriter class, but you're still calling Console.WriteLine(). Like you mentioned in your question, you need to call output.Write() to use your overload.

Saggio
  • 2,212
  • 6
  • 33
  • 50