Repository: dotnet/runtime
File: src/libraries/System.Console/src/System/ConsolePal.Windows.cs (C#)

Code before:

            // If someone launches a managed process via CreateProcess, stdout
            // could be set to INVALID_HANDLE_VALUE or they might use 0 as an invalid handle.
            // We also need to ensure that the handle is writable.
            if (handle == IntPtr.Zero || handle == InvalidHandleValue || !ConsoleHandleIsWritable(handle))
            {
                throw new IOException(SR.IO_NoConsole);
            }

            return new SafeFileHandle(handle, ownsHandle: false);
        }

        public static SafeFileHandle OpenStandardErrorHandle()
        {
            IntPtr handle = Interop.Kernel32.GetStdHandle(Interop.Kernel32.HandleTypes.STD_ERROR_HANDLE);

            // If someone launches a managed process via CreateProcess, stderr
            // could be set to INVALID_HANDLE_VALUE or they might use 0 as an invalid handle.
            // We also need to ensure that the handle is writable.
            if (handle == IntPtr.Zero || handle == InvalidHandleValue || !ConsoleHandleIsWritable(handle))
            {
                throw new IOException(SR.IO_NoConsole);
            }

            return new SafeFileHandle(handle, ownsHandle: false);
        }

        public static Encoding InputEncoding
        {
            get { return EncodingHelper.GetSupportedConsoleEncoding((int)Interop.Kernel32.GetConsoleCP()); }
        }

        public static void SetConsoleInputEncoding(Encoding enc)
        {
            if (enc.CodePage != UnicodeCodePage)
            {
                if (!Interop.Kernel32.SetConsoleCP(enc.CodePage))
                {
                    HandleSetConsoleEncodingError(Marshal.GetLastPInvokeError());
                }
            }
        }

        public static Encoding OutputEncoding
        {
            get { return EncodingHelper.GetSupportedConsoleEncoding((int)Interop.Kernel32.GetConsoleOutputCP()); }
        }

        public static void SetConsoleOutputEncoding(Encoding enc)
        {
            if (enc.CodePage != UnicodeCodePage)

Review comment (refactor):
Let's introduce a helper to reduce code duplication. Something like this:

```suggestion
        public static SafeFileHandle OpenStandardInputHandle() => OpenStandardHandle(Interop.Kernel32.HandleTypes.STD_INPUT_HANDLE);

        public static SafeFileHandle OpenStandardOutputHandle() => OpenStandardHandle(Interop.Kernel32.HandleTypes.STD_OUTPUT_HANDLE);

        public static SafeFileHandle OpenStandardErrorHandle() => OpenStandardHandle(Interop.Kernel32.HandleTypes.STD_ERROR_HANDLE);

        private static SafeFileHandle OpenStandardHandle(int handleType)
        {
            IntPtr handle = Interop.Kernel32.GetStdHandle(handleType);
            bool isReadable = handleType == Interop.Kernel32.HandleTypes.STD_INPUT_HANDLE;

            // If someone launches a managed process via CreateProcess, stderr
            // could be set to INVALID_HANDLE_VALUE or they might use 0 as an invalid handle.
            // We also need to ensure that the handle is writable.
            if (handle == IntPtr.Zero || handle == InvalidHandleValue 
                || (isReadable ? !ConsoleHandleIsReadable(handle) : !ConsoleHandleIsWritable(handle)))
            {
                throw new IOException(SR.IO_NoConsole);
            }

            return new SafeFileHandle(handle, ownsHandle: false);
        }
```

Code after:
            get { return EncodingHelper.GetSupportedConsoleEncoding((int)Interop.Kernel32.GetConsoleOutputCP()); }
        }

        public static void SetConsoleOutputEncoding(Encoding enc)
        {
            if (enc.CodePage != UnicodeCodePage)
            {
                if (!Interop.Kernel32.SetConsoleOutputCP(enc.CodePage))
                {
                    HandleSetConsoleEncodingError(Marshal.GetLastPInvokeError());
                }
            }
        }

        private static void HandleSetConsoleEncodingError(int lastError)
        {
            if (lastError == Interop.Errors.ERROR_INVALID_HANDLE
                || lastError == Interop.Errors.ERROR_INVALID_ACCESS)
            {
                // no console, or not a valid handle, so fail silently
                return;
            }

            throw Win32Marshal.GetExceptionForWin32Error(lastError);
        }

        /// <summary>Gets whether Console.In is targeting a terminal display.</summary>
        public static bool IsInputRedirectedCore()
        {
            return IsHandleRedirected(InputHandle);
        }

        /// <summary>Gets whether Console.Out is targeting a terminal display.</summary>
        public static bool IsOutputRedirectedCore()
        {
            return IsHandleRedirected(OutputHandle);
        }

        /// <summary>Gets whether Console.In is targeting a terminal display.</summary>
        public static bool IsErrorRedirectedCore()
        {
            return IsHandleRedirected(ErrorHandle);
        }

        private static bool IsHandleRedirected(IntPtr handle)
        {
            // If handle is not to a character device, we must be redirected:
            uint fileType = Interop.Kernel32.GetFileType(handle);
            if ((fileType & Interop.Kernel32.FileTypes.FILE_TYPE_CHAR) != Interop.Kernel32.FileTypes.FILE_TYPE_CHAR)
                return true;