3

全て

私は自分のものではなくライブラリを持っているので、それを変更することはできません。このライブラリには 2 つのメソッドがあります。それぞれを Method_1() と Method_2() と呼びましょう。これらのメソッドでは Console.WriteLine("...") と呼ばれます

クラスがあります

public class CustomBackgroundWorker: BackgroundWorker
{
         private readonly StringBuilder logBuilder;

         public CustomBackgroundWorker ()
         {
             logBuilder = new StringBuilder ();
             TextWriter outStream = new StringWriter (logBuilder);
             Console.SetOut (outStream);
         }

         public string GetLogs ()
         {
             return logBuilder.ToString ();
         }
}

このクラスのインスタンスを 2 つ作成します。各インスタンスは、ライブラリからメソッドを実行します。ただし、SetOut() メソッドはグローバルに機能するため、出力は 1 つのストリームにのみ保存されます。出力を別のスレッドから別のストリームにリダイレクトすることは可能ですか?

どうも

4

1 に答える 1

4

あなたがやろうとしていることは簡単ではありません。Console.WriteLine() staticは共有されているためです。これらのメソッドを呼び出すスレッドは標準出力ストリームに書き込みます。

出力を個別のファイルに分割する最もクリーンな方法は、TextWriter複数の出力ファイルをラップする独自のファイルを作成し、それを標準出力として設定することです。TextWriter次に、必要な出力ファイルを指定して、各スレッド自体を に登録します。呼び出しがライターに着信するたびに、どのスレッドが呼び出しを行ったかを確認し、適切なファイルに書き込みます。

これを正しく行うには明らかにいくつかの作業が必要ですが (多数の競合状態やリソース共有の問題が発生する可能性があるため)、やりたいことができるようになります。

編集:これは、そのようなライターがどのように見えるか、およびそれがどのように使用されるかのサンプルです。このクラスは不完全で (たとえば、現在は s のみをサポートしていますWriteLine()) string、他のバグも存在する可能性があります。

public class ThreadAwareStreamWriter : TextWriter
{
    private ConcurrentDictionary<int, TextWriter> threadWriterMap;
    private TextWriter defaultWriter;

    public ThreadAwareStreamWriter()
    {
        this.threadWriterMap = new ConcurrentDictionary<int, TextWriter>();
        this.defaultWriter = Console.Out;
    }

    public TextWriter RegisterThreadWriter(TextWriter threadWriter)
    {
        int threadId = Thread.CurrentThread.ManagedThreadId;

        TextWriter oldWriter;
        this.threadWriterMap.TryGetValue(threadId, out oldWriter);
        this.threadWriterMap[threadId] = threadWriter;

        return oldWriter;
    }

    public void DeregisterThread()
    {
        TextWriter threadWriter;
        if (this.threadWriterMap.TryRemove(Thread.CurrentThread.ManagedThreadId, out threadWriter))
        {
            threadWriter.Close();
        }
    }

    public override Encoding Encoding
    {
        get 
        {
            TextWriter threadWriter;
            if (this.threadWriterMap.TryGetValue(Thread.CurrentThread.ManagedThreadId, out threadWriter))
            {
                return threadWriter.Encoding;
            }

            return this.defaultWriter.Encoding;
        }
    }

    public override void WriteLine(string value)
    {
        TextWriter threadWriter;
        if (this.threadWriterMap.TryGetValue(Thread.CurrentThread.ManagedThreadId, out threadWriter))
        {
            threadWriter.WriteLine(value);
            return;
        }

        if (this.defaultWriter != null)
        {
            this.defaultWriter.WriteLine(value);
        }
    }
}

サンプルプログラム:

public static void Main(string[] args)
{
    ThreadAwareStreamWriter writer = new ThreadAwareStreamWriter();
    Console.SetOut(writer);

    Thread t = new Thread(o =>
    {
        ThreadAwareStreamWriter tWriter = (ThreadAwareStreamWriter)o;
        tWriter.RegisterThreadWriter(new StreamWriter(File.Open("test.txt", FileMode.Create, FileAccess.ReadWrite)));
        Console.WriteLine("Hello from another thread");

        tWriter.DeregisterThread();
    });

    t.Start(writer);

    Console.WriteLine("Hello");
    Console.ReadLine();
}

これにより、「Hello」がコンソールに出力され、「Hello from another thread」がファイル「test.txt」に出力されます。

于 2012-05-31T18:55:00.220 に答える