【问题标题】:Redirect console.writeline from windows application to a string将 Windows 应用程序中的 console.writeline 重定向到字符串
【发布时间】:2012-08-08 08:17:54
【问题描述】:

我有一个用 C# 编写的外部 dll,我从程序集文档中了解到它使用 Console.WriteLine 将其调试消息写入控制台。

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

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

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

【问题讨论】:

    标签: c# .net console


    【解决方案1】:

    您似乎想实时捕获控制台输出,我发现您可以创建自己的 TextWriter 实现,每当WriteWriteLineConsole 上发生时触发事件。

    作者长这样:

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

    【讨论】:

    • 这个 DLL 在我与应用程序的 UI 交互期间写入控制台,所以我不直接进行 DLL 调用,但我会捕获所有控制台输出,所以我想我必须在表单中初始化load ,然后稍后获取捕获的文本。
    • 它是 WinForms 应用程序吗?在程序流程中什么时候需要输出?
    • 是的,它是一个 c# winform 应用程序,我需要在 GUI 事件之后捕获控制台输出。
    • @geogeek:答案已修改。我编写了一个基于 TextWriter 的简单类,它实现了 Write 和 WriteLine 的事件处理程序,可以帮助您在控制台输出进入时捕获它。
    • @DavidCFuchs 你的意思是已经创建的控制台编写器不能像我的例子一样传递给 SetOut 吗?你需要创建一个新的、未使用的实例吗?
    【解决方案2】:

    基本上是这样的:

    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 之前进行设置。

    【讨论】:

    • 这个 DLL 在我与应用程序的 UI 交互期间写入控制台,所以我不直接调用 DLL,但我会捕获所有控制台输出,所以我想我必须以表格形式初始化load ,然后稍后获取捕获的文本。
    【解决方案3】:

    你也可以用 Console.OpenStandardOutput 调用 SetOut,这样会恢复原来的输出流:

    Console.SetOut(new StreamWriter(Console.OpenStandardOutput()));
    

    【讨论】:

      【解决方案4】:

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

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

      【讨论】:

        【解决方案5】:

        使用@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
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2013-09-14
          • 2010-09-26
          • 1970-01-01
          • 2011-06-22
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多