Złożone formatowanie

Funkcja formatowania złożonego platformy .NET przyjmuje listę obiektów i ciąg formatu złożonego jako dane wejściowe. Ciąg formatu złożonego składa się ze stałego tekstu połączonego z indeksowanym symbolami zastępczymi, nazywanymi elementami formatu. Te elementy formatu odpowiadają obiektom na liście. Operacja formatowania zwraca ciąg wynikowy, który składa się z oryginalnego stałego tekstu zmieszanego z ciągiem reprezentującym obiekty na liście.

Ważne

Zamiast używać ciągów formatu złożonego, można użyć ciągów interpolowanych, jeśli używany język i jego wersja obsługują te ciągi . Ciąg interpolowany zawiera wyrażenia interpolowane. Każde wyrażenie interpolowane jest rozpoznawane przy użyciu wartości wyrażenia i uwzględniane w ciągu wynikowym po przypisaniu ciągu. Aby uzyskać więcej informacji, zobacz Interpolacja ciągów (odwołanie w C#) i ciągi interpolowane (odwołanie w języku Visual Basic).

Następujące metody obsługują funkcję formatowania złożonego:

Ciąg formatu złożonego

Ciąg formatu złożonego i lista obiektów są używane jako argumenty metod, które obsługują funkcję formatowania złożonego. Ciąg formatu złożonego składa się z zera lub większej liczby serii stałego tekstu zmieszanego z co najmniej jednym elementem formatu. Stały tekst to dowolnie wybrany ciąg, a każdy element formatu odpowiada obiektowi lub strukturze opakowanej na liście. Reprezentacja ciągu każdego obiektu zastępuje odpowiedni element formatu.

Rozważmy następujący Format fragment kodu:

string.Format("Name = {0}, hours = {1:hh}", "Fred", DateTime.Now);
String.Format("Name = {0}, hours = {1:hh}", "Fred", DateTime.Now)

Stały tekst to Name = i , hours = . Elementy formatu to {0}, których indeks 0 odpowiada obiektowi name, i {1:hh}, którego indeks 1 odpowiada obiektowi DateTime.Now.

Formatowanie składni elementu

Każdy element formatu ma następującą postać i składa się z następujących składników:

{index[,alignment][:formatString]}

Pasujące nawiasy klamrowe ({ i }) są wymagane.

Składnik indeksu

Obowiązkowy składnik indeksu , który jest również nazywany specyfikatorem parametru, jest liczbą rozpoczynającą się od 0, która identyfikuje odpowiedni element na liście obiektów. Oznacza to, że element formatu, którego specyfikator parametru jest 0 formatuje pierwszy obiekt na liście. Element formatu, którego specyfikator parametru jest 1 formatuje drugi obiekt na liście itd. Poniższy przykład zawiera cztery specyfikatory parametrów, ponumerowane zero do trzech, aby reprezentować liczby pierwsze mniejsze niż 10:

string.Format("Name = {0}, hours = {1:hh}", "Fred", DateTime.Now);
String.Format("Name = {0}, hours = {1:hh}", "Fred", DateTime.Now)

Wiele elementów formatu może odwoływać się do tego samego elementu na liście obiektów, jeśli będą miały określony taki sam specyfikator parametru. Na przykład można sformatować tę samą wartość liczbową w formacie szesnastkowym, naukowym i liczbowym, określając ciąg formatu złożonego, taki jak "0x{0:X} {0:E} {0:N}", jak pokazano w poniższym przykładzie:

string multiple = string.Format("0x{0:X} {0:E} {0:N}",
                                Int64.MaxValue);
Console.WriteLine(multiple);

// The example displays the following output:
//      0x7FFFFFFFFFFFFFFF 9.223372E+018 9,223,372,036,854,775,807.00
Dim multiple As String = String.Format("0x{0:X} {0:E} {0:N}",
                                       Int64.MaxValue)
Console.WriteLine(multiple)

'The example displays the following output
'     0x7FFFFFFFFFFFFFFF 9.223372E+018 9,223,372,036,854,775,807.00

Każdy element formatu może odwoływać się do dowolnego obiektu na liście. Jeśli na przykład istnieją trzy obiekty, możesz sformatować drugi, pierwszy i trzeci obiekt, określając ciąg formatu złożonego, taki jak {1} {0} {2}. Obiekt, do którego nie odwołuje się element formatu, jest ignorowany. Element FormatException jest zgłaszany w czasie wykonywania, jeśli specyfikator parametru wyznacza element poza granicami listy obiektów.

Składnik wyrównania

Opcjonalny składnik wyrównania to podpisana liczba całkowita wskazująca preferowaną sformatowaną szerokość pola. Jeśli wartość wyrównania jest mniejsza niż długość sformatowanego ciągu, wyrównanie jest ignorowane, a długość sformatowanego ciągu jest używana jako szerokość pola. Sformatowane dane w polu są wyrównane do prawej, jeśli wyrównanie jest dodatnie i wyrównane do lewej, jeśli wyrównanie jest ujemne. Jeśli potrzebne jest dopełnienie, będą używane znaki odstępu. Przecinek jest wymagany, jeśli określono wyrównanie .

W poniższym przykładzie zdefiniowano dwie tablice, jedną zawierającą nazwy pracowników, a drugą zawierającą godziny pracy w ciągu dwóch tygodni. Ciąg formatu złożonego w lewo wyrównuje nazwy w polu 20 znaków i wyrówna ich godziny w polu 5-znakowym. Standardowy ciąg formatu "N1" formatuje godziny z jedną cyfrą ułamkową.

string[] names = { "Adam", "Bridgette", "Carla", "Daniel",
                   "Ebenezer", "Francine", "George" };
decimal[] hours = { 40, 6.667m, 40.39m, 82,
                    40.333m, 80, 16.75m };

Console.WriteLine("{0,-20} {1,5}\n", "Name", "Hours");

for (int counter = 0; counter < names.Length; counter++)
    Console.WriteLine("{0,-20} {1,5:N1}", names[counter], hours[counter]);

// The example displays the following output:
//      Name                 Hours
//      
//      Adam                  40.0
//      Bridgette              6.7
//      Carla                 40.4
//      Daniel                82.0
//      Ebenezer              40.3
//      Francine              80.0
//      George                16.8
Dim names As String() = {"Adam", "Bridgette", "Carla", "Daniel",
                         "Ebenezer", "Francine", "George"}

Dim hours As Decimal() = {40, 6.667D, 40.39D, 82,
                          40.333D, 80, 16.75D}

Console.WriteLine("{0,-20} {1,5}\n", "Name", "Hours")

For counter = 0 To names.Length - 1
    Console.WriteLine("{0,-20} {1,5:N1}", names(counter), hours(counter))
Next

'The example displays the following output
'     Name                 Hours
'     
'     Adam                  40.0
'     Bridgette              6.7
'     Carla                 40.4
'     Daniel                82.0
'     Ebenezer              40.3
'     Francine              80.0
'     George                16.8

Formatowanie składnika ciągu

Opcjonalny składnik formatString jest ciągiem formatu, który jest odpowiedni dla typu sformatowanego obiektu. Możesz określić następujące elementy:

  • Standardowy lub niestandardowy ciąg formatu liczbowego, jeśli odpowiadający mu obiekt jest wartością liczbową.
  • Standardowy lub niestandardowy ciąg formatu daty i godziny, jeśli odpowiedni obiekt jest obiektem DateTime .
  • Ciąg formatu wyliczenia, jeśli odpowiedni obiekt jest wartością wyliczenia.

Jeśli formatString nie jest określony, używany jest ogólny specyfikator formatu ("G") dla typu liczbowego, daty i godziny lub wyliczenia. Dwukropek jest wymagany, jeśli określono formatString .

W poniższej tabeli wymieniono typy lub kategorie typów w bibliotece klas platformy .NET, które obsługują wstępnie zdefiniowany zestaw ciągów formatu, i zawiera linki do artykułów, które zawierają listę obsługiwanych ciągów formatu. Formatowanie ciągów to rozszerzalny mechanizm, który umożliwia definiowanie nowych ciągów formatu dla wszystkich istniejących typów oraz definiowanie zestawu ciągów formatu obsługiwanych przez typ zdefiniowany przez aplikację.

Aby uzyskać więcej informacji, zobacz IFormattable artykuły i ICustomFormatter dotyczące interfejsu.

Typ lub kategoria typów Zobacz
Typy dat i godzin (DateTime, DateTimeOffset) Standardowe ciągi formatu data i godzina

Niestandardowe ciągi formatu data i godzina
Typy wyliczenia (wszystkie typy pochodzące z System.Enum) Ciągi formatujące wyliczenia
Typy liczbowe (BigInteger, Byte, DecimalInt64Int32Int16DoubleSingleUInt16SByte, ) UInt64UInt32 Standardowe ciągi formatów liczbowych

Niestandardowe ciągi formatujące liczby
Guid Guid.ToString(String)
TimeSpan Standardowe ciągi formatujące TimeSpan

Niestandardowe ciągi formatujące TimeSpan

Ucieczka nawiasów klamrowych

Klamrowe nawiasy otwierający i zamykający są interpretowane jako rozpoczęcie i zakończenie elementu formatu. Aby wyświetlić nawias klamrowy otwierający literał lub zamykający nawias klamrowy, należy użyć sekwencji ucieczki. Określ dwa otwierające nawiasy klamrowe ({{) w stałym tekście, aby wyświetlić jeden otwierający nawias klamrowy ({) lub dwa zamykające nawiasy klamrowe (}}), aby wyświetlić jeden zamykający nawias klamrowy (}).

Nawiasy klamrowe z elementem formatu są analizowane inaczej między platformami .NET i .NET Framework.

.NET

Nawiasy klamrowe można unikać wokół elementu formatu. Rozważmy na przykład element {{{0:D}}}formatu , który ma na celu wyświetlenie nawiasu klamrowego otwierającego, wartości liczbowej sformatowanej jako liczba dziesiętna i zamykającego nawiasu klamrowego. Element formatu jest interpretowany w następujący sposób:

  1. Pierwsze dwa otwierające nawiasy klamrowe ({{) są ucieczki i dają jeden otwierający nawias klamrowy.
  2. Następne trzy znaki ({0:) są interpretowane jako początek elementu formatu.
  3. Następny znak (D) jest interpretowany jako specyfikator formatu dziesiętnego standardowego formatu liczbowego.
  4. Następny nawias klamrowy (}) jest interpretowany jako koniec elementu formatu.
  5. Ostatnie dwa nawiasy klamrowe zamykające są ucieczki i dają jeden zamykający nawias klamrowy.
  6. Wynik końcowy, który jest wyświetlany, to ciąg literału . {6324}
int value = 6324;
string output = string.Format("{{{0:D}}}", value);

Console.WriteLine(output);
// The example displays the following output:
//       {6324}
Dim value As Integer = 6324
Dim output As String = String.Format("{{{0:D}}}", value)

Console.WriteLine(output)

'The example displays the following output
'      {6324}

.NET Framework

Nawiasy klamrowe w elemencie formatu są interpretowane sekwencyjnie w kolejności ich napotkania. Interpretowanie zagnieżdżonych nawiasów klamrowych nie jest obsługiwane.

Sposób interpretowania nawiasów klamrowych poprzedzonych znakiem ucieczki może prowadzić do nieoczekiwanych rezultatów. Rozważmy na przykład element {{{0:D}}}formatu , który ma na celu wyświetlenie nawiasu klamrowego otwierającego, wartości liczbowej sformatowanej jako liczba dziesiętna i zamykającego nawiasu klamrowego. Jednak element formatu jest interpretowany w następujący sposób:

  1. Pierwsze dwa otwierające nawiasy klamrowe ({{) są ucieczki i dają jeden otwierający nawias klamrowy.
  2. Następne trzy znaki ({0:) są interpretowane jako początek elementu formatu.
  3. Następny znak (D) zostanie zinterpretowany jako specyfikator formatu dziesiętnego standardowego formatu liczbowego, ale następne dwa nawiasy klamrowe (}}) uniknęły pojedynczego nawiasu klamrowego. Ponieważ wynikowy ciąg (D}) nie jest standardowym specyfikatorem formatu liczbowego, wynikowy ciąg jest interpretowany jako ciąg formatu niestandardowego, który oznacza wyświetlanie ciągu D}literału .
  4. Ostatni nawias klamrowy (}) jest interpretowany jako koniec elementu formatu.
  5. Wynik końcowy, który jest wyświetlany, to ciąg literału . {D} Wartość liczbowa, która miała zostać sformatowana, nie jest wyświetlana.
int value = 6324;
string output = string.Format("{{{0:D}}}",
                              value);
Console.WriteLine(output);

// The example displays the following output:
//       {D}
Dim value As Integer = 6324
Dim output As String = String.Format("{{{0:D}}}",
                                     value)
Console.WriteLine(output)

'The example displays the following output:
'      {D}

Jednym ze sposobów na napisanie kodu w celu uniknięcia błędnej interpretacji nawiasów klamrowych i elementów formatu jest oddzielne formatowanie nawiasów klamrowych i elementów. Oznacza to, że w pierwszej operacji formatowania wyświetl nawias klamrowy otwierający literał. W następnej operacji wyświetl wynik elementu formatu, a w końcowej operacji wyświetl nawias klamrowy zamykający literał. Poniższy przykład ilustruje to podejście:

int value = 6324;
string output = string.Format("{0}{1:D}{2}",
                             "{", value, "}");
Console.WriteLine(output);

// The example displays the following output:
//       {6324}
Dim value As Integer = 6324
Dim output As String = String.Format("{0}{1:D}{2}",
                                     "{", value, "}")
Console.WriteLine(output)

'The example displays the following output:
'      {6324}

Kolejność przetwarzania

Jeśli wywołanie metody formatowania złożonego zawiera IFormatProvider argument, którego wartość nie nulljest , środowisko uruchomieniowe wywołuje jego IFormatProvider.GetFormat metodę w celu żądania ICustomFormatter implementacji. Jeśli metoda może zwrócić implementację ICustomFormatter , jest buforowana podczas wywołania metody formatowania złożonego.

Każda wartość na liście parametrów odpowiadająca elementowi formatu jest konwertowana na ciąg w następujący sposób:

  1. Jeśli wartość do sformatowania to null, zwracany jest pusty ciąg String.Empty .

  2. Jeśli implementacja ICustomFormatter jest dostępna, środowisko uruchomieniowe wywołuje jego Format metodę. Środowisko uruchomieniowe przekazuje wartość elementu formatString formatu (lub null jeśli nie jest obecna) do metody . Środowisko uruchomieniowe przekazuje również implementację IFormatProvider do metody . Jeśli wywołanie ICustomFormatter.Format metody zwróci nullmetodę , wykonanie przejdzie do następnego kroku. W przeciwnym razie zwracany jest wynik ICustomFormatter.Format wywołania.

  3. Jeśli wartość implementuje IFormattable interfejs, wywoływana jest metoda interfejsu ToString(String, IFormatProvider) . Jeśli element jest obecny w elemencie formatu, wartość formatString jest przekazywana do metody . null W przeciwnym razie jest przekazywany. Argument IFormatProvider jest określany w następujący sposób:

  4. Wywoływana jest metoda bez ToString parametrów typu, która zastępuje Object.ToString() lub dziedziczy zachowanie klasy bazowej. W takim przypadku ciąg formatu określony przez formatString składnik w elemencie formatu, jeśli jest obecny, jest ignorowany.

Wyrównanie zostanie zastosowane po wykonaniu poprzednich kroków.

Przykłady kodu

W poniższym przykładzie pokazano jeden ciąg utworzony przy użyciu formatowania złożonego, a drugi utworzony przy użyciu metody obiektu ToString . Oba typy formatowania dają równoważne wyniki.

string formatString1 = string.Format("{0:dddd MMMM}", DateTime.Now);
string formatString2 = DateTime.Now.ToString("dddd MMMM");
Dim formatString1 As String = String.Format("{0:dddd MMMM}", DateTime.Now)
Dim formatString2 As String = DateTime.Now.ToString("dddd MMMM")

Zakładając, że bieżący dzień to czwartek w maju, wartość obu ciągów w poprzednim przykładzie znajduje Thursday May się w kulturze angielskiej USA.

Console.WriteLine uwidacznia tę samą funkcjonalność co String.Format. Jedyną różnicą między dwiema metodami jest to, że String.Format zwraca jego wynik jako ciąg, podczas gdy Console.WriteLine zapisuje wynik do strumienia wyjściowego skojarzonego z obiektem Console . W poniższym przykładzie użyto Console.WriteLine metody do sformatowania wartości myNumber w walucie:

int myNumber = 100;
Console.WriteLine("{0:C}", myNumber);

// The example displays the following output
// if en-US is the current culture:
//        $100.00
Dim myNumber As Integer = 100
Console.WriteLine("{0:C}", myNumber)

'The example displays the following output
'if en-US Is the current culture:
'       $100.00

W poniższym przykładzie pokazano formatowanie wielu obiektów, w tym formatowanie jednego obiektu na dwa różne sposoby:

string myName = "Fred";
Console.WriteLine(string.Format("Name = {0}, hours = {1:hh}, minutes = {1:mm}",
                                myName, DateTime.Now));

// Depending on the current time, the example displays output like the following:
//        Name = Fred, hours = 11, minutes = 30
Dim myName As String = "Fred"
Console.WriteLine(String.Format("Name = {0}, hours = {1:hh}, minutes = {1:mm}",
                                myName, DateTime.Now))
'Depending on the current time, the example displays output Like the following:
'       Name = Fred, hours = 11, minutes = 30

W poniższym przykładzie pokazano użycie wyrównania w formatowaniu. Argumenty sformatowane są umieszczane między pionowymi znakami paska (|), aby wyróżnić wynikowe wyrównanie.

string firstName = "Fred";
string lastName = "Opals";
int myNumber = 100;

string formatFirstName = string.Format("First Name = |{0,10}|", firstName);
string formatLastName = string.Format("Last Name =  |{0,10}|", lastName);
string formatPrice = string.Format("Price =      |{0,10:C}|", myNumber);
Console.WriteLine(formatFirstName);
Console.WriteLine(formatLastName);
Console.WriteLine(formatPrice);
Console.WriteLine();

formatFirstName = string.Format("First Name = |{0,-10}|", firstName);
formatLastName = string.Format("Last Name =  |{0,-10}|", lastName);
formatPrice = string.Format("Price =      |{0,-10:C}|", myNumber);
Console.WriteLine(formatFirstName);
Console.WriteLine(formatLastName);
Console.WriteLine(formatPrice);

// The example displays the following output on a system whose current
// culture is en-US:
//     First Name = |      Fred|
//     Last Name =  |     Opals|
//     Price =      |   $100.00|
//
//     First Name = |Fred      |
//     Last Name =  |Opals     |
//     Price =      |$100.00   |
Dim firstName As String = "Fred"
Dim lastName As String = "Opals"
Dim myNumber As Integer = 100

Dim formatFirstName As String = String.Format("First Name = |{0,10}|", firstName)
Dim formatLastName As String = String.Format("Last Name =  |{0,10}|", lastName)
Dim formatPrice As String = String.Format("Price =      |{0,10:C}|", myNumber)
Console.WriteLine(formatFirstName)
Console.WriteLine(formatLastName)
Console.WriteLine(formatPrice)
Console.WriteLine()

formatFirstName = String.Format("First Name = |{0,-10}|", firstName)
formatLastName = String.Format("Last Name =  |{0,-10}|", lastName)
formatPrice = String.Format("Price =      |{0,-10:C}|", myNumber)
Console.WriteLine(formatFirstName)
Console.WriteLine(formatLastName)
Console.WriteLine(formatPrice)

'The example displays the following output on a system whose current
'culture Is en-US:
'    First Name = |      Fred|
'    Last Name =  |     Opals|
'    Price =      |   $100.00|
'
'    First Name = |Fred      |
'    Last Name =  |Opals     |
'    Price =      |$100.00   |

Zobacz też