System.Console, klasa

Ten artykuł zawiera dodatkowe uwagi dotyczące dokumentacji referencyjnej dla tego interfejsu API.

Konsola to okno systemu operacyjnego, w którym użytkownicy wchodzą w interakcje z systemem operacyjnym lub z aplikacją konsolową opartą na tekście, wprowadzając tekst wejściowy za pomocą klawiatury komputera i odczytując dane wyjściowe tekstu z terminalu komputera. Na przykład w systemie operacyjnym Windows konsola jest nazywana oknem wiersza polecenia i akceptuje polecenia MS-DOS. Klasa zapewnia podstawową Console obsługę aplikacji, które odczytują znaki z i zapisują znaki do konsoli.

Strumienie we/wy konsoli

Po uruchomieniu aplikacji konsolowej system operacyjny automatycznie kojarzy trzy strumienie we/wy z konsolą: standardowy strumień wejściowy, standardowy strumień wyjściowy i standardowy strumień wyjściowy błędów. Aplikacja może odczytywać dane wejściowe użytkownika ze standardowego strumienia wejściowego; zapisywanie normalnych danych do standardowego strumienia wyjściowego; i zapisują dane o błędach do standardowego strumienia danych wyjściowych błędów. Te strumienie są prezentowane aplikacji jako wartości Console.Inwłaściwości , Console.Outi Console.Error .

Domyślnie wartość In właściwości jest obiektem reprezentującym klawiaturę System.IO.TextReader , a wartości Out właściwości i Error to System.IO.TextWriter obiekty reprezentujące okno konsoli. Można jednak ustawić te właściwości na strumienie, które nie reprezentują okna konsoli ani klawiatury; na przykład można ustawić te właściwości na strumienie reprezentujące pliki. Aby przekierować standardowe dane wejściowe, standardowe dane wyjściowe lub standardowy strumień błędów, wywołaj odpowiednio metodę Console.SetIn, Console.SetOutlub Console.SetError . Operacje we/wy korzystające z tych strumieni są synchronizowane, co oznacza, że wiele wątków może odczytywać strumienie lub zapisywać je. Oznacza to, że metody, które są zwykle asynchroniczne, takie jak TextReader.ReadLineAsync, wykonują synchronicznie, jeśli obiekt reprezentuje strumień konsoli.

Uwaga

Nie używaj Console klasy do wyświetlania danych wyjściowych w aplikacjach nienadzorowanych, takich jak aplikacje serwera. Wywołania metod, takich jak Console.Write i Console.WriteLine nie mają wpływu na aplikacje graficznego interfejsu użytkownika.

Console składowe klasy, które działają normalnie, gdy podstawowy strumień jest kierowany do konsoli, może zgłosić wyjątek, jeśli strumień jest przekierowywany, na przykład do pliku. Zaprogramuj aplikację, aby przechwycić System.IO.IOException wyjątki w przypadku przekierowania standardowego strumienia. Można również użyć IsOutputRedirectedwłaściwości , IsInputRedirectedi IsErrorRedirected , aby określić, czy standardowy strumień jest przekierowywany przed wykonaniem operacji, która zgłasza System.IO.IOException wyjątek.

Czasami przydatne jest jawne wywołanie elementów członkowskich obiektów strumienia reprezentowanych przez Inwłaściwości , Outi Error . Na przykład domyślnie Console.ReadLine metoda odczytuje dane wejściowe ze standardowego strumienia wejściowego. Console.WriteLine Podobnie metoda zapisuje dane w standardowym strumieniu wyjściowym, a dane są zgodne z domyślnym ciągiem zakończenia wiersza, który można znaleźć pod adresem Environment.NewLine. Console Jednak klasa nie udostępnia odpowiedniej metody zapisywania danych w standardowym strumieniu wyjściowym błędów ani właściwości w celu zmiany ciągu zakończenia wiersza dla danych zapisanych w tym strumieniu.

Ten problem można rozwiązać, ustawiając TextWriter.NewLine właściwość Out właściwości lub Error na inny ciąg zakończenia wiersza. Na przykład następująca instrukcja języka C# ustawia ciąg zakończenia wiersza dla standardowego strumienia wyjściowego błędu na dwie sekwencje powrotu karetki i wiersza:

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

Następnie można jawnie wywołać metodę WriteLine obiektu strumienia wyjściowego błędu, jak w następującej instrukcji języka C#:

Console.Error.WriteLine();

Bufor ekranu i okno konsoli

Dwie ściśle powiązane funkcje konsoli to bufor ekranu i okno konsoli. Tekst jest w rzeczywistości odczytywany lub zapisywany w strumieniach należących do konsoli, ale wydaje się być odczytywany lub zapisywany w obszarze należącym do konsoli o nazwie bufor ekranu. Bufor ekranu jest atrybutem konsoli i jest zorganizowany jako prostokątna siatka wierszy i kolumn, w których każdy przecięcie siatki lub komórka znaku może zawierać znak. Każdy znak ma własny kolor pierwszego planu, a każda komórka znaków ma własny kolor tła.

Bufor ekranu jest wyświetlany za pośrednictwem prostokątnego regionu nazywanego oknem konsoli. Okno konsoli jest innym atrybutem konsoli; nie jest to konsola, która jest oknem systemu operacyjnego. Okno konsoli jest rozmieszczone w wierszach i kolumnach, jest mniejsze lub równe rozmiarowi buforu ekranu i można je przenieść, aby wyświetlić różne obszary bazowego buforu ekranu. Jeśli bufor ekranu jest większy niż okno konsoli, konsola automatycznie wyświetla paski przewijania, aby okno konsoli można było zmienić położenie na obszarze buforu ekranu.

Kursor wskazuje położenie buforu ekranu, w którym tekst jest obecnie odczytywany lub zapisywany. Kursor może być ukryty lub widoczny, a jego wysokość można zmienić. Jeśli kursor jest widoczny, pozycja okna konsoli jest przenoszona automatycznie, dzięki czemu kursor jest zawsze w widoku.

Początek współrzędnych komórki znaku w buforze ekranu to lewy górny róg, a położenie kursora i okna konsoli są mierzone względem tego źródła. Użyj indeksów opartych na zerach, aby określić pozycje; oznacza to, że określ najbardziej górny wiersz jako wiersz 0, a kolumnę z lewej strony jako kolumnę 0. Maksymalna wartość indeksów wierszy i kolumn to Int16.MaxValue.

Obsługa formatu Unicode dla konsoli

Ogólnie rzecz biorąc, konsola odczytuje dane wejściowe i zapisuje dane wyjściowe przy użyciu bieżącej strony kodowej konsoli, która domyślnie definiuje ustawienia regionalne systemu. Strona kodowa może obsługiwać tylko podzbiór dostępnych znaków Unicode, więc jeśli spróbujesz wyświetlić znaki, które nie są mapowane przez określoną stronę kodową, konsola nie będzie mogła wyświetlić wszystkich znaków ani dokładnie je przedstawić. Poniższy przykład ilustruje ten problem. Próbuje wyświetlić znaki alfabetu cyrylica z U+0410 do U+044F do konsoli. Jeśli uruchomisz przykład w systemie, który używa strony kodowej konsoli 437, każdy znak zostanie zastąpiony znakiem zapytania (?), ponieważ znaki cyrylica nie są mapowane na znaki na stronie kodowej 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
//
//    ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?
//    ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?
//    ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?  ?

Oprócz pomocniczych stron Console kodu klasa obsługuje kodowanie UTF-8 z klasą UTF8Encoding . Począwszy od programu .NET Framework 4.5, Console klasa obsługuje również kodowanie UTF-16 z klasą UnicodeEncoding . Aby wyświetlić znaki Unicode w konsoli programu . właściwość jest ustawiana OutputEncoding na UTF8Encoding wartość lub UnicodeEncoding.

Obsługa znaków Unicode wymaga, aby koder rozpoznawał określony znak Unicode, a także wymaga czcionki, która zawiera glyphs potrzebne do renderowania tego znaku. Aby pomyślnie wyświetlić znaki Unicode w konsoli, czcionka konsoli musi być ustawiona na czcionkę inną niż raster lub TrueType, taką jak Consolas lub Lucida Console. W poniższym przykładzie pokazano, jak można programowo zmienić czcionkę z czcionki rasterowej na Konsolę Lucida.

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

Jednak czcionki TrueType mogą wyświetlać tylko podzbiór glifów. Na przykład czcionka Konsoli Lucida wyświetla tylko 643 z około 64 000 dostępnych znaków od U+0021 do U+FB02. Aby zobaczyć, które znaki obsługuje określona czcionka, otwórz aplet Czcionki w Panel sterowania, wybierz opcję Znajdź znak i wybierz czcionkę, której zestaw znaków chcesz sprawdzić na liście Czcionka okna Mapa znaków.

System Windows używa łączenia czcionek w celu wyświetlania glifów, które nie są dostępne w określonej czcionki. Aby uzyskać informacje o łączeniu czcionek do wyświetlania dodatkowych zestawów znaków, zobacz Globalizacja Krok po kroku: Czcionki. Połączone czcionki są definiowane w podkluczu HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\FontLink\SystemLink rejestru. Każdy wpis skojarzony z tym podkluczem odpowiada nazwie czcionki podstawowej, a jego wartość jest tablicą ciągów definiującą pliki czcionek i czcionki połączone z czcionką podstawową. Każdy element członkowski tablicy definiuje połączoną czcionkę i przyjmuje formę font-file-name, font-name. W poniższym przykładzie pokazano, jak programowo zdefiniować połączoną czcionkę o nazwie SimSun znajdującą się w pliku czcionek o nazwie simsun.ttc, który wyświetla uproszczone znaki Han.

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()

Obsługa formatu Unicode dla konsoli ma następujące ograniczenia:

  • Kodowanie UTF-32 nie jest obsługiwane. Jedynymi obsługiwanymi kodami Unicode są odpowiednio UTF-8 i UTF-16, które są reprezentowane przez UTF8Encoding klasy i UnicodeEncoding .

  • Dane wyjściowe dwukierunkowe nie są obsługiwane.

  • Wyświetlanie znaków poza podstawową płaszczyzną wielojęzyczną (czyli par zastępczych) nie jest obsługiwane, nawet jeśli są zdefiniowane w połączonym pliku czcionki.

  • Wyświetlanie znaków w złożonych skryptach nie jest obsługiwane.

  • Łączenie sekwencji znaków (czyli znaków składających się z znaku podstawowego i co najmniej jednego połączonego znaku) jest wyświetlane jako osobne znaki. Aby obejść to ograniczenie, można znormalizować ciąg, który ma być wyświetlany, wywołując metodę String.Normalize przed wysłaniem danych wyjściowych do konsoli programu . W poniższym przykładzie ciąg zawierający łączącą sekwencję znaków U+0061 U+0308 jest wyświetlany w konsoli jako dwa znaki przed znormalizowaniem ciągu wyjściowego i jako pojedynczy znak po wywołaniu String.Normalize metody.

    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"
    //       ä
    

    Normalizacja jest opłacalnym rozwiązaniem tylko wtedy, gdy standard Unicode dla znaku zawiera wstępnie skomponowaną formę odpowiadającą konkretnej sekwencji znaków łączących.

  • Jeśli czcionka zapewnia glyph dla punktu kodu w obszarze użytku prywatnego, zostanie wyświetlony symbol glyph. Jednak ze względu na to, że znaki w obszarze użytku prywatnego są specyficzne dla aplikacji, może to nie być oczekiwane glyph.

W poniższym przykładzie zostanie wyświetlony zakres znaków Unicode w konsoli programu . Przykład akceptuje trzy parametry wiersza polecenia: początek zakresu do wyświetlenia, koniec zakresu do wyświetlenia i czy używać bieżącego kodowania konsoli (false) lub kodowania UTF-16 (true). Przyjęto założenie, że konsola używa czcionki TrueType.

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  Ӱ  ӱ  Ӳ  ӳ - Ӵ  ӵ  Ӷ  ӷ -- Ӹ  ӹ  Ӻ  ӻ - Ӽ  ӽ  Ӿ  ӿ

Typowe operacje

Klasa Console zawiera następujące metody odczytywania danych wejściowych konsoli i zapisywania danych wyjściowych konsoli:

  • Przeciążenia ReadKey metody odczytują pojedynczy znak.

  • Metoda ReadLine odczytuje cały wiersz danych wejściowych.

  • Metoda Write konwertuje wystąpienie typu wartości, tablicę znaków lub zestaw obiektów na sformatowany lub niesformatowany ciąg, a następnie zapisuje ten ciąg w konsoli.

  • Równoległy zestaw WriteLine metod przeciąża dane wyjściowe tego samego ciągu co Write przeciążenia, ale także dodaj ciąg zakończenia wiersza.

Klasa Console zawiera również metody i właściwości służące do wykonywania następujących operacji:

  • Pobierz lub ustaw rozmiar buforu ekranu. Właściwości BufferHeight i BufferWidth umożliwiają uzyskanie lub ustawienie odpowiednio wysokości i szerokości buforu, a SetBufferSize metoda umożliwia ustawienie rozmiaru buforu w jednym wywołaniu metody.

  • Pobierz lub ustaw rozmiar okna konsoli. Właściwości WindowHeight i WindowWidth pozwalają uzyskać lub ustawić odpowiednio wysokość i szerokość okna, a SetWindowSize metoda umożliwia ustawienie rozmiaru okna w jednym wywołaniu metody.

  • Pobierz lub ustaw rozmiar kursora. Właściwość CursorSize określa wysokość kursora w komórce znaku.

  • Pobierz lub ustaw położenie okna konsoli względem buforu ekranu. Właściwości WindowTop i WindowLeft umożliwiają uzyskanie lub ustawienie górnego wiersza i lewej kolumny buforu ekranu wyświetlanego w oknie konsoli, a SetWindowPosition metoda umożliwia ustawienie tych wartości w jednym wywołaniu metody.

  • Pobierz lub ustaw położenie kursora przez pobranie lub ustawienie CursorTop właściwości i CursorLeft lub ustawienie pozycji kursora SetCursorPosition przez wywołanie metody .

  • Przenieś lub wyczyść dane w buforze ekranu, wywołując metodę MoveBufferArea or Clear .

  • Pobierz lub ustaw kolory pierwszego planu i tła przy użyciu ForegroundColor właściwości i BackgroundColor albo zresetuj tło i pierwszy plan do domyślnych kolorów, wywołując metodę ResetColor .

  • Odtwórz dźwięk sygnału dźwiękowego za pośrednictwem głośnika konsoli, wywołując metodę Beep .

Uwagi dotyczące platformy .NET Core

W programie .NET Framework na pulpicie Console klasa używa kodowania zwracanego przez GetConsoleCP metodę i GetConsoleOutputCP, która zazwyczaj jest kodowaniem strony kodowej. Na przykład kod w systemach, których kultura jest angielska (Stany Zjednoczone), strona kodowa 437 jest kodowaniem używanym domyślnie. Jednak platforma .NET Core może udostępnić tylko ograniczony podzbiór tych kodowań. W takim przypadku Encoding.UTF8 jest używany jako domyślne kodowanie dla konsoli programu .

Jeśli aplikacja zależy od określonych kodowań stron kodowych, nadal można je udostępnić, wykonując następujące czynności przed wywołaniem dowolnych Console metod:

  1. EncodingProvider Pobierz obiekt z CodePagesEncodingProvider.Instance właściwości .

  2. EncodingProvider Przekaż obiekt do Encoding.RegisterProvider metody, aby udostępnić dodatkowe kodowanie obsługiwane przez dostawcę kodowania.

Klasa Console będzie następnie automatycznie używać domyślnego kodowania systemu, a nie UTF8, pod warunkiem, że zarejestrowano dostawcę kodowania przed wywołaniem dowolnych Console metod wyjściowych.

Przykłady

W poniższym przykładzie pokazano, jak odczytywać dane z danych i zapisywać je w standardowych strumieniach wejściowych i wyjściowych. Należy pamiętać, że te strumienie mogą być przekierowywane przy użyciu SetIn metod i SetOut .

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!