System.Console class

This article provides supplementary remarks to the reference documentation for this API.

The console is an operating system window where users interact with the operating system or with a text-based console application by entering text input through the computer keyboard, and by reading text output from the computer terminal. For example, in the Windows operating system, the console is called the Command Prompt window and accepts MS-DOS commands. The Console class provides basic support for applications that read characters from, and write characters to, the console.

Console I/O streams

When a console application starts, the operating system automatically associates three I/O streams with the console: standard input stream, standard output stream, and standard error output stream. Your application can read user input from the standard input stream; write normal data to the standard output stream; and write error data to the standard error output stream. These streams are presented to your application as the values of the Console.In, Console.Out, and Console.Error properties.

By default, the value of the In property is a System.IO.TextReader object that represents the keyboard, and the values of the Out and Error properties are System.IO.TextWriter objects that represent a console window. However, you can set these properties to streams that do not represent the console window or keyboard; for example, you can set these properties to streams that represent files. To redirect the standard input, standard output, or standard error stream, call the Console.SetIn, Console.SetOut, or Console.SetError method, respectively. I/O operations that use these streams are synchronized, which means that multiple threads can read from, or write to, the streams. This means that methods that are ordinarily asynchronous, such as TextReader.ReadLineAsync, execute synchronously if the object represents a console stream.

Note

Do not use the Console class to display output in unattended applications, such as server applications. Calls to methods such as Console.Write and Console.WriteLine have no effect in GUI applications.

Console class members that work normally when the underlying stream is directed to a console might throw an exception if the stream is redirected, for example, to a file. Program your application to catch System.IO.IOException exceptions if you redirect a standard stream. You can also use the IsOutputRedirected, IsInputRedirected, and IsErrorRedirected properties to determine whether a standard stream is redirected before performing an operation that throws an System.IO.IOException exception.

It is sometimes useful to explicitly call the members of the stream objects represented by the In, Out, and Error properties. For example, by default, the Console.ReadLine method reads input from the standard input stream. Similarly, the Console.WriteLine method writes data to the standard output stream, and the data is followed by the default line termination string, which can be found at Environment.NewLine. However, the Console class does not provide a corresponding method to write data to the standard error output stream, or a property to change the line termination string for data written to that stream.

You can solve this problem by setting the TextWriter.NewLine property of the Out or Error property to another line termination string. For example, the following C# statement sets the line termination string for the standard error output stream to two carriage return and line feed sequences:

Console.Error.NewLine = "\r\n\r\n";

You can then explicitly call the WriteLine method of the error output stream object, as in the following C# statement:

Console.Error.WriteLine();

Screen buffer and console window

Two closely related features of the console are the screen buffer and the console window. Text is actually read from or written to streams owned by the console, but appear to be read from or written to an area owned by the console called the screen buffer. The screen buffer is an attribute of the console, and is organized as a rectangular grid of rows and columns where each grid intersection, or character cell, can contain a character. Each character has its own foreground color, and each character cell has its own background color.

The screen buffer is viewed through a rectangular region called the console window. The console window is another attribute of the console; it is not the console itself, which is an operating system window. The console window is arranged in rows and columns, is less than or equal to the size of the screen buffer, and can be moved to view different areas of the underlying screen buffer. If the screen buffer is larger than the console window, the console automatically displays scroll bars so the console window can be repositioned over the screen buffer area.

A cursor indicates the screen buffer position where text is currently read or written. The cursor can be hidden or made visible, and its height can be changed. If the cursor is visible, the console window position is moved automatically so the cursor is always in view.

The origin for character cell coordinates in the screen buffer is the upper left corner, and the positions of the cursor and the console window are measured relative to that origin. Use zero-based indexes to specify positions; that is, specify the topmost row as row 0, and the leftmost column as column 0. The maximum value for the row and column indexes is Int16.MaxValue.

Unicode support for the console

In general, the console reads input and writes output by using the current console code page, which the system locale defines by default. A code page can handle only a subset of available Unicode characters, so if you try to display characters that are not mapped by a particular code page, the console won't be able to display all characters or represent them accurately. The following example illustrates this problem. It tries to display the characters of the Cyrillic alphabet from U+0410 to U+044F to the console. If you run the example on a system that uses console code page 437, each character is replaced by a question mark (?), because Cyrillic characters do not map to the characters in code page 437.

using System;

public class Example3
{
    public static void Main()
    {
        // Create a Char array for the modern Cyrillic alphabet,
        // from U+0410 to U+044F.
        int nChars = 0x044F - 0x0410 + 1;
        char[] chars = new char[nChars];
        ushort codePoint = 0x0410;
        for (int ctr = 0; ctr < chars.Length; ctr++)
        {
            chars[ctr] = (char)codePoint;
            codePoint++;
        }

        Console.WriteLine("Current code page: {0}\n",
                          Console.OutputEncoding.CodePage);
        // Display the characters.
        foreach (var ch in chars)
        {
            Console.Write("{0}  ", ch);
            if (Console.CursorLeft >= 70)
                Console.WriteLine();
        }
    }
}
// The example displays the following output:
//    Current code page: 437
//
//    ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?
//    ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?
//    ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?
Module Example
   Public Sub Main()
      ' Create a Char array for the modern Cyrillic alphabet, 
      ' from U+0410 to U+044F.
      Dim nChars As Integer = &h44F - &h0410
      Dim chars(nChars) As Char
      Dim codePoint As UInt16 = &h0410
      For ctr As Integer = 0 To chars.Length - 1
        chars(ctr) = ChrW(codePoint)
        codePoint += CType(1, UShort)
      Next   
         
      Console.WriteLine("Current code page: {0}", 
                        Console.OutputEncoding.CodePage)
      Console.WriteLine()
      ' Display the characters.
      For Each ch In chars
         Console.Write("{0}  ", ch)
         If Console.CursorLeft >= 70 Then Console.WriteLine()
      Next
   End Sub
End Module
' The example displays the following output:
'       Current code page: 437
'       
'       ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?
'       ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?
'       ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?
open System

// Create a char List for the modern Cyrillic alphabet,
// from U+0410 to U+044F.
let chars =
    [ for codePoint in 0x0410 .. 0x044F do
        Convert.ToChar codePoint ]

printfn "Current code page: %i\n" Console.OutputEncoding.CodePage
// Display the characters.
for ch in chars do
    printf "%c  " ch
    if Console.CursorLeft >= 70 then Console.WriteLine()

// The example displays the following output:
//    Current code page: 437
//
//    ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?
//    ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?
//    ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?

In addition to supporting code pages, the Console class supports UTF-8 encoding with the UTF8Encoding class. Beginning with .NET Framework 4.5, the Console class also supports UTF-16 encoding with the UnicodeEncoding class. To display Unicode characters to the console. you set the OutputEncoding property to either UTF8Encoding or UnicodeEncoding.

Support for Unicode characters requires the encoder to recognize a particular Unicode character, and also requires a font that has the glyphs needed to render that character. To successfully display Unicode characters to the console, the console font must be set to a non-raster or TrueType font such as Consolas or Lucida Console. The following example shows how you can programmatically change the font from a raster font to Lucida Console.

using System;
using System.Runtime.InteropServices;

public class Example2
{
    [DllImport("kernel32.dll", SetLastError = true)]
    static extern IntPtr GetStdHandle(int nStdHandle);

    [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    static extern bool GetCurrentConsoleFontEx(
           IntPtr consoleOutput,
           bool maximumWindow,
           ref CONSOLE_FONT_INFO_EX lpConsoleCurrentFontEx);

    [DllImport("kernel32.dll", SetLastError = true)]
    static extern bool SetCurrentConsoleFontEx(
           IntPtr consoleOutput,
           bool maximumWindow,
           CONSOLE_FONT_INFO_EX consoleCurrentFontEx);

    private const int STD_OUTPUT_HANDLE = -11;
    private const int TMPF_TRUETYPE = 4;
    private const int LF_FACESIZE = 32;
    private static IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1);

    public static unsafe void Main()
    {
        string fontName = "Lucida Console";
        IntPtr hnd = GetStdHandle(STD_OUTPUT_HANDLE);
        if (hnd != INVALID_HANDLE_VALUE)
        {
            CONSOLE_FONT_INFO_EX info = new CONSOLE_FONT_INFO_EX();
            info.cbSize = (uint)Marshal.SizeOf(info);
            bool tt = false;
            // First determine whether there's already a TrueType font.
            if (GetCurrentConsoleFontEx(hnd, false, ref info))
            {
                tt = (info.FontFamily & TMPF_TRUETYPE) == TMPF_TRUETYPE;
                if (tt)
                {
                    Console.WriteLine("The console already is using a TrueType font.");
                    return;
                }
                // Set console font to Lucida Console.
                CONSOLE_FONT_INFO_EX newInfo = new CONSOLE_FONT_INFO_EX();
                newInfo.cbSize = (uint)Marshal.SizeOf(newInfo);
                newInfo.FontFamily = TMPF_TRUETYPE;
                IntPtr ptr = new IntPtr(newInfo.FaceName);
                Marshal.Copy(fontName.ToCharArray(), 0, ptr, fontName.Length);
                // Get some settings from current font.
                newInfo.dwFontSize = new COORD(info.dwFontSize.X, info.dwFontSize.Y);
                newInfo.FontWeight = info.FontWeight;
                SetCurrentConsoleFontEx(hnd, false, newInfo);
            }
        }
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct COORD
    {
        internal short X;
        internal short Y;

        internal COORD(short x, short y)
        {
            X = x;
            Y = y;
        }
    }

    [StructLayout(LayoutKind.Sequential)]
    internal unsafe struct CONSOLE_FONT_INFO_EX
    {
        internal uint cbSize;
        internal uint nFont;
        internal COORD dwFontSize;
        internal int FontFamily;
        internal int FontWeight;
        internal fixed char FaceName[LF_FACESIZE];
    }
}
Imports System.Runtime.InteropServices

Public Module Example5
    ' <DllImport("kernel32.dll", SetLastError = true)>
    Private Declare Function GetStdHandle Lib "Kernel32" (
                   nStdHandle As Integer) As IntPtr

    ' [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    Private Declare Function GetCurrentConsoleFontEx Lib "Kernel32" (
                   consoleOutput As IntPtr,
                   maximumWindow As Boolean,
                   ByRef lpConsoleCurrentFontEx As CONSOLE_FONT_INFO_EX) As Boolean

    ' [DllImport("kernel32.dll", SetLastError = true)]
    Private Declare Function SetCurrentConsoleFontEx Lib "Kernel32" (
                   consoleOutput As IntPtr,
                   maximumWindow As Boolean,
                   consoleCurrentFontEx As CONSOLE_FONT_INFO_EX) As Boolean

    Private Const STD_OUTPUT_HANDLE As Integer = -11
    Private Const TMPF_TRUETYPE As Integer = 4
    Private Const LF_FACESIZE As Integer = 32
    Private INVALID_HANDLE_VALUE As IntPtr = New IntPtr(-1)

    Public Sub Main()
        Dim fontName As String = "Lucida Console"
        Dim hnd As IntPtr = GetStdHandle(STD_OUTPUT_HANDLE)
        If hnd <> INVALID_HANDLE_VALUE Then
            Dim info As CONSOLE_FONT_INFO_EX = New CONSOLE_FONT_INFO_EX()
            info.cbSize = CUInt(Marshal.SizeOf(info))
            Dim tt As Boolean = False
            ' First determine whether there's already a TrueType font.
            If GetCurrentConsoleFontEx(hnd, False, info) Then
                tt = (info.FontFamily And TMPF_TRUETYPE) = TMPF_TRUETYPE
                If tt Then
                    Console.WriteLine("The console already is using a TrueType font.")
                    Return
                End If
                ' Set console font to Lucida Console.
                Dim newInfo As CONSOLE_FONT_INFO_EX = New CONSOLE_FONT_INFO_EX()
                newInfo.cbSize = CUInt(Marshal.SizeOf(newInfo))
                newInfo.FontFamily = TMPF_TRUETYPE
                newInfo.FaceName = fontName
                ' Get some settings from current font.
                newInfo.dwFontSize = New COORD(info.dwFontSize.X, info.dwFontSize.Y)
                newInfo.FontWeight = info.FontWeight
                SetCurrentConsoleFontEx(hnd, False, newInfo)
            End If
        End If
    End Sub

    <StructLayout(LayoutKind.Sequential)> Friend Structure COORD
        Friend X As Short
        Friend Y As Short

        Friend Sub New(x As Short, y As Short)
            Me.X = x
            Me.Y = y
        End Sub
    End Structure

    <StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Unicode)> Friend Structure CONSOLE_FONT_INFO_EX
        Friend cbSize As UInteger
        Friend nFont As UInteger
        Friend dwFontSize As COORD
        Friend FontFamily As Integer
        Friend FontWeight As Integer
        <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=32)> Friend FaceName As String
    End Structure
End Module
module Example

open System
open System.Runtime.InteropServices

[<Literal>]
let STD_OUTPUT_HANDLE = -11

[<Literal>]
let TMPF_TRUETYPE = 4

[<Literal>]
let LF_FACESIZE = 32

let INVALID_HANDLE_VALUE = IntPtr(-1)


[<Struct>]
[<StructLayout(LayoutKind.Sequential)>]
type COORD =
    val mutable X: int16
    val mutable Y: int16

    internal new(x: int16, y: int16) =
        { X = x
          Y = y }

[<Struct>]
[<StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)>]
type CONSOLE_FONT_INFO_EX =
    val mutable cbSize: uint32
    val mutable nFont: uint32
    val mutable dwFontSize: COORD
    val mutable FontFamily: int
    val mutable FontWeight: int
    [<MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)>]
    val mutable FaceName: string

[<DllImport("kernel32.dll", SetLastError = true)>]
extern IntPtr GetStdHandle(int nStdHandle)

[<DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)>]
extern bool GetCurrentConsoleFontEx(IntPtr consoleOutput, bool maximumWindow, CONSOLE_FONT_INFO_EX lpConsoleCurrentFontEx)

[<DllImport("kernel32.dll", SetLastError = true)>]
extern bool SetCurrentConsoleFontEx(IntPtr consoleOutput, bool maximumWindow, CONSOLE_FONT_INFO_EX consoleCurrentFontEx)

[<EntryPoint>]
let main argv =
    let fontName = "Lucida Console"
    let hnd = GetStdHandle(STD_OUTPUT_HANDLE)
    if hnd <> INVALID_HANDLE_VALUE then
        let mutable info = CONSOLE_FONT_INFO_EX()
        info.cbSize <- uint32 (Marshal.SizeOf(info))
        // First determine whether there's already a TrueType font.
        if (GetCurrentConsoleFontEx(hnd, false, info)) then
            if (((info.FontFamily) &&& TMPF_TRUETYPE) = TMPF_TRUETYPE) then
                Console.WriteLine("The console already is using a TrueType font.")
            else
                // Set console font to Lucida Console.
                let mutable newInfo = CONSOLE_FONT_INFO_EX()
                newInfo.cbSize <- uint32 (Marshal.SizeOf(newInfo))
                newInfo.FontFamily <- TMPF_TRUETYPE
                newInfo.FaceName <- fontName
                // Get some settings from current font.
                newInfo.dwFontSize <- COORD(info.dwFontSize.X, info.dwFontSize.Y)
                newInfo.FontWeight <- info.FontWeight
                SetCurrentConsoleFontEx(hnd, false, newInfo) |> ignore
                Console.WriteLine("The console is now using a TrueType font.")

    // Return zero for success
    0

However, TrueType fonts can display only a subset of glyphs. For example, the Lucida Console font displays only 643 of the approximately 64,000 available characters from U+0021 to U+FB02. To see which characters a particular font supports, open the Fonts applet in Control Panel, choose the Find a character option, and choose the font whose character set you'd like to examine in the Font list of the Character Map window.

Windows uses font linking to display glyphs that are not available in a particular font. For information about font linking to display additional character sets, see Globalization Step-by-Step: Fonts. Linked fonts are defined in the HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\FontLink\SystemLink subkey of the registry. Each entry associated with this subkey corresponds to the name of a base font, and its value is a string array that defines the font files and the fonts that are linked to the base font. Each member of the array defines a linked font and takes the form font-file-name,font-name. The following example illustrates how you can programmatically define a linked font named SimSun found in a font file named simsun.ttc that displays Simplified Han characters.

using Microsoft.Win32;
using System;

public class Example
{
   public static void Main()
   {
      string valueName = "Lucida Console";
      string newFont = "simsun.ttc,SimSun";
      string[] fonts = null;
      RegistryValueKind kind = 0;
      bool toAdd;

      RegistryKey key = Registry.LocalMachine.OpenSubKey(
                 @"Software\Microsoft\Windows NT\CurrentVersion\FontLink\SystemLink",
                 true);
      if (key == null) {
         Console.WriteLine("Font linking is not enabled.");
      }
      else {
         // Determine if the font is a base font.
         string[] names = key.GetValueNames();
         if (Array.Exists(names, s => s.Equals(valueName,
                                      StringComparison.OrdinalIgnoreCase))) {
            // Get the value's type.
            kind = key.GetValueKind(valueName);

            // Type should be RegistryValueKind.MultiString, but we can't be sure.
            switch (kind) {
               case RegistryValueKind.String:
                  fonts = new string[] { (string) key.GetValue(valueName) };
                  break;
               case RegistryValueKind.MultiString:
                  fonts = (string[]) key.GetValue(valueName);
                  break;
               case RegistryValueKind.None:
                  // Do nothing.
                  fonts = new string[] { };
                  break;
            }
            // Determine whether SimSun is a linked font.
            if (Array.FindIndex(fonts, s =>s.IndexOf("SimSun",
                                       StringComparison.OrdinalIgnoreCase) >=0) >= 0) {
               Console.WriteLine("Font is already linked.");
               toAdd = false;
            }
            else {
               // Font is not a linked font.
               toAdd = true;
            }
         }
         else {
            // Font is not a base font.
            toAdd = true;
            fonts = new string[] { };
         }

         if (toAdd) {
            Array.Resize(ref fonts, fonts.Length + 1);
            fonts[fonts.GetUpperBound(0)] = newFont;
            // Change REG_SZ to REG_MULTI_SZ.
            if (kind == RegistryValueKind.String)
               key.DeleteValue(valueName, false);

            key.SetValue(valueName, fonts, RegistryValueKind.MultiString);
            Console.WriteLine("SimSun added to the list of linked fonts.");
         }
      }

      if (key != null) key.Close();
   }
}
Imports Microsoft.Win32

Module Example2
    Public Sub Main()
        Dim valueName As String = "Lucida Console"
        Dim newFont As String = "simsun.ttc,SimSun"
        Dim fonts() As String = Nothing
        Dim kind As RegistryValueKind
        Dim toAdd As Boolean

        Dim key As RegistryKey = Registry.LocalMachine.OpenSubKey(
                 "Software\Microsoft\Windows NT\CurrentVersion\FontLink\SystemLink",
                 True)
        If key Is Nothing Then
            Console.WriteLine("Font linking is not enabled.")
        Else
            ' Determine if the font is a base font.
            Dim names() As String = key.GetValueNames()
            If Array.Exists(names, Function(s) s.Equals(valueName,
                                                     StringComparison.OrdinalIgnoreCase)) Then
                ' Get the value's type.
                kind = key.GetValueKind(valueName)

                ' Type should be RegistryValueKind.MultiString, but we can't be sure.
                Select Case kind
                    Case RegistryValueKind.String
                        fonts = {CStr(key.GetValue(valueName))}
                    Case RegistryValueKind.MultiString
                        fonts = CType(key.GetValue(valueName), String())
                    Case RegistryValueKind.None
                        ' Do nothing.
                        fonts = {}
                End Select
                ' Determine whether SimSun is a linked font.
                If Array.FindIndex(fonts, Function(s) s.IndexOf("SimSun",
                                      StringComparison.OrdinalIgnoreCase) >= 0) >= 0 Then
                    Console.WriteLine("Font is already linked.")
                    toAdd = False
                Else
                    ' Font is not a linked font.
                    toAdd = True
                End If
            Else
                ' Font is not a base font.
                toAdd = True
                fonts = {}
            End If

            If toAdd Then
                Array.Resize(fonts, fonts.Length + 1)
                fonts(fonts.GetUpperBound(0)) = newFont
                ' Change REG_SZ to REG_MULTI_SZ.
                If kind = RegistryValueKind.String Then
                    key.DeleteValue(valueName, False)
                End If
                key.SetValue(valueName, fonts, RegistryValueKind.MultiString)
                Console.WriteLine("SimSun added to the list of linked fonts.")
            End If
        End If

        If key IsNot Nothing Then key.Close()
    End Sub
End Module
open System
open Microsoft.Win32

let valueName = "Lucida Console"
let newFont = "simsun.ttc,SimSun"

let key =
    Registry.LocalMachine.OpenSubKey(@"Software\Microsoft\Windows NT\CurrentVersion\FontLink\SystemLink", true)
if isNull key then
    printfn "Font linking is not enabled."
else
    // Determine if the font is a base font.
    let names = key.GetValueNames()

    let (fonts, kind, toAdd) =
        if names |> Array.exists (fun s -> s.Equals(valueName, StringComparison.OrdinalIgnoreCase)) then
            // Get the value's type.
            let kind = key.GetValueKind(valueName)

            // Type should be RegistryValueKind.MultiString, but we can't be sure.
            let fonts =
                match kind with
                | RegistryValueKind.String -> [| key.GetValue(valueName) :?> string |]
                | RegistryValueKind.MultiString -> (key.GetValue(valueName) :?> string array)
                | _ -> [||]

            // Determine whether SimSun is a linked font.
            let toAdd =
                not (fonts |> Array.exists (fun s -> s.IndexOf("SimSun", StringComparison.OrdinalIgnoreCase) >= 0))

            (fonts, kind, toAdd)
        else
            // Font is not a base font.
            ([||], RegistryValueKind.Unknown, true)

    if toAdd then
        // Font is not a linked font.
        let newFonts = Array.append fonts [| newFont |]

        // Change REG_SZ to REG_MULTI_SZ.
        if kind = RegistryValueKind.String then key.DeleteValue(valueName, false)

        key.SetValue(valueName, newFonts, RegistryValueKind.MultiString)
        printfn "SimSun added to the list of linked fonts."
    else
        printfn "Font is already linked."


if not (isNull key) then key.Close()

Unicode support for the console has the following limitations:

  • UTF-32 encoding is not supported. The only supported Unicode encodings are UTF-8 and UTF-16, which are represented by the UTF8Encoding and UnicodeEncoding classes, respectively.

  • Bidirectional output is not supported.

  • Display of characters outside the Basic Multilingual Plane (that is, of surrogate pairs) is not supported, even if they are defined in a linked font file.

  • Display of characters in complex scripts is not supported.

  • Combining character sequences (that is, characters that consist of a base character and one or more combining characters) are displayed as separate characters. To work around this limitation, you can normalize the string to be displayed by calling the String.Normalize method before sending output to the console. In the following example, a string that contains the combining character sequence U+0061 U+0308 is displayed to the console as two characters before the output string is normalized, and as a single character after the String.Normalize method is called.

    using System;
    using System.IO;
    
    public class Example1
    {
        public static void Main()
        {
            char[] chars = { '\u0061', '\u0308' };
    
            string combining = new String(chars);
            Console.WriteLine(combining);
    
            combining = combining.Normalize();
            Console.WriteLine(combining);
        }
    }
    // The example displays the following output:
    //       a"
    //       ä
    
    Module Example3
        Public Sub Main()
            Dim chars() As Char = {ChrW(&H61), ChrW(&H308)}
    
            Dim combining As String = New String(chars)
            Console.WriteLine(combining)
    
            combining = combining.Normalize()
            Console.WriteLine(combining)
        End Sub
    End Module
    ' The example displays the following output:
    '       a"
    '       ä
    
    open System
    
    let chars = [| '\u0061'; '\u0308' |]
    
    let combining = String chars
    Console.WriteLine combining
    
    let combining2 = combining.Normalize()
    Console.WriteLine combining2
    
    
    // The example displays the following output:
    //       a"
    //       ä
    

    Normalization is a viable solution only if the Unicode standard for the character includes a pre-composed form that corresponds to a particular combining character sequence.

  • If a font provides a glyph for a code point in the private use area, that glyph will be displayed. However, because characters in the private use area are application-specific, this may not be the expected glyph.

The following example displays a range of Unicode characters to the console. The example accepts three command-line parameters: the start of the range to display, the end of the range to display, and whether to use the current console encoding (false) or UTF-16 encoding (true). It assumes that the console is using a TrueType font.

using System;
using System.IO;
using System.Globalization;
using System.Text;

public static class DisplayChars
{
   private static void Main(string[] args)
   {
      uint rangeStart = 0;
      uint rangeEnd = 0;
      bool setOutputEncodingToUnicode = true;
      // Get the current encoding so we can restore it.
      Encoding originalOutputEncoding = Console.OutputEncoding;

    try
    {
         switch(args.Length)
         {
            case 2:
               rangeStart = uint.Parse(args[0], NumberStyles.HexNumber);
               rangeEnd = uint.Parse(args[1], NumberStyles.HexNumber);
               setOutputEncodingToUnicode = true;
               break;
            case 3:
               if (! uint.TryParse(args[0], NumberStyles.HexNumber, null, out rangeStart))
                  throw new ArgumentException(String.Format("{0} is not a valid hexadecimal number.", args[0]));

               if (!uint.TryParse(args[1], NumberStyles.HexNumber, null, out rangeEnd))
                  throw new ArgumentException(String.Format("{0} is not a valid hexadecimal number.", args[1]));

               bool.TryParse(args[2], out setOutputEncodingToUnicode);
               break;
            default:
               Console.WriteLine("Usage: {0} <{1}> <{2}> [{3}]",
                                 Environment.GetCommandLineArgs()[0],
                                 "startingCodePointInHex",
                                 "endingCodePointInHex",
                                 "<setOutputEncodingToUnicode?{true|false, default:false}>");
               return;
         }

         if (setOutputEncodingToUnicode) {
            // This won't work before .NET Framework 4.5.
            try {
               // Set encoding using endianness of this system.
               // We're interested in displaying individual Char objects, so
               // we don't want a Unicode BOM or exceptions to be thrown on
               // invalid Char values.
               Console.OutputEncoding = new UnicodeEncoding(! BitConverter.IsLittleEndian, false);
               Console.WriteLine("\nOutput encoding set to UTF-16");
            }
            catch (IOException) {
               Console.OutputEncoding = new UTF8Encoding();
               Console.WriteLine("Output encoding set to UTF-8");
            }
         }
         else {
            Console.WriteLine("The console encoding is {0} (code page {1})",
                              Console.OutputEncoding.EncodingName,
                              Console.OutputEncoding.CodePage);
         }
         DisplayRange(rangeStart, rangeEnd);
      }
      catch (ArgumentException ex) {
         Console.WriteLine(ex.Message);
      }
      finally {
         // Restore console environment.
         Console.OutputEncoding = originalOutputEncoding;
      }
   }

   public static void DisplayRange(uint start, uint end)
   {
      const uint upperRange = 0x10FFFF;
      const uint surrogateStart = 0xD800;
      const uint surrogateEnd = 0xDFFF;

      if (end <= start) {
         uint t = start;
         start = end;
         end = t;
      }

      // Check whether the start or end range is outside of last plane.
      if (start > upperRange)
         throw new ArgumentException(String.Format("0x{0:X5} is outside the upper range of Unicode code points (0x{1:X5})",
                                                   start, upperRange));
      if (end > upperRange)
         throw new ArgumentException(String.Format("0x{0:X5} is outside the upper range of Unicode code points (0x{0:X5})",
                                                   end, upperRange));

      // Since we're using 21-bit code points, we can't use U+D800 to U+DFFF.
      if ((start < surrogateStart & end > surrogateStart) || (start >= surrogateStart & start <= surrogateEnd ))
         throw new ArgumentException(String.Format("0x{0:X5}-0x{1:X5} includes the surrogate pair range 0x{2:X5}-0x{3:X5}",
                                                   start, end, surrogateStart, surrogateEnd));
      uint last = RoundUpToMultipleOf(0x10, end);
      uint first = RoundDownToMultipleOf(0x10, start);

      uint rows = (last - first) / 0x10;

      for (uint r = 0; r < rows; ++r) {
         // Display the row header.
         Console.Write("{0:x5} ", first + 0x10 * r);

         for (uint c = 0; c < 0x10; ++c) {
            uint cur = (first + 0x10 * r + c);
            if (cur  < start) {
               Console.Write($" {(char)(0x20)} ");
            }
            else if (end < cur) {
               Console.Write($" {(char)(0x20)} ");
            }
            else {
               // the cast to int is safe, since we know that val <= upperRange.
               String chars = Char.ConvertFromUtf32( (int) cur);
               // Display a space for code points that are not valid characters.
               if (CharUnicodeInfo.GetUnicodeCategory(chars[0]) ==
                                               UnicodeCategory.OtherNotAssigned)
                  Console.Write($" {(char)(0x20)} ");
               // Display a space for code points in the private use area.
               else if (CharUnicodeInfo.GetUnicodeCategory(chars[0]) ==
                                              UnicodeCategory.PrivateUse)
                 Console.Write($" {(char)(0x20)} ");
               // Is surrogate pair a valid character?
               // Note that the console will interpret the high and low surrogate
               // as separate (and unrecognizable) characters.
               else if (chars.Length > 1 && CharUnicodeInfo.GetUnicodeCategory(chars, 0) ==
                                            UnicodeCategory.OtherNotAssigned)
                  Console.Write($" {(char)(0x20)} ");
               else
                  Console.Write($" {chars} ");
            }

            switch (c) {
               case 3: case 11:
                  Console.Write("-");
                  break;
               case 7:
                  Console.Write("--");
                  break;
            }
         }

         Console.WriteLine();
         if (0 < r && r % 0x10 == 0)
            Console.WriteLine();
      }
   }

   private static uint RoundUpToMultipleOf(uint b, uint u)
   {
      return RoundDownToMultipleOf(b, u) + b;
   }

   private static uint RoundDownToMultipleOf(uint b, uint u)
   {
      return u - (u % b);
   }
}
// If the example is run with the command line
//       DisplayChars 0400 04FF true
// the example displays the Cyrillic character set as follows:
//       Output encoding set to UTF-16
//       00400  Ѐ  Ё  Ђ  Ѓ - Є  Ѕ  І  Ї -- Ј  Љ  Њ  Ћ - Ќ  Ѝ  Ў  Џ
//       00410  А  Б  В  Г - Д  Е  Ж  З -- И  Й  К  Л - М  Н  О  П
//       00420  Р  С  Т  У - Ф  Х  Ц  Ч -- Ш  Щ  Ъ  Ы - Ь  Э  Ю  Я
//       00430  а  б  в  г - д  е  ж  з -- и  й  к  л - м  н  о  п
//       00440  р  с  т  у - ф  х  ц  ч -- ш  щ  ъ  ы - ь  э  ю  я
//       00450  ѐ  ё  ђ  ѓ - є  ѕ  і  ї -- ј  љ  њ  ћ - ќ  ѝ  ў  џ
//       00460  Ѡ  ѡ  Ѣ  ѣ - Ѥ  ѥ  Ѧ  ѧ -- Ѩ  ѩ  Ѫ  ѫ - Ѭ  ѭ  Ѯ  ѯ
//       00470  Ѱ  ѱ  Ѳ  ѳ - Ѵ  ѵ  Ѷ  ѷ -- Ѹ  ѹ  Ѻ  ѻ - Ѽ  ѽ  Ѿ  ѿ
//       00480  Ҁ  ҁ  ҂  ҃ - ҄  ҅  ҆  ҇ -- ҈  ҉  Ҋ  ҋ - Ҍ  ҍ  Ҏ  ҏ
//       00490  Ґ  ґ  Ғ  ғ - Ҕ  ҕ  Җ  җ -- Ҙ  ҙ  Қ  қ - Ҝ  ҝ  Ҟ  ҟ
//       004a0  Ҡ  ҡ  Ң  ң - Ҥ  ҥ  Ҧ  ҧ -- Ҩ  ҩ  Ҫ  ҫ - Ҭ  ҭ  Ү  ү
//       004b0  Ұ  ұ  Ҳ  ҳ - Ҵ  ҵ  Ҷ  ҷ -- Ҹ  ҹ  Һ  һ - Ҽ  ҽ  Ҿ  ҿ
//       004c0  Ӏ  Ӂ  ӂ  Ӄ - ӄ  Ӆ  ӆ  Ӈ -- ӈ  Ӊ  ӊ  Ӌ - ӌ  Ӎ  ӎ  ӏ
//       004d0  Ӑ  ӑ  Ӓ  ӓ - Ӕ  ӕ  Ӗ  ӗ -- Ә  ә  Ӛ  ӛ - Ӝ  ӝ  Ӟ  ӟ
//       004e0  Ӡ  ӡ  Ӣ  ӣ - Ӥ  ӥ  Ӧ  ӧ -- Ө  ө  Ӫ  ӫ - Ӭ  ӭ  Ӯ  ӯ
//       004f0  Ӱ  ӱ  Ӳ  ӳ - Ӵ  ӵ  Ӷ  ӷ -- Ӹ  ӹ  Ӻ  ӻ - Ӽ  ӽ  Ӿ  ӿ
Imports System.IO
Imports System.Globalization
Imports System.Text

Public Module DisplayChars
   Public Sub Main(args() As String)
      Dim rangeStart As UInteger = 0
      Dim rangeEnd As UInteger = 0
      Dim setOutputEncodingToUnicode As Boolean = True
      ' Get the current encoding so we can restore it.
      Dim originalOutputEncoding As Encoding = Console.OutputEncoding

    Try
         Select Case args.Length
            Case 2
               rangeStart = UInt32.Parse(args(0), NumberStyles.HexNumber)
               rangeEnd = UInt32.Parse(args(1), NumberStyles.HexNumber)
               setOutputEncodingToUnicode = True
            Case 3
               If Not UInt32.TryParse(args(0), NumberStyles.HexNumber, Nothing, rangeStart) Then
                  Throw New ArgumentException(String.Format("{0} is not a valid hexadecimal number.", args(0)))
               End If
               
               If Not UInt32.TryParse(args(1), NumberStyles.HexNumber, Nothing, rangeEnd) Then
                  Throw New ArgumentException(String.Format("{0} is not a valid hexadecimal number.", args(1)))
               End If
               
               Boolean.TryParse(args(2), setOutputEncodingToUnicode)
            Case Else
               Console.WriteLine("Usage: {0} <{1}> <{2}> [{3}]", 
                                 Environment.GetCommandLineArgs()(0), 
                                 "startingCodePointInHex", 
                                 "endingCodePointInHex", 
                                 "<setOutputEncodingToUnicode?{true|false, default:false}>")
               Exit Sub
         End Select
   
         If setOutputEncodingToUnicode Then
            ' This won't work before .NET Framework 4.5.
            Try 
               ' Set encoding Imports endianness of this system.
               ' We're interested in displaying individual Char objects, so 
               ' we don't want a Unicode BOM or exceptions to be thrown on
               ' invalid Char values.
               Console.OutputEncoding = New UnicodeEncoding(Not BitConverter.IsLittleEndian, False) 
               Console.WriteLine("{0}Output encoding set to UTF-16", vbCrLf)
            Catch e As IOException
               Console.OutputEncoding = New UTF8Encoding()
               Console.WriteLine("Output encoding set to UTF-8")
            End Try
         Else
            Console.WriteLine("The console encoding is {0} (code page {1})", 
                              Console.OutputEncoding.EncodingName,
                              Console.OutputEncoding.CodePage)
         End If
         DisplayRange(rangeStart, rangeEnd)
      Catch ex As ArgumentException
         Console.WriteLine(ex.Message)
      Finally
         ' Restore console environment.
         Console.OutputEncoding = originalOutputEncoding
      End Try
   End Sub

   Public Sub DisplayRange(rangeStart As UInteger, rangeEnd As UInteger)
      Const upperRange As UInteger = &h10FFFF
      Const surrogateStart As UInteger = &hD800
      Const surrogateEnd As UInteger = &hDFFF
       
      If rangeEnd <= rangeStart Then
         Dim t As UInteger = rangeStart
         rangeStart = rangeEnd
         rangeEnd = t
      End If

      ' Check whether the start or end range is outside of last plane.
      If rangeStart > upperRange Then
         Throw New ArgumentException(String.Format("0x{0:X5} is outside the upper range of Unicode code points (0x{1:X5})",
                                                   rangeStart, upperRange))                                   
      End If
      If rangeEnd > upperRange Then
         Throw New ArgumentException(String.Format("0x{0:X5} is outside the upper range of Unicode code points (0x{0:X5})",
                                                   rangeEnd, upperRange))
      End If
      ' Since we're using 21-bit code points, we can't use U+D800 to U+DFFF.
      If (rangeStart < surrogateStart And rangeEnd > surrogateStart) OrElse (rangeStart >= surrogateStart And rangeStart <= surrogateEnd )
         Throw New ArgumentException(String.Format("0x{0:X5}-0x{1:X5} includes the surrogate pair range 0x{2:X5}-0x{3:X5}", 
                                                   rangeStart, rangeEnd, surrogateStart, surrogateEnd))         
      End If
      
      Dim last As UInteger = RoundUpToMultipleOf(&h10, rangeEnd)
      Dim first As UInteger = RoundDownToMultipleOf(&h10, rangeStart)

      Dim rows As UInteger = (last - first) \ &h10

      For r As UInteger = 0 To rows - 1
         ' Display the row header.
         Console.Write("{0:x5} ", first + &h10 * r)

         For c As UInteger = 1 To &h10
            Dim cur As UInteger = first + &h10 * r + c
            If cur  < rangeStart Then
               Console.Write(" {0} ", Convert.ToChar(&h20))
            Else If rangeEnd < cur Then
               Console.Write(" {0} ", Convert.ToChar(&h20))
            Else 
               ' the cast to int is safe, since we know that val <= upperRange.
               Dim chars As String = Char.ConvertFromUtf32(CInt(cur))
               ' Display a space for code points that are not valid characters.
               If CharUnicodeInfo.GetUnicodeCategory(chars(0)) = 
                                   UnicodeCategory.OtherNotAssigned Then
                  Console.Write(" {0} ", Convert.ToChar(&h20))
               ' Display a space for code points in the private use area.
               Else If CharUnicodeInfo.GetUnicodeCategory(chars(0)) =
                                        UnicodeCategory.PrivateUse Then
                 Console.Write(" {0} ", Convert.ToChar(&h20))
               ' Is surrogate pair a valid character?
               ' Note that the console will interpret the high and low surrogate
               ' as separate (and unrecognizable) characters.
               Else If chars.Length > 1 AndAlso CharUnicodeInfo.GetUnicodeCategory(chars, 0) = 
                                            UnicodeCategory.OtherNotAssigned Then
                  Console.Write(" {0} ", Convert.ToChar(&h20))
               Else
                  Console.Write(" {0} ", chars) 
               End If   
            End If
            
            Select Case c
               Case 3, 11
                  Console.Write("-")
               Case 7
                  Console.Write("--")
            End Select
         Next

         Console.WriteLine()
         If 0 < r AndAlso r Mod &h10 = 0
            Console.WriteLine()
         End If
      Next
   End Sub

   Private Function RoundUpToMultipleOf(b As UInteger, u As UInteger) As UInteger
      Return RoundDownToMultipleOf(b, u) + b
   End Function

   Private Function RoundDownToMultipleOf(b As UInteger, u As UInteger) As UInteger
      Return u - (u Mod b)
   End Function
End Module
' If the example is run with the command line
'       DisplayChars 0400 04FF true
' the example displays the Cyrillic character set as follows:
'       Output encoding set to UTF-16
'       00400  Ѐ  Ё  Ђ  Ѓ - Є  Ѕ  І  Ї -- Ј  Љ  Њ  Ћ - Ќ  Ѝ  Ў  Џ
'       00410  А  Б  В  Г - Д  Е  Ж  З -- И  Й  К  Л - М  Н  О  П
'       00420  Р  С  Т  У - Ф  Х  Ц  Ч -- Ш  Щ  Ъ  Ы - Ь  Э  Ю  Я
'       00430  а  б  в  г - д  е  ж  з -- и  й  к  л - м  н  о  п
'       00440  р  с  т  у - ф  х  ц  ч -- ш  щ  ъ  ы - ь  э  ю  я
'       00450  ѐ  ё  ђ  ѓ - є  ѕ  і  ї -- ј  љ  њ  ћ - ќ  ѝ  ў  џ
'       00460  Ѡ  ѡ  Ѣ  ѣ - Ѥ  ѥ  Ѧ  ѧ -- Ѩ  ѩ  Ѫ  ѫ - Ѭ  ѭ  Ѯ  ѯ
'       00470  Ѱ  ѱ  Ѳ  ѳ - Ѵ  ѵ  Ѷ  ѷ -- Ѹ  ѹ  Ѻ  ѻ - Ѽ  ѽ  Ѿ  ѿ
'       00480  Ҁ  ҁ  ҂  ҃ - ҄  ҅  ҆  ҇ -- ҈  ҉  Ҋ  ҋ - Ҍ  ҍ  Ҏ  ҏ
'       00490  Ґ  ґ  Ғ  ғ - Ҕ  ҕ  Җ  җ -- Ҙ  ҙ  Қ  қ - Ҝ  ҝ  Ҟ  ҟ
'       004a0  Ҡ  ҡ  Ң  ң - Ҥ  ҥ  Ҧ  ҧ -- Ҩ  ҩ  Ҫ  ҫ - Ҭ  ҭ  Ү  ү
'       004b0  Ұ  ұ  Ҳ  ҳ - Ҵ  ҵ  Ҷ  ҷ -- Ҹ  ҹ  Һ  һ - Ҽ  ҽ  Ҿ  ҿ
'       004c0  Ӏ  Ӂ  ӂ  Ӄ - ӄ  Ӆ  ӆ  Ӈ -- ӈ  Ӊ  ӊ  Ӌ - ӌ  Ӎ  ӎ  ӏ
'       004d0  Ӑ  ӑ  Ӓ  ӓ - Ӕ  ӕ  Ӗ  ӗ -- Ә  ә  Ӛ  ӛ - Ӝ  ӝ  Ӟ  ӟ
'       004e0  Ӡ  ӡ  Ӣ  ӣ - Ӥ  ӥ  Ӧ  ӧ -- Ө  ө  Ӫ  ӫ - Ӭ  ӭ  Ӯ  ӯ
'       004f0  Ӱ  ӱ  Ӳ  ӳ - Ӵ  ӵ  Ӷ  ӷ -- Ӹ  ӹ  Ӻ  ӻ - Ӽ  ӽ  Ӿ  ӿ
module DisplayChars

open System
open System.IO
open System.Globalization
open System.Text

type uint = uint32

let inline roundDownToMultipleOf b u = u - (u % b)

let inline roundUpToMultipleOf b u = roundDownToMultipleOf b u |> (+) b

let displayRange (start: uint) (``end``: uint) =

    let upperRange = 0x10FFFFu
    let surrogateStart = 0xD800u
    let surrogateEnd = 0xDFFFu

    let start, ``end`` =
        if ``end`` <= start then ``end``, start
        else start, ``end``

    // Check whether the start or end range is outside of last plane.
    if start > upperRange then
        invalidArg "start"
            (String.Format("0x{0:X5} is outside the upper range of Unicode code points (0x{1:X5})", start, upperRange))
    if ``end`` > upperRange then
        invalidArg "end"
            (String.Format("0x{0:X5} is outside the upper range of Unicode code points (0x{0:X5})", ``end``, upperRange))

    // Since we're using 21-bit code points, we can't use U+D800 to U+DFFF.
    if (start < surrogateStart && ``end`` > surrogateStart) || (start >= surrogateStart && start <= surrogateEnd) then
        raise
            (ArgumentException
                (String.Format
                    ("0x{0:X5}-0x{1:X5} includes the surrogate pair range 0x{2:X5}-0x{3:X5}", start, ``end``,
                     surrogateStart, surrogateEnd)))
    let last = roundUpToMultipleOf 0x10u ``end``
    let first = roundDownToMultipleOf 0x10u start

    let rows = (last - first) / 0x10u

    for r in 0u .. (rows - 1u) do
        // Display the row header.
        printf "%05x " (first + 0x10u * r)

        for c in 0u .. (0x10u - 1u) do
            let cur = (first + 0x10u * r + c)
            if cur < start || ``end`` < cur then
                printf " %c " (Convert.ToChar 0x20)
            else
                // the cast to int is safe, since we know that val <= upperRange.
                let chars = Char.ConvertFromUtf32(int cur)
                // Display a space for code points that are not valid characters.
                if CharUnicodeInfo.GetUnicodeCategory(chars[0]) = UnicodeCategory.OtherNotAssigned then
                    printf " %c " (Convert.ToChar 0x20)
                else
                    // Display a space for code points in the private use area.
                    if CharUnicodeInfo.GetUnicodeCategory(chars[0]) = UnicodeCategory.PrivateUse then
                        printf " %c " (Convert.ToChar 0x20)
                    else if chars.Length > 1
                            && CharUnicodeInfo.GetUnicodeCategory(chars, 0) = UnicodeCategory.OtherNotAssigned then
                        printf " %c " (Convert.ToChar 0x20)
                    else printf " %s " chars

            match c with
            | 3u
            | 11u -> printf "-"
            | 7u -> printf "--"
            | _ -> ()

        Console.WriteLine()
        if (0u < r && r % 0x10u = 0u) then Console.WriteLine()



[<EntryPoint>]
let main args =
    // Get the current encoding so we can restore it.
    let originalOutputEncoding = Console.OutputEncoding

    try
        try
            let parsedArgs =
                match args.Length with
                | 2 ->
                    Some
                        {| setOutputEncodingToUnicode = true
                           rangeStart = uint.Parse(args[0], NumberStyles.HexNumber)
                           rangeEnd = uint.Parse(args[1], NumberStyles.HexNumber) |}
                | 3 ->
                    let parseHexNumberOrThrow (value: string) parameterName =
                        (uint.TryParse(value, NumberStyles.HexNumber, null))
                        |> function
                        | (false, _) ->
                            invalidArg parameterName (String.Format("{0} is not a valid hexadecimal number.", value))
                        | (true, value) -> value

                    let setOutputEncodingToUnicode =
                        match bool.TryParse args[2] with
                        | true, value -> value
                        | false, _ -> true

                    Some
                        {| setOutputEncodingToUnicode = setOutputEncodingToUnicode
                           rangeStart = parseHexNumberOrThrow args[0] "rangeStart"
                           rangeEnd = parseHexNumberOrThrow args[1] "rangeEnd" |}
                | _ ->
                    printfn "Usage: %s <%s> <%s> [%s]" (Environment.GetCommandLineArgs()[0]) "startingCodePointInHex"
                        "endingCodePointInHex" "<setOutputEncodingToUnicode?{true|false, default:false}>"
                    None

            match parsedArgs with
            | None -> ()
            | Some parsedArgs ->
                if parsedArgs.setOutputEncodingToUnicode then
                    // This won't work before .NET Framework 4.5.
                    try
                        // Set encoding using endianness of this system.
                        // We're interested in displaying individual Char objects, so
                        // we don't want a Unicode BOM or exceptions to be thrown on
                        // invalid Char values.
                        Console.OutputEncoding <- UnicodeEncoding(not BitConverter.IsLittleEndian, false)
                        printfn "\nOutput encoding set to UTF-16"

                    with :? IOException ->
                        printfn "Output encoding set to UTF-8"
                        Console.OutputEncoding <- UTF8Encoding()
                else
                    printfn "The console encoding is %s (code page %i)" (Console.OutputEncoding.EncodingName)
                        (Console.OutputEncoding.CodePage)

                displayRange parsedArgs.rangeStart parsedArgs.rangeEnd
        with :? ArgumentException as ex -> Console.WriteLine(ex.Message)
    finally
        // Restore console environment.
        Console.OutputEncoding <- originalOutputEncoding
    0

// If the example is run with the command line
//       DisplayChars 0400 04FF true
// the example displays the Cyrillic character set as follows:
//       Output encoding set to UTF-16
//       00400  Ѐ  Ё  Ђ  Ѓ - Є  Ѕ  І  Ї -- Ј  Љ  Њ  Ћ - Ќ  Ѝ  Ў  Џ
//       00410  А  Б  В  Г - Д  Е  Ж  З -- И  Й  К  Л - М  Н  О  П
//       00420  Р  С  Т  У - Ф  Х  Ц  Ч -- Ш  Щ  Ъ  Ы - Ь  Э  Ю  Я
//       00430  а  б  в  г - д  е  ж  з -- и  й  к  л - м  н  о  п
//       00440  р  с  т  у - ф  х  ц  ч -- ш  щ  ъ  ы - ь  э  ю  я
//       00450  ѐ  ё  ђ  ѓ - є  ѕ  і  ї -- ј  љ  њ  ћ - ќ  ѝ  ў  џ
//       00460  Ѡ  ѡ  Ѣ  ѣ - Ѥ  ѥ  Ѧ  ѧ -- Ѩ  ѩ  Ѫ  ѫ - Ѭ  ѭ  Ѯ  ѯ
//       00470  Ѱ  ѱ  Ѳ  ѳ - Ѵ  ѵ  Ѷ  ѷ -- Ѹ  ѹ  Ѻ  ѻ - Ѽ  ѽ  Ѿ  ѿ
//       00480  Ҁ  ҁ  ҂  ҃ - ҄  ҅  ҆  ҇ -- ҈  ҉  Ҋ  ҋ - Ҍ  ҍ  Ҏ  ҏ
//       00490  Ґ  ґ  Ғ  ғ - Ҕ  ҕ  Җ  җ -- Ҙ  ҙ  Қ  қ - Ҝ  ҝ  Ҟ  ҟ
//       004a0  Ҡ  ҡ  Ң  ң - Ҥ  ҥ  Ҧ  ҧ -- Ҩ  ҩ  Ҫ  ҫ - Ҭ  ҭ  Ү  ү
//       004b0  Ұ  ұ  Ҳ  ҳ - Ҵ  ҵ  Ҷ  ҷ -- Ҹ  ҹ  Һ  һ - Ҽ  ҽ  Ҿ  ҿ
//       004c0  Ӏ  Ӂ  ӂ  Ӄ - ӄ  Ӆ  ӆ  Ӈ -- ӈ  Ӊ  ӊ  Ӌ - ӌ  Ӎ  ӎ  ӏ
//       004d0  Ӑ  ӑ  Ӓ  ӓ - Ӕ  ӕ  Ӗ  ӗ -- Ә  ә  Ӛ  ӛ - Ӝ  ӝ  Ӟ  ӟ
//       004e0  Ӡ  ӡ  Ӣ  ӣ - Ӥ  ӥ  Ӧ  ӧ -- Ө  ө  Ӫ  ӫ - Ӭ  ӭ  Ӯ  ӯ
//       004f0  Ӱ  ӱ  Ӳ  ӳ - Ӵ  ӵ  Ӷ  ӷ -- Ӹ  ӹ  Ӻ  ӻ - Ӽ  ӽ  Ӿ  ӿ

Common operations

The Console class contains the following methods for reading console input and writing console output:

  • The overloads of the ReadKey method read an individual character.

  • The ReadLine method reads an entire line of input.

  • The Write method overloads convert an instance of a value type, an array of characters, or a set of objects to a formatted or unformatted string, and then write that string to the console.

  • A parallel set of WriteLine method overloads output the same string as the Write overloads but also add a line termination string.

The Console class also contains methods and properties to perform the following operations:

  • Get or set the size of the screen buffer. The BufferHeight and BufferWidth properties let you get or set the buffer height and width, respectively, and the SetBufferSize method lets you set the buffer size in a single method call.

  • Get or set the size of the console window. The WindowHeight and WindowWidth properties let you get or set the window height and width, respectively, and the SetWindowSize method lets you set the window size in a single method call.

  • Get or set the size of the cursor. The CursorSize property specifies the height of the cursor in a character cell.

  • Get or set the position of the console window relative to the screen buffer. The WindowTop and WindowLeft properties let you get or set the top row and leftmost column of the screen buffer that appears in the console window, and the SetWindowPosition method lets you set these values in a single method call.

  • Get or set the position of the cursor by getting or setting the CursorTop and CursorLeft properties, or set the position of the cursor by calling the SetCursorPosition method.

  • Move or clear data in the screen buffer by calling the MoveBufferArea or Clear method.

  • Get or set the foreground and background colors by using the ForegroundColor and BackgroundColor properties, or reset the background and foreground to their default colors by calling the ResetColor method.

  • Play the sound of a beep through the console speaker by calling the Beep method.

.NET Core notes

In .NET Framework on the desktop, the Console class uses the encoding returned by GetConsoleCP and GetConsoleOutputCP, which typically is a code page encoding. For example code, on systems whose culture is English (United States), code page 437 is the encoding that is used by default. However, .NET Core may make only a limited subset of these encodings available. Where this is the case, Encoding.UTF8 is used as the default encoding for the console.

If your app depends on specific code page encodings, you can still make them available by doing the following before you call any Console methods:

  1. Retrieve the EncodingProvider object from the CodePagesEncodingProvider.Instance property.

  2. Pass the EncodingProvider object to the Encoding.RegisterProvider method to make the additional encodings supported by the encoding provider available.

The Console class will then automatically use the default system encoding rather than UTF8, provided that you have registered the encoding provider before calling any Console output methods.

Examples

The following example demonstrates how to read data from, and write data to, the standard input and output streams. Note that these streams can be redirected by using the SetIn and SetOut methods.

using System;

public class Example4
{
    public static void Main()
    {
        Console.Write("Hello ");
        Console.WriteLine("World!");
        Console.Write("Enter your name: ");
        string name = Console.ReadLine();
        Console.Write("Good day, ");
        Console.Write(name);
        Console.WriteLine("!");
    }
}
// The example displays output similar to the following:
//       Hello World!
//       Enter your name: James
//       Good day, James!
Public Class Example4
    Public Shared Sub Main()
        Console.Write("Hello ")
        Console.WriteLine("World!")
        Console.Write("Enter your name: ")
        Dim name As String = Console.ReadLine()
        Console.Write("Good day, ")
        Console.Write(name)
        Console.WriteLine("!")
    End Sub
End Class
' The example displays output similar to the following:
'        Hello World!
'        Enter your name: James
'        Good day, James!
module Example

open System

[<EntryPoint>]
let main argv =
    Console.Write("Hello ")
    Console.WriteLine("World!")
    Console.Write("Enter your name: ")
    let name = Console.ReadLine()
    Console.Write("Good day, ")
    Console.Write(name)
    Console.WriteLine("!")
    0
    
// The example displays output similar to the following:
//       Hello World!
//       Enter your name: James
//       Good day, James!