From 65289bd8396d48ea027807c6d88b217f3e239f58 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 26 May 2026 17:01:02 +0000 Subject: [PATCH 1/2] Initial plan From 078699608645c353e021606d0f60dad1b69f7c38 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 26 May 2026 17:05:05 +0000 Subject: [PATCH 2/2] Fix Process standard stream examples to avoid resource leaks and add ownership remarks - Inline StandardOutput/StandardError stream access in examples to avoid undisposed StreamReader variables - Add IMPORTANT notes to StandardOutput, StandardError, and StandardInput documentation clarifying stream ownership and disposal responsibilities - Remove unused System.IO imports from updated snippets Agent-Logs-Url: https://github.com/dotnet/dotnet-api-docs/sessions/6f53bd78-3ca0-40fb-8937-2ca2c5abfd3e Co-authored-by: adamsitnik <6011991+adamsitnik@users.noreply.github.com> --- .../System.Diagnostics/Process/StandardError/source.cs | 4 +--- .../Process/StandardOutput/process_standardoutput.cs | 4 +--- .../System.Diagnostics/Process/StandardError/source.fs | 3 +-- .../Process/StandardOutput/process_standardoutput.fs | 3 +-- .../System.Diagnostics/Process/StandardError/source.vb | 4 +--- .../Process/StandardOutput/process_standardoutput.vb | 8 +++----- xml/System.Diagnostics/Process.xml | 9 +++++++++ 7 files changed, 17 insertions(+), 18 deletions(-) diff --git a/snippets/csharp/System.Diagnostics/Process/StandardError/source.cs b/snippets/csharp/System.Diagnostics/Process/StandardError/source.cs index 85a554a5d6e..74e39dec789 100644 --- a/snippets/csharp/System.Diagnostics/Process/StandardError/source.cs +++ b/snippets/csharp/System.Diagnostics/Process/StandardError/source.cs @@ -9,7 +9,6 @@ net.exe process and reads output from its stream reader.*/ using System; using System.Diagnostics; -using System.IO; namespace Process_StandardError { @@ -43,9 +42,8 @@ public static void GetStandardError(string[] args) myProcess.StartInfo = myProcessStartInfo; myProcess.Start(); - StreamReader myStreamReader = myProcess.StandardError; // Read the standard error of net.exe and write it on to console. - Console.WriteLine(myStreamReader.ReadLine()); + Console.WriteLine(myProcess.StandardError.ReadLine()); } // } diff --git a/snippets/csharp/System.Diagnostics/Process/StandardOutput/process_standardoutput.cs b/snippets/csharp/System.Diagnostics/Process/StandardOutput/process_standardoutput.cs index 803e2038c5c..30337b58dab 100644 --- a/snippets/csharp/System.Diagnostics/Process/StandardOutput/process_standardoutput.cs +++ b/snippets/csharp/System.Diagnostics/Process/StandardOutput/process_standardoutput.cs @@ -1,5 +1,4 @@ using System; -using System.IO; using System.Diagnostics; class StandardOutputExample @@ -14,8 +13,7 @@ public static void Main() process.Start(); // Synchronously read the standard output of the spawned process. - StreamReader reader = process.StandardOutput; - string output = reader.ReadToEnd(); + string output = process.StandardOutput.ReadToEnd(); // Write the redirected output to this application's window. Console.WriteLine(output); diff --git a/snippets/fsharp/System.Diagnostics/Process/StandardError/source.fs b/snippets/fsharp/System.Diagnostics/Process/StandardError/source.fs index 31dd7131772..b877eb6a02f 100644 --- a/snippets/fsharp/System.Diagnostics/Process/StandardError/source.fs +++ b/snippets/fsharp/System.Diagnostics/Process/StandardError/source.fs @@ -9,7 +9,6 @@ myProcessStartInfo.RedirectStandardError <- true myProcess.StartInfo <- myProcessStartInfo myProcess.Start() |> ignore -let myStreamReader = myProcess.StandardError // Read the standard error of net.exe and write it on to console. -printfn $"{myStreamReader.ReadLine()}" +printfn $"{myProcess.StandardError.ReadLine()}" // diff --git a/snippets/fsharp/System.Diagnostics/Process/StandardOutput/process_standardoutput.fs b/snippets/fsharp/System.Diagnostics/Process/StandardOutput/process_standardoutput.fs index 11bb7ae69e1..d325e9feb30 100644 --- a/snippets/fsharp/System.Diagnostics/Process/StandardOutput/process_standardoutput.fs +++ b/snippets/fsharp/System.Diagnostics/Process/StandardOutput/process_standardoutput.fs @@ -9,8 +9,7 @@ proc.StartInfo.RedirectStandardOutput <- true proc.Start() |> ignore // Synchronously read the standard output of the spawned process. -let reader = proc.StandardOutput -let output = reader.ReadToEnd() +let output = proc.StandardOutput.ReadToEnd() // Write the redirected output to this application's window. printfn $"{output}" diff --git a/snippets/visualbasic/System.Diagnostics/Process/StandardError/source.vb b/snippets/visualbasic/System.Diagnostics/Process/StandardError/source.vb index 930bc8d2cb6..a4a85899c7b 100644 --- a/snippets/visualbasic/System.Diagnostics/Process/StandardError/source.vb +++ b/snippets/visualbasic/System.Diagnostics/Process/StandardError/source.vb @@ -9,7 +9,6 @@ Imports System.Diagnostics Imports System.ComponentModel -Imports System.IO Namespace Process_StandardError @@ -37,9 +36,8 @@ Namespace Process_StandardError myProcess.StartInfo = myProcessStartInfo myProcess.Start() - Dim myStreamReader As StreamReader = myProcess.StandardError ' Read the standard error of net.exe and write it on to console. - Console.WriteLine(myStreamReader.ReadLine()) + Console.WriteLine(myProcess.StandardError.ReadLine()) End Using ' End Sub diff --git a/snippets/visualbasic/System.Diagnostics/Process/StandardOutput/process_standardoutput.vb b/snippets/visualbasic/System.Diagnostics/Process/StandardOutput/process_standardoutput.vb index 7e22ecbf61c..cf843bdbc4e 100644 --- a/snippets/visualbasic/System.Diagnostics/Process/StandardOutput/process_standardoutput.vb +++ b/snippets/visualbasic/System.Diagnostics/Process/StandardOutput/process_standardoutput.vb @@ -1,5 +1,4 @@ -Imports System.IO -Imports System.Diagnostics +Imports System.Diagnostics Module Module1 Sub Main() @@ -9,9 +8,8 @@ Module Module1 process.StartInfo.RedirectStandardOutput = True process.Start() - ' Synchronously read the standard output of the spawned process. - Dim reader As StreamReader = process.StandardOutput - Dim output As String = reader.ReadToEnd() + ' Synchronously read the standard output of the spawned process. + Dim output As String = process.StandardOutput.ReadToEnd() Console.WriteLine(output) process.WaitForExit() diff --git a/xml/System.Diagnostics/Process.xml b/xml/System.Diagnostics/Process.xml index 947837ef0f4..2028835b089 100644 --- a/xml/System.Diagnostics/Process.xml +++ b/xml/System.Diagnostics/Process.xml @@ -5085,6 +5085,9 @@ If no main module is found, it could be because the process hasn't finished load The redirected stream can be read synchronously or asynchronously. Methods such as , , and perform synchronous read operations on the error output stream of the process. These synchronous read operations do not complete until the associated writes to its stream, or closes the stream. +> [!IMPORTANT] +> When you read from the stream synchronously (for example, by calling or ), the no longer disposes the stream when the process is disposed. In this case, you're responsible for disposing the returned by , or you can call methods directly on the property (for example, `process.StandardError.ReadToEnd()`) within a `using` block for the instance. If you use to read the stream asynchronously, the retains ownership of the stream and disposes it when the process is disposed. + In contrast, starts asynchronous read operations on the stream. This method enables a designated event handler for the stream output and immediately returns to the caller, which can perform other work while the stream output is directed to the event handler. Synchronous read operations introduce a dependency between the caller reading from the stream and the child process writing to that stream. These dependencies can result in deadlock conditions. When the caller reads from the redirected stream of a child process, it is dependent on the child. The caller waits on the read operation until the child writes to the stream or closes the stream. When the child process writes enough data to fill its redirected stream, it is dependent on the parent. The child process waits on the next write operation until the parent reads from the full stream or closes the stream. The deadlock condition results when the caller and child process wait on each other to complete an operation, and neither can proceed. You can avoid deadlocks by evaluating dependencies between the caller and child process. @@ -5181,6 +5184,9 @@ You can use asynchronous read operations to avoid these dependencies and their d > [!NOTE] > To use , you must set to `false`, and you must set to `true`. Otherwise, writing to the stream throws an exception. +> [!IMPORTANT] +> When you access the stream, the no longer disposes the stream when the process is disposed. In this case, you're responsible for closing the by calling , or you can rely on disposing the within a `using` block and accessing inline. + ## Examples @@ -5249,6 +5255,9 @@ You can use asynchronous read operations to avoid these dependencies and their d The redirected stream can be read synchronously or asynchronously. Methods such as , , and perform synchronous read operations on the output stream of the process. These synchronous read operations do not complete until the associated writes to its stream, or closes the stream. +> [!IMPORTANT] +> When you read from the stream synchronously (for example, by calling or ), the no longer disposes the stream when the process is disposed. In this case, you're responsible for disposing the returned by , or you can call methods directly on the property (for example, `process.StandardOutput.ReadToEnd()`) within a `using` block for the instance. If you use to read the stream asynchronously, the retains ownership of the stream and disposes it when the process is disposed. + In contrast, starts asynchronous read operations on the stream. This method enables a designated event handler for the stream output and immediately returns to the caller, which can perform other work while the stream output is directed to the event handler. Synchronous read operations introduce a dependency between the caller reading from the stream and the child process writing to that stream. These dependencies can result in deadlock conditions. When the caller reads from the redirected stream of a child process, it is dependent on the child. The caller waits on the read operation until the child writes to the stream or closes the stream. When the child process writes enough data to fill its redirected stream, it is dependent on the parent. The child process waits on the next write operation until the parent reads from the full stream or closes the stream. The deadlock condition results when the caller and child process wait on each other to complete an operation, and neither can proceed. You can avoid deadlocks by evaluating dependencies between the caller and child process.