18

我有一个用 C# 编写的外部 dll,我从程序集文档中研究了它使用Console.WriteLine.

这个 DLL 在我与应用程序的 UI 交互期间写入控制台,所以我不直接调用 DLL,但我会捕获所有控制台输出,所以我想我必须在表单加载中初始化,然后稍后获取捕获的文本.

我想将所有输出重定向到一个字符串变量。

我试过Console.SetOut了,但它用于重定向到字符串并不容易。

4

5 回答 5

32

由于您似乎想实时捕获控制台输出,我发现您可能会创建自己的TextWriter实现,该Write实现WriteLineConsole.

作者长这样:

    public class ConsoleWriterEventArgs : EventArgs
    {
        public string Value { get; private set; }
        public ConsoleWriterEventArgs(string value)
        {
            Value = value;
        }
    }

    public class ConsoleWriter : TextWriter
    {
        public override Encoding Encoding { get { return Encoding.UTF8; } }

        public override void Write(string value)
        {
            if (WriteEvent != null) WriteEvent(this, new ConsoleWriterEventArgs(value));
            base.Write(value);
        }

        public override void WriteLine(string value)
        {
            if (WriteLineEvent != null) WriteLineEvent(this, new ConsoleWriterEventArgs(value));
            base.WriteLine(value);
        }

        public event EventHandler<ConsoleWriterEventArgs> WriteEvent;
        public event EventHandler<ConsoleWriterEventArgs> WriteLineEvent;
    }

如果它是 WinForm 应用程序,您可以像这样在 Program.cs 中设置编写器并使用其事件:

    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [STAThread]
    static void Main()
    {
        using (var consoleWriter = new ConsoleWriter())
        {
            consoleWriter.WriteEvent += consoleWriter_WriteEvent;
            consoleWriter.WriteLineEvent += consoleWriter_WriteLineEvent;

            Console.SetOut(consoleWriter);
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Form1());
        }
    }

    static void consoleWriter_WriteLineEvent(object sender, Program.ConsoleWriterEventArgs e)
    {
        MessageBox.Show(e.Value, "WriteLine");
    }

    static void consoleWriter_WriteEvent(object sender, Program.ConsoleWriterEventArgs e)
    {
        MessageBox.Show(e.Value, "Write");
    }
于 2012-08-11T03:46:44.260 回答
22

它基本上相当于以下几点:

var originalConsoleOut = Console.Out; // preserve the original stream
using(var writer = new StringWriter())
{
    Console.SetOut(writer);

    Console.WriteLine("some stuff"); // or make your DLL calls :)

    writer.Flush(); // when you're done, make sure everything is written out

    var myString = writer.GetStringBuilder().ToString();
}

Console.SetOut(originalConsoleOut); // restore Console.Out

因此,在您的情况下,您需要在调用第三方 DLL 之前进行设置。

于 2012-08-11T03:44:11.863 回答
4

您也可以使用 Console.OpenStandardOutput 调用 SetOut,这将恢复原始输出流:

Console.SetOut(new StreamWriter(Console.OpenStandardOutput()));
于 2014-12-10T11:32:18.273 回答
2

或者您可以将它包装在一个辅助方法中,该方法将一些代码作为参数运行它并返回打印的字符串。注意我们如何优雅地处理异常。

public string RunCodeReturnConsoleOut(Action code) 
{
  string result;
  var originalConsoleOut = Console.Out;
  try 
  {
    using (var writer = new StringWriter()) 
    {
      Console.SetOut(writer);
      code();
      writer.Flush();
      result = writer.GetStringBuilder().ToString();
    }
    return result;
  }
  finally 
  {
    Console.SetOut(originalConsoleOut); 
  }
}
于 2012-08-20T09:51:15.320 回答
0

使用@Adam Lear@Carlo V. Dango提出的解决方案,我创建了一个辅助类:

public sealed class RedirectConsole : IDisposable
{
    private readonly Action<string> logFunction;
    private readonly TextWriter oldOut = Console.Out;
    private readonly StringWriter sw = new StringWriter();

    public RedirectConsole(Action<string> logFunction)
    {
        this.logFunction = logFunction;
        Console.SetOut(sw);
    }

    public void Dispose()
    {
        Console.SetOut(oldOut);
        sw.Flush();
        logFunction(sw.ToString());
        sw.Dispose();
    }
}

可以通过以下方式使用:

public static void MyWrite(string str)
{
    // print console output to Log/Socket/File
}

public static void Main()
{
    using(var r = new RedirectConsole(MyWrite)) {
        Console.WriteLine("Message 1");
        Console.WriteLine("Message 2");
    }
    // After the using section is finished,
    // MyWrite will be called once with a string containing all messages,
    // which has been written during the using section,
    // separated by new line characters
}
于 2021-01-20T10:43:20.750 回答