System.String.Format, metoda
Ten artykuł zawiera dodatkowe uwagi dotyczące dokumentacji referencyjnej dla tego interfejsu API.
Ważne
Zamiast wywoływać metodę String.Format lub używając ciągów formatu złożonego, można użyć ciągów interpolowanych, jeśli język je obsługuje. Ciąg interpolowany to ciąg zawierający 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).
Przykłady
Wiele przykładów, które wywołają metodę Format , są przeplatane w tym artykule. Możesz również pobrać kompletny zestaw przykładów String.Format
, które są dołączone do projektu platformy .NET Core dla języka C#.
Poniżej przedstawiono niektóre przykłady zawarte w artykule:
Tworzenie ciągu formatu
Wstawianie ciągu
Element formatu
Formatuj elementy, które mają ten sam indeks
Sformatowane dane wyjściowe kontrolki
Formatowanie kontrolek
Odstępy między kontrolkami
Wyrównanie kontrolek
Kontrolowanie liczby cyfr całkowitych
Kontrolowanie liczby cyfr po separatorze dziesiętny
Uwzględnij nawiasy klamrowe literału w ciągu wynikowym
Rozróżnianie kultur w ciągach formatu
Rozróżnianie kultur w ciągach formatu
Dostosowywanie operacji formatowania
Niestandardowa operacja formatowania
Dostawca przechwytywania i formater liczb rzymskich
Wprowadzenie do metody String.Format
Użyj String.Format polecenia , jeśli musisz wstawić wartość obiektu, zmiennej lub wyrażenia do innego ciągu. Możesz na przykład wstawić wartość wartości Decimal do ciągu, aby wyświetlić ją użytkownikowi jako pojedynczy ciąg:
Decimal pricePerOunce = 17.36m;
String s = String.Format("The current price is {0} per ounce.",
pricePerOunce);
Console.WriteLine(s);
// Result: The current price is 17.36 per ounce.
let pricePerOunce = 17.36m
String.Format("The current price is {0} per ounce.", pricePerOunce)
|> printfn "%s"
// Result: The current price is 17.36 per ounce.
Dim pricePerOunce As Decimal = 17.36D
Dim s As String = String.Format("The current price is {0} per ounce.",
pricePerOunce)
' Result: The current price is 17.36 per ounce.
Możesz kontrolować formatowanie tej wartości:
Decimal pricePerOunce = 17.36m;
String s = String.Format("The current price is {0:C2} per ounce.",
pricePerOunce);
Console.WriteLine(s);
// Result if current culture is en-US:
// The current price is $17.36 per ounce.
let pricePerOunce = 17.36m
String.Format("The current price is {0:C2} per ounce.", pricePerOunce)
|> printfn "%s"
// Result if current culture is en-US:
// The current price is $17.36 per ounce.
Dim pricePerOunce As Decimal = 17.36D
Dim s As String = String.Format("The current price is {0:C2} per ounce.",
pricePerOunce)
' Result if current culture is en-US:
' The current price is $17.36 per ounce.
Oprócz formatowania można również kontrolować wyrównanie i odstępy.
Wstawianie ciągu
String.Format rozpoczyna się od ciągu formatu, po którym następuje co najmniej jeden obiekt lub wyrażenia, które zostaną przekonwertowane na ciągi i wstawione w określonym miejscu w ciągu formatu. Na przykład:
decimal temp = 20.4m;
string s = String.Format("The temperature is {0}°C.", temp);
Console.WriteLine(s);
// Displays 'The temperature is 20.4°C.'
let temp = 20.4m
String.Format("The temperature is {0}°C.", temp)
|> printfn "%s"
// Displays 'The temperature is 20.4°C.'
Dim temp As Decimal = 20.4D
Dim s As String = String.Format("The temperature is {0}°C.", temp)
Console.WriteLine(s)
' Displays 'The temperature is 20.4°C.'
Element {0}
w ciągu formatu jest elementem formatu. 0
to indeks obiektu, którego wartość ciągu zostanie wstawiona na tej pozycji. (Indeksy zaczynają się od 0). Jeśli obiekt do wstawienia nie jest ciągiem, jego ToString
metoda jest wywoływana w celu przekonwertowania go na jeden przed wstawieniem go w ciągu wynikowym.
Oto inny przykład, który używa dwóch elementów formatu i dwóch obiektów na liście obiektów:
string s = String.Format("At {0}, the temperature is {1}°C.",
DateTime.Now, 20.4);
Console.WriteLine(s);
// Output similar to: 'At 4/10/2015 9:29:41 AM, the temperature is 20.4°C.'
String.Format("At {0}, the temperature is {1}°C.", DateTime.Now, 20.4)
|> printfn "%s"
// Output similar to: 'At 4/10/2015 9:29:41 AM, the temperature is 20.4°C.'
Dim s As String = String.Format("At {0}, the temperature is {1}°C.",
Date.Now, 20.4)
' Output similar to: 'At 4/10/2015 9:29:41 AM, the temperature is 20.4°C.'
Można mieć dowolną liczbę elementów formatu i tyle obiektów na liście obiektów, o ile indeks każdego elementu formatu ma pasujący obiekt na liście obiektów. Nie musisz również martwić się o to, które przeciążenie wywołujesz; kompilator wybierze odpowiedni dla Ciebie.
Formatowanie kontrolek
Indeks można obserwować w elemencie formatu z ciągiem formatu, aby kontrolować sposób formatowania obiektu. Na przykład {0:d}
stosuje ciąg formatu "d" do pierwszego obiektu na liście obiektów. Oto przykład z pojedynczym obiektem i dwoma elementami formatu:
string s = String.Format("It is now {0:d} at {0:t}", DateTime.Now);
Console.WriteLine(s);
// Output similar to: 'It is now 4/10/2015 at 10:04 AM'
String.Format("It is now {0:d} at {0:t}", DateTime.Now)
|> printfn "%s"
// Output similar to: 'It is now 4/10/2015 at 10:04 AM'
Dim s As String = String.Format("It is now {0:d} at {0:t}",
Date.Now)
' Output similar to: 'It is now 4/10/2015 at 10:04 AM'
Wiele typów obsługuje ciągi formatu, w tym wszystkie typy liczbowe (ciągi formatu standardowego i niestandardowego), wszystkie daty i godziny (zarówno ciągi formatu standardowego, jak i niestandardowego) oraz interwały czasu (zarówno ciągi formatu standardowego, jak i niestandardowego), wszystkie typy wyliczenia typów wyliczenia i identyfikatory GUID. Możesz również dodać obsługę ciągów formatu do własnych typów.
Odstępy między kontrolkami
Można zdefiniować szerokość ciągu wstawionego do ciągu wynikowego przy użyciu składni, takiej jak {0,12}
, która wstawia ciąg 12-znakowy. W tym przypadku ciąg reprezentujący pierwszy obiekt jest wyrównany do prawej w polu 12 znaków. (Jeśli ciąg reprezentujący pierwszy obiekt ma długość więcej niż 12 znaków, preferowana szerokość pola jest ignorowana, a cały ciąg jest wstawiany do ciągu wynikowego).
W poniższym przykładzie zdefiniowano 6-znakowe pole do przechowywania ciągu "Year" i ciągów roku, a także 15-znakowe pole do przechowywania ciągu "Population" i niektórych danych populacji. Należy pamiętać, że znaki są wyrównane do prawej strony w polu.
int[] years = { 2013, 2014, 2015 };
int[] population = { 1025632, 1105967, 1148203 };
var sb = new System.Text.StringBuilder();
sb.Append(String.Format("{0,6} {1,15}\n\n", "Year", "Population"));
for (int index = 0; index < years.Length; index++)
sb.Append(String.Format("{0,6} {1,15:N0}\n", years[index], population[index]));
Console.WriteLine(sb);
// Result:
// Year Population
//
// 2013 1,025,632
// 2014 1,105,967
// 2015 1,148,203
open System
open System.Text
let years = [| 2013; 2014; 2015 |]
let population = [| 1025632; 1105967; 1148203 |]
let sb = StringBuilder()
sb.Append(String.Format("{0,6} {1,15}\n\n", "Year", "Population")) |> ignore
for i = 0 to years.Length - 1 do
sb.Append(String.Format("{0,6} {1,15:N0}\n", years[i], population[i])) |> ignore
printfn $"{sb}"
// Result:
// Year Population
//
// 2013 1,025,632
// 2014 1,105,967
// 2015 1,148,203
Dim years() As Integer = {2013, 2014, 2015}
Dim population() As Integer = {1025632, 1105967, 1148203}
Dim sb As New StringBuilder()
sb.Append(String.Format("{0,6} {1,15}{2}{2}",
"Year", "Population", vbCrLf))
For index As Integer = 0 To years.Length - 1
sb.AppendFormat("{0,6} {1,15:N0}{2}",
years(index), population(index), vbCrLf)
Next
' Result:
' Year Population
'
' 2013 1,025,632
' 2014 1,105,967
' 2015 1,148,203
Wyrównanie kontrolek
Domyślnie ciągi są wyrównane do prawej strony w polu, jeśli określisz szerokość pola. Aby wyrównać ciągi do lewej strony w polu, należy poprzeć szerokość pola znakiem ujemnym, takim jak {0,-12}
zdefiniowanie 12-znakowego pola wyrównanego do lewej.
Poniższy przykład jest podobny do poprzedniego, z tą różnicą, że wyrównuje zarówno etykiety, jak i dane.
int[] years = { 2013, 2014, 2015 };
int[] population = { 1025632, 1105967, 1148203 };
String s = String.Format("{0,-10} {1,-10}\n\n", "Year", "Population");
for (int index = 0; index < years.Length; index++)
s += String.Format("{0,-10} {1,-10:N0}\n",
years[index], population[index]);
Console.WriteLine($"\n{s}");
// Result:
// Year Population
//
// 2013 1,025,632
// 2014 1,105,967
// 2015 1,148,203
let years = [| 2013; 2014; 2015 |]
let population = [| 1025632; 1105967; 1148203 |]
let mutable s = String.Format("{0,-10} {1,-10}\n\n", "Year", "Population")
for i = 0 to years.Length - 1 do
s <- s + String.Format("{0,-10} {1,-10:N0}\n", years[i], population[i])
printfn $"\n{s}"
// Result:
// Year Population
//
// 2013 1,025,632
// 2014 1,105,967
// 2015 1,148,203
Dim years() As Integer = {2013, 2014, 2015}
Dim population() As Integer = {1025632, 1105967, 1148203}
Dim s As String = String.Format("{0,-10} {1,-10}{2}{2}",
"Year", "Population", vbCrLf)
For index As Integer = 0 To years.Length - 1
s += String.Format("{0,-10} {1,-10:N0}{2}",
years(index), population(index), vbCrLf)
Next
' Result:
' Year Population
'
' 2013 1,025,632
' 2014 1,105,967
' 2015 1,148,203
String.Format korzysta z funkcji formatowania złożonego. Aby uzyskać więcej informacji, zobacz Formatowanie złożone.
Jaką metodę wywołać?
Działanie | Wywołanie |
---|---|
Sformatuj co najmniej jeden obiekt przy użyciu konwencji bieżącej kultury. | Z wyjątkiem przeciążeń, które zawierają parametr, pozostałe Format przeciążenia obejmują provider String parametr, po którym następuje co najmniej jeden parametr obiektu. W związku z tym nie trzeba określać, które Format przeciążenie ma być wywoływane. Kompilator języka wybiera odpowiednie przeciążenie spośród przeciążeń, które nie mają parametru provider na podstawie listy argumentów. Jeśli na przykład lista argumentów zawiera pięć argumentów, kompilator wywołuje metodę Format(String, Object[]) . |
Formatuj co najmniej jeden obiekt przy użyciu konwencji określonej kultury. | Każde Format przeciążenie, które zaczyna się od parametru provider , następuje String parametr i co najmniej jeden parametr obiektu. W związku z tym nie trzeba określać konkretnego Format przeciążenia, które ma być wywoływane. Kompilator języka wybiera odpowiednie przeciążenie spośród przeciążeń, które mają provider parametr na podstawie listy argumentów. Jeśli na przykład lista argumentów zawiera pięć argumentów, kompilator wywołuje metodę Format(IFormatProvider, String, Object[]) . |
Wykonaj niestandardową operację formatowania z implementacją ICustomFormatter lub implementacją IFormattable . | Każde z czterech przeciążeń z parametrem provider . Kompilator wybiera odpowiednie przeciążenie spośród przeciążeń, które mają provider parametr na podstawie listy argumentów. |
Metoda formatowania w skrócie
Każde przeciążenie metody używa funkcji formatowania złożonego Formatw celu uwzględnienia symboli zastępczych indeksowanych na podstawie zera, nazywanych elementami formatu, w ciągu formatu złożonego. W czasie wykonywania każdy element formatu jest zastępowany ciągiem reprezentującym odpowiedni argument na liście parametrów. Jeśli wartość argumentu to null
, element formatu zostanie zastąpiony elementem String.Empty. Na przykład następujące wywołanie Format(String, Object, Object, Object) metody zawiera ciąg formatu z trzema elementami formatu, {0}, {1}i {2}, oraz listą argumentów z trzema elementami.
DateTime dat = new DateTime(2012, 1, 17, 9, 30, 0);
string city = "Chicago";
int temp = -16;
string output = String.Format("At {0} in {1}, the temperature was {2} degrees.",
dat, city, temp);
Console.WriteLine(output);
// The example displays output like the following:
// At 1/17/2012 9:30:00 AM in Chicago, the temperature was -16 degrees.
open System
let dat = DateTime(2012, 1, 17, 9, 30, 0)
let city = "Chicago"
let temp = -16
String.Format("At {0} in {1}, the temperature was {2} degrees.", dat, city, temp)
|> printfn "%s"
// The example displays output like the following:
// At 1/17/2012 9:30:00 AM in Chicago, the temperature was -16 degrees.
Dim dat As Date = #1/17/2012 9:30AM#
Dim city As String = "Chicago"
Dim temp As Integer = -16
Dim output As String = String.Format("At {0} in {1}, the temperature was {2} degrees.",
dat, city, temp)
Console.WriteLine(output)
' The example displays the following output:
' At 1/17/2012 9:30:00 AM in Chicago, the temperature was -16 degrees.
Element formatu
Element formatu ma następującą składnię:
{index[,alignment][:formatString]}
Nawiasy oznaczają elementy opcjonalne. Wymagane są nawiasy klamrowe otwierające i zamykające. (Aby dołączyć literał otwierający lub zamykający nawias klamrowy w ciągu formatu, zobacz Sekcja Ucieczka nawiasów klamrowych w artykule Dotyczącym formatowania złożonego).
Na przykład element formatu do formatowania wartości waluty może wyglądać następująco:
var value = String.Format("{0,-10:C}", 126347.89m);
Console.WriteLine(value);
open System
String.Format("{0,-10:C}", 126347.89m)
|> printfn "%s"
String.Format("{0,-10:C}", 126347.89D)
Element formatu ma następujące elementy:
Indeks
Indeks zerowy argumentu, którego reprezentacja ciągu ma zostać uwzględniona w tym miejscu w ciągu. Jeśli ten argument to null
, pusty ciąg zostanie uwzględniony na tym miejscu w ciągu.
Wyrównanie
Opcjonalny. Liczba całkowita ze znakiem wskazująca całkowitą długość pola, do którego wstawiono argument i czy jest wyrównana do prawej (dodatnia liczba całkowita) lub wyrównana do lewej (ujemna liczba całkowita). W przypadku pominięcia wyrównania ciąg reprezentujący odpowiedni argument zostanie wstawiony w polu bez spacji wiodących ani końcowych.
Jeśli wartość wyrównania jest mniejsza niż długość argumentu do wstawienia, wyrównanie jest ignorowane, a długość ciągu reprezentacja argumentu jest używana jako szerokość pola.
Formatstring
Opcjonalny. Ciąg określający format ciągu wynikowego odpowiedniego argumentu. Jeśli pominięto formatString, metoda bez ToString
parametrów odpowiedniego argumentu jest wywoływana w celu utworzenia jego reprezentacji ciągu. Jeśli określisz formatString, argument, do którego odwołuje się element formatu, musi zaimplementować IFormattable interfejs. Typy, które obsługują ciągi formatu, to:
Wszystkie typy całkowitoliczkowe i zmiennoprzecinkowe. (Zobacz Standardowe ciągi formatu liczbowego i niestandardowe ciągi formatu liczbowego.
DateTime i DateTimeOffset. (Zobacz Standardowe ciągi formatu daty i godziny oraz niestandardowe ciągi formatu daty i godziny.
Wszystkie typy wyliczenia. (Zobacz Ciągi formatu wyliczenia).
TimeSpan Wartości. (Zobacz Standardowe ciągi formatu TimeSpan i niestandardowe ciągi formatu TimeSpan.
Identyfikatory guid. (Zobacz metodę Guid.ToString(String) ).
Należy jednak pamiętać, że dowolny typ niestandardowy może implementować IFormattable lub rozszerzać implementację IFormattable istniejącego typu.
W poniższym przykładzie alignment
użyto argumentów i formatString
do wygenerowania sformatowanych danych wyjściowych.
// Create array of 5-tuples with population data for three U.S. cities, 1940-1950.
Tuple<string, DateTime, int, DateTime, int>[] cities =
{ Tuple.Create("Los Angeles", new DateTime(1940, 1, 1), 1504277,
new DateTime(1950, 1, 1), 1970358),
Tuple.Create("New York", new DateTime(1940, 1, 1), 7454995,
new DateTime(1950, 1, 1), 7891957),
Tuple.Create("Chicago", new DateTime(1940, 1, 1), 3396808,
new DateTime(1950, 1, 1), 3620962),
Tuple.Create("Detroit", new DateTime(1940, 1, 1), 1623452,
new DateTime(1950, 1, 1), 1849568) };
// Display header
var header = String.Format("{0,-12}{1,8}{2,12}{1,8}{2,12}{3,14}\n",
"City", "Year", "Population", "Change (%)");
Console.WriteLine(header);
foreach (var city in cities) {
var output = String.Format("{0,-12}{1,8:yyyy}{2,12:N0}{3,8:yyyy}{4,12:N0}{5,14:P1}",
city.Item1, city.Item2, city.Item3, city.Item4, city.Item5,
(city.Item5 - city.Item3)/ (double)city.Item3);
Console.WriteLine(output);
}
// The example displays the following output:
// City Year Population Year Population Change (%)
//
// Los Angeles 1940 1,504,277 1950 1,970,358 31.0 %
// New York 1940 7,454,995 1950 7,891,957 5.9 %
// Chicago 1940 3,396,808 1950 3,620,962 6.6 %
// Detroit 1940 1,623,452 1950 1,849,568 13.9 %
// Create a list of 5-tuples with population data for three U.S. cities, 1940-1950.
let cities =
[ "Los Angeles", DateTime(1940, 1, 1), 1504277, DateTime(1950, 1, 1), 1970358
"New York", DateTime(1940, 1, 1), 7454995, DateTime(1950, 1, 1), 7891957
"Chicago", DateTime(1940, 1, 1), 3396808, DateTime(1950, 1, 1), 3620962
"Detroit", DateTime(1940, 1, 1), 1623452, DateTime(1950, 1, 1), 1849568 ]
// Display header
String.Format("{0,-12}{1,8}{2,12}{1,8}{2,12}{3,14}\n", "City", "Year", "Population", "Change (%)")
|> printfn "%s"
for name, year1, pop1, year2, pop2 in cities do
String.Format("{0,-12}{1,8:yyyy}{2,12:N0}{3,8:yyyy}{4,12:N0}{5,14:P1}",
name, year1, pop1, year2, pop2,
double (pop2 - pop1) / double pop1)
|> printfn "%s"
// The example displays the following output:
// City Year Population Year Population Change (%)
//
// Los Angeles 1940 1,504,277 1950 1,970,358 31.0 %
// New York 1940 7,454,995 1950 7,891,957 5.9 %
// Chicago 1940 3,396,808 1950 3,620,962 6.6 %
// Detroit 1940 1,623,452 1950 1,849,568 13.9 %
Module Example3
Public Sub Main()
' Create array of 5-tuples with population data for three U.S. cities, 1940-1950.
Dim cities() =
{Tuple.Create("Los Angeles", #1/1/1940#, 1504277, #1/1/1950#, 1970358),
Tuple.Create("New York", #1/1/1940#, 7454995, #1/1/1950#, 7891957),
Tuple.Create("Chicago", #1/1/1940#, 3396808, #1/1/1950#, 3620962),
Tuple.Create("Detroit", #1/1/1940#, 1623452, #1/1/1950#, 1849568)}
' Display header
Dim header As String = String.Format("{0,-12}{1,8}{2,12}{1,8}{2,12}{3,14}",
"City", "Year", "Population", "Change (%)")
Console.WriteLine(header)
Console.WriteLine()
For Each city In cities
Dim output = String.Format("{0,-12}{1,8:yyyy}{2,12:N0}{3,8:yyyy}{4,12:N0}{5,14:P1}",
city.Item1, city.Item2, city.Item3, city.Item4, city.Item5,
(city.Item5 - city.Item3) / city.Item3)
Console.WriteLine(output)
Next
End Sub
End Module
' The example displays the following output:
' City Year Population Year Population Change (%)
'
' Los Angeles 1940 1,504,277 1950 1,970,358 31.0 %
' New York 1940 7,454,995 1950 7,891,957 5.9 %
' Chicago 1940 3,396,808 1950 3,620,962 6.6 %
' Detroit 1940 1,623,452 1950 1,849,568 13.9 %
Sposób formatowania argumentów
Elementy formatu są przetwarzane sekwencyjnie od początku ciągu. Każdy element formatu ma indeks odpowiadający obiektowi na liście argumentów metody. Metoda Format pobiera argument i uzyskuje jego reprezentację ciągu w następujący sposób:
Jeśli argument to
null
, metoda wstawia String.Empty do ciągu wynikowego. Nie musisz zajmować się obsługą NullReferenceException argumentów o wartości null.Jeśli wywołasz Format(IFormatProvider, String, Object[]) przeciążenie, a
provider
implementacja IFormatProvider.GetFormat obiektu zwróci implementację inną niż null ICustomFormatter , argument zostanie przekazany do jego ICustomFormatter.Format(String, Object, IFormatProvider) metody. Jeśli element formatu zawiera argument formatString , jest przekazywany jako pierwszy argument do metody . Jeśli implementacja ICustomFormatter jest dostępna i generuje ciąg inny niż null, ten ciąg jest zwracany jako reprezentacja ciągu argumentu; w przeciwnym razie zostanie wykonany następny krok.Jeśli argument implementuje IFormattable interfejs, wywoływana jest jego IFormattable.ToString implementacja.
Wywoływana jest metoda bez
ToString
parametrów argumentu, która zastępuje lub dziedziczy z implementacji klasy bazowej.
Przykład, który przechwytuje wywołania ICustomFormatter.Format metody i pozwala zobaczyć, jakie informacje metoda Format przekazuje do metody formatowania dla każdego elementu formatu w ciągu formatu złożonego, zobacz Przykład: dostawca przechwytywania i formater liczb rzymskich.
Aby uzyskać więcej informacji, zobacz Przetwarzanie zamówienia.
Elementy formatu o tym samym indeksie
Metoda Format zgłasza FormatException wyjątek, jeśli indeks elementu indeksu jest większy lub równy liczbie argumentów na liście argumentów. format
Może jednak zawierać więcej elementów formatu niż argumenty, o ile wiele elementów formatu ma ten sam indeks. W wywołaniu Format(String, Object) metody w poniższym przykładzie lista argumentów ma jeden argument, ale ciąg formatu zawiera dwa elementy formatu: jeden wyświetla wartość dziesiętną liczby, a drugi wyświetla jego wartość szesnastkowa.
short[] values= { Int16.MinValue, -27, 0, 1042, Int16.MaxValue };
Console.WriteLine("{0,10} {1,10}\n", "Decimal", "Hex");
foreach (short value in values)
{
string formatString = String.Format("{0,10:G}: {0,10:X}", value);
Console.WriteLine(formatString);
}
// The example displays the following output:
// Decimal Hex
//
// -32768: 8000
// -27: FFE5
// 0: 0
// 1042: 412
// 32767: 7FFF
open System
let values= [| Int16.MinValue; -27s; 0s; 1042s; Int16.MaxValue |]
printfn "%10s %10s\n" "Decimal" "Hex"
for value in values do
String.Format("{0,10:G}: {0,10:X}", value)
|> printfn "%s"
// The example displays the following output:
// Decimal Hex
//
// -32768: 8000
// -27: FFE5
// 0: 0
// 1042: 412
// 32767: 7FFF
Module Example1
Public Sub Main()
Dim values() As Short = {Int16.MinValue, -27, 0, 1042, Int16.MaxValue}
Console.WriteLine("{0,10} {1,10}", "Decimal", "Hex")
Console.WriteLine()
For Each value As Short In values
Dim formatString As String = String.Format("{0,10:G}: {0,10:X}", value)
Console.WriteLine(formatString)
Next
End Sub
End Module
' The example displays the following output:
' Decimal Hex
'
' -32768: 8000
' -27: FFE5
' 0: 0
' 1042: 412
' 32767: 7FFF
Format i kultura
Ogólnie rzecz biorąc, obiekty na liście argumentów są konwertowane na ich reprezentacje ciągów przy użyciu konwencji bieżącej kultury, która jest zwracana przez CultureInfo.CurrentCulture właściwość . To zachowanie można kontrolować, wywołując jedno z przeciążeń Format , które zawiera provider
parametr. Parametr provider
jest implementacją IFormatProvider , która dostarcza informacje dotyczące formatowania niestandardowego i specyficznego dla kultury, które są używane do moderowania procesu formatowania.
Interfejs IFormatProvider ma jeden element członkowski , GetFormatktóry jest odpowiedzialny za zwrócenie obiektu, który udostępnia informacje o formatowaniu. Platforma .NET ma trzy IFormatProvider implementacje, które zapewniają formatowanie specyficzne dla kultury:
- CultureInfo. Metoda GetFormat zwraca obiekt specyficzny dla NumberFormatInfo kultury do formatowania wartości liczbowych i obiektu specyficznego dla DateTimeFormatInfo kultury do formatowania wartości daty i godziny.
- DateTimeFormatInfo, który jest używany do formatowania wartości daty i godziny specyficznego dla kultury. Metoda GetFormat zwraca się sama.
- NumberFormatInfo, który jest używany do formatowania wartości liczbowych specyficznych dla kultury. Metoda GetFormat(Type) zwraca się sama.
Niestandardowe formatowanie operacji
Można również wywołać dowolne przeciążenia Format metody, które mają provider
parametr typu IFormatProvider , aby wykonać niestandardowe operacje formatowania. Można na przykład sformatować liczbę całkowitą jako numer identyfikacyjny lub numer telefonu. Aby wykonać niestandardowe formatowanie, provider
argument musi implementować zarówno interfejsy , jak IFormatProvider i ICustomFormatter . Format Gdy metoda jest przekazywana implementacji ICustomFormatter jako provider
argument, Format metoda wywołuje jego IFormatProvider.GetFormat implementację i żąda obiektu typu ICustomFormatter. Następnie wywołuje metodę zwróconego ICustomFormatterFormat obiektu w celu sformatowania każdego elementu formatu w przekazanym do niego ciągu złożonego.
Aby uzyskać więcej informacji na temat udostępniania niestandardowych rozwiązań formatowania, zobacz How to: Define and Use Custom Numeric Format Providers and ICustomFormatter. Przykład, który konwertuje liczby całkowite na sformatowane liczby niestandardowe, zobacz Przykład: niestandardowa operacja formatowania. Przykład, który konwertuje niepodpisane bajty na liczby rzymskie, zobacz Przykład: dostawca przechwytywania i formater liczb rzymskich.
Przykład: niestandardowa operacja formatowania
W tym przykładzie zdefiniowano dostawcę formatu, który formatuje wartość całkowitą jako numer konta klienta w postaci x-xxxxx-xx.
using System;
public class TestFormatter
{
public static void Main()
{
int acctNumber = 79203159;
Console.WriteLine(String.Format(new CustomerFormatter(), "{0}", acctNumber));
Console.WriteLine(String.Format(new CustomerFormatter(), "{0:G}", acctNumber));
Console.WriteLine(String.Format(new CustomerFormatter(), "{0:S}", acctNumber));
Console.WriteLine(String.Format(new CustomerFormatter(), "{0:P}", acctNumber));
try {
Console.WriteLine(String.Format(new CustomerFormatter(), "{0:X}", acctNumber));
}
catch (FormatException e) {
Console.WriteLine(e.Message);
}
}
}
public class CustomerFormatter : IFormatProvider, ICustomFormatter
{
public object GetFormat(Type formatType)
{
if (formatType == typeof(ICustomFormatter))
return this;
else
return null;
}
public string Format(string format,
object arg,
IFormatProvider formatProvider)
{
if (! this.Equals(formatProvider))
{
return null;
}
else
{
if (String.IsNullOrEmpty(format))
format = "G";
string customerString = arg.ToString();
if (customerString.Length < 8)
customerString = customerString.PadLeft(8, '0');
format = format.ToUpper();
switch (format)
{
case "G":
return customerString.Substring(0, 1) + "-" +
customerString.Substring(1, 5) + "-" +
customerString.Substring(6);
case "S":
return customerString.Substring(0, 1) + "/" +
customerString.Substring(1, 5) + "/" +
customerString.Substring(6);
case "P":
return customerString.Substring(0, 1) + "." +
customerString.Substring(1, 5) + "." +
customerString.Substring(6);
default:
throw new FormatException(
String.Format("The '{0}' format specifier is not supported.", format));
}
}
}
}
// The example displays the following output:
// 7-92031-59
// 7-92031-59
// 7/92031/59
// 7.92031.59
// The 'X' format specifier is not supported.
open System
type CustomerFormatter() =
interface IFormatProvider with
member this.GetFormat(formatType) =
if formatType = typeof<ICustomFormatter> then
this
else
null
interface ICustomFormatter with
member this.Format(format, arg, formatProvider: IFormatProvider) =
if this.Equals formatProvider |> not then
null
else
let format =
if String.IsNullOrEmpty format then "G"
else format.ToUpper()
let customerString =
let s = string arg
if s.Length < 8 then
s.PadLeft(8, '0')
else s
match format with
| "G" ->
customerString.Substring(0, 1) + "-" +
customerString.Substring(1, 5) + "-" +
customerString.Substring 6
| "S" ->
customerString.Substring(0, 1) + "/" +
customerString.Substring(1, 5) + "/" +
customerString.Substring 6
| "P" ->
customerString.Substring(0, 1) + "." +
customerString.Substring(1, 5) + "." +
customerString.Substring 6
| _ ->
raise (FormatException $"The '{format}' format specifier is not supported.")
let acctNumber = 79203159
String.Format(CustomerFormatter(), "{0}", acctNumber)
|> printfn "%s"
String.Format(CustomerFormatter(), "{0:G}", acctNumber)
|> printfn "%s"
String.Format(CustomerFormatter(), "{0:S}", acctNumber)
|> printfn "%s"
String.Format(CustomerFormatter(), "{0:P}", acctNumber)
|> printfn "%s"
try
String.Format(CustomerFormatter(), "{0:X}", acctNumber)
|> printfn "%s"
with :? FormatException as e ->
printfn $"{e.Message}"
// The example displays the following output:
// 7-92031-59
// 7-92031-59
// 7/92031/59
// 7.92031.59
// The 'X' format specifier is not supported.
Module TestFormatter
Public Sub Main()
Dim acctNumber As Integer = 79203159
Console.WriteLine(String.Format(New CustomerFormatter, "{0}", acctNumber))
Console.WriteLine(String.Format(New CustomerFormatter, "{0:G}", acctNumber))
Console.WriteLine(String.Format(New CustomerFormatter, "{0:S}", acctNumber))
Console.WriteLine(String.Format(New CustomerFormatter, "{0:P}", acctNumber))
Try
Console.WriteLine(String.Format(New CustomerFormatter, "{0:X}", acctNumber))
Catch e As FormatException
Console.WriteLine(e.Message)
End Try
End Sub
End Module
Public Class CustomerFormatter : Implements IFormatProvider, ICustomFormatter
Public Function GetFormat(type As Type) As Object _
Implements IFormatProvider.GetFormat
If type Is GetType(ICustomFormatter) Then
Return Me
Else
Return Nothing
End If
End Function
Public Function Format(fmt As String, _
arg As Object, _
formatProvider As IFormatProvider) As String _
Implements ICustomFormatter.Format
If Not Me.Equals(formatProvider) Then
Return Nothing
Else
If String.IsNullOrEmpty(fmt) Then fmt = "G"
Dim customerString As String = arg.ToString()
if customerString.Length < 8 Then _
customerString = customerString.PadLeft(8, "0"c)
Select Case fmt
Case "G"
Return customerString.Substring(0, 1) & "-" & _
customerString.Substring(1, 5) & "-" & _
customerString.Substring(6)
Case "S"
Return customerString.Substring(0, 1) & "/" & _
customerString.Substring(1, 5) & "/" & _
customerString.Substring(6)
Case "P"
Return customerString.Substring(0, 1) & "." & _
customerString.Substring(1, 5) & "." & _
customerString.Substring(6)
Case Else
Throw New FormatException( _
String.Format("The '{0}' format specifier is not supported.", fmt))
End Select
End If
End Function
End Class
' The example displays the following output:
' 7-92031-59
' 7-92031-59
' 7/92031/59
' 7.92031.59
' The 'X' format specifier is not supported.
Przykład: dostawca przechwytywania i formater liczb rzymskich
W tym przykładzie zdefiniowano niestandardowego dostawcę formatu, który implementuje ICustomFormatter interfejsy i IFormatProvider w celu wykonania dwóch czynności:
Wyświetla on parametry przekazane do jego ICustomFormatter.Format implementacji. Dzięki temu możemy zobaczyć, jakie parametry Format(IFormatProvider, String, Object[]) metoda przekazuje do niestandardowej implementacji formatowania dla każdego obiektu, który próbuje sformatować. Może to być przydatne podczas debugowania aplikacji.
Jeśli obiekt do sformatowania jest niepodpisaną wartością bajtu, która ma być sformatowana przy użyciu standardowego ciągu formatu "R", formatator niestandardowy formatuje wartość liczbową jako cyfrę rzymską.
using System;
using System.Globalization;
public class InterceptProvider : IFormatProvider, ICustomFormatter
{
public object GetFormat(Type formatType)
{
if (formatType == typeof(ICustomFormatter))
return this;
else
return null;
}
public string Format(String format, Object obj, IFormatProvider provider)
{
// Display information about method call.
string formatString = format ?? "<null>";
Console.WriteLine("Provider: {0}, Object: {1}, Format String: {2}",
provider.GetType().Name, obj ?? "<null>", formatString);
if (obj == null) return String.Empty;
// If this is a byte and the "R" format string, format it with Roman numerals.
if (obj is Byte && formatString.ToUpper().Equals("R")) {
Byte value = (Byte) obj;
int remainder;
int result;
String returnString = String.Empty;
// Get the hundreds digit(s)
result = Math.DivRem(value, 100, out remainder);
if (result > 0)
returnString = new String('C', result);
value = (Byte) remainder;
// Get the 50s digit
result = Math.DivRem(value, 50, out remainder);
if (result == 1)
returnString += "L";
value = (Byte) remainder;
// Get the tens digit.
result = Math.DivRem(value, 10, out remainder);
if (result > 0)
returnString += new String('X', result);
value = (Byte) remainder;
// Get the fives digit.
result = Math.DivRem(value, 5, out remainder);
if (result > 0)
returnString += "V";
value = (Byte) remainder;
// Add the ones digit.
if (remainder > 0)
returnString += new String('I', remainder);
// Check whether we have too many X characters.
int pos = returnString.IndexOf("XXXX");
if (pos >= 0) {
int xPos = returnString.IndexOf("L");
if (xPos >= 0 & xPos == pos - 1)
returnString = returnString.Replace("LXXXX", "XC");
else
returnString = returnString.Replace("XXXX", "XL");
}
// Check whether we have too many I characters
pos = returnString.IndexOf("IIII");
if (pos >= 0)
if (returnString.IndexOf("V") >= 0)
returnString = returnString.Replace("VIIII", "IX");
else
returnString = returnString.Replace("IIII", "IV");
return returnString;
}
// Use default for all other formatting.
if (obj is IFormattable)
return ((IFormattable) obj).ToString(format, CultureInfo.CurrentCulture);
else
return obj.ToString();
}
}
public class Example
{
public static void Main()
{
int n = 10;
double value = 16.935;
DateTime day = DateTime.Now;
InterceptProvider provider = new InterceptProvider();
Console.WriteLine(String.Format(provider, "{0:N0}: {1:C2} on {2:d}\n", n, value, day));
Console.WriteLine(String.Format(provider, "{0}: {1:F}\n", "Today: ",
(DayOfWeek) DateTime.Now.DayOfWeek));
Console.WriteLine(String.Format(provider, "{0:X}, {1}, {2}\n",
(Byte) 2, (Byte) 12, (Byte) 199));
Console.WriteLine(String.Format(provider, "{0:R}, {1:R}, {2:R}\n",
(Byte) 2, (Byte) 12, (Byte) 199));
}
}
// The example displays the following output:
// Provider: InterceptProvider, Object: 10, Format String: N0
// Provider: InterceptProvider, Object: 16.935, Format String: C2
// Provider: InterceptProvider, Object: 1/31/2013 6:10:28 PM, Format String: d
// 10: $16.94 on 1/31/2013
//
// Provider: InterceptProvider, Object: Today: , Format String: <null>
// Provider: InterceptProvider, Object: Thursday, Format String: F
// Today: : Thursday
//
// Provider: InterceptProvider, Object: 2, Format String: X
// Provider: InterceptProvider, Object: 12, Format String: <null>
// Provider: InterceptProvider, Object: 199, Format String: <null>
// 2, 12, 199
//
// Provider: InterceptProvider, Object: 2, Format String: R
// Provider: InterceptProvider, Object: 12, Format String: R
// Provider: InterceptProvider, Object: 199, Format String: R
// II, XII, CXCIX
open System
open System.Globalization
type InterceptProvider() =
interface IFormatProvider with
member this.GetFormat(formatType) =
if formatType = typeof<ICustomFormatter> then
this
else
null
interface ICustomFormatter with
member _.Format(format, obj, provider: IFormatProvider) =
// Display information about method call.
let formatString =
if format = null then "<null>" else format
printfn $"Provider: {provider.GetType().Name}, Object: %A{obj}, Format String: %s{formatString}"
if obj = null then
String.Empty
else
// If this is a byte and the "R" format string, format it with Roman numerals.
match obj with
| :? byte as value when formatString.ToUpper().Equals "R" ->
let mutable returnString = String.Empty
// Get the hundreds digit(s)
let struct (result, remainder) = Math.DivRem(value, 100uy)
if result > 0uy then
returnString <- String('C', int result)
let value = byte remainder
// Get the 50s digit
let struct (result, remainder) = Math.DivRem(value, 50uy)
if result = 1uy then
returnString <- returnString + "L"
let value = byte remainder
// Get the tens digit.
let struct (result, remainder) = Math.DivRem(value, 10uy)
if result > 0uy then
returnString <- returnString + String('X', int result)
let value = byte remainder
// Get the fives digit.
let struct (result, remainder) = Math.DivRem(value, 5uy)
if result > 0uy then
returnString <- returnString + "V"
let value = byte remainder
// Add the ones digit.
if remainder > 0uy then
returnString <- returnString + String('I', int remainder)
// Check whether we have too many X characters.
let pos = returnString.IndexOf "XXXX"
if pos >= 0 then
let xPos = returnString.IndexOf "L"
returnString <-
if xPos >= 0 && xPos = pos - 1 then
returnString.Replace("LXXXX", "XC")
else
returnString.Replace("XXXX", "XL")
// Check whether we have too many I characters
let pos = returnString.IndexOf "IIII"
if pos >= 0 then
returnString <-
if returnString.IndexOf "V" >= 0 then
returnString.Replace("VIIII", "IX")
else
returnString.Replace("IIII", "IV")
returnString
// Use default for all other formatting.
| :? IFormattable as x ->
x.ToString(format, CultureInfo.CurrentCulture)
| _ ->
string obj
let n = 10
let value = 16.935
let day = DateTime.Now
let provider = InterceptProvider()
String.Format(provider, "{0:N0}: {1:C2} on {2:d}\n", n, value, day)
|> printfn "%s"
String.Format(provider, "{0}: {1:F}\n", "Today: ", DateTime.Now.DayOfWeek)
|> printfn "%s"
String.Format(provider, "{0:X}, {1}, {2}\n", 2uy, 12uy, 199uy)
|> printfn "%s"
String.Format(provider, "{0:R}, {1:R}, {2:R}\n", 2uy, 12uy, 199uy)
|> printfn "%s"
// The example displays the following output:
// Provider: InterceptProvider, Object: 10, Format String: N0
// Provider: InterceptProvider, Object: 16.935, Format String: C2
// Provider: InterceptProvider, Object: 1/31/2013 6:10:28 PM, Format String: d
// 10: $16.94 on 1/31/2013
//
// Provider: InterceptProvider, Object: Today: , Format String: <null>
// Provider: InterceptProvider, Object: Thursday, Format String: F
// Today: : Thursday
//
// Provider: InterceptProvider, Object: 2, Format String: X
// Provider: InterceptProvider, Object: 12, Format String: <null>
// Provider: InterceptProvider, Object: 199, Format String: <null>
// 2, 12, 199
//
// Provider: InterceptProvider, Object: 2, Format String: R
// Provider: InterceptProvider, Object: 12, Format String: R
// Provider: InterceptProvider, Object: 199, Format String: R
// II, XII, CXCIX
Imports System.Globalization
Public Class InterceptProvider : Implements IFormatProvider, ICustomFormatter
Public Function GetFormat(formatType As Type) As Object _
Implements IFormatProvider.GetFormat
If formatType Is GetType(ICustomFormatter) Then
Return Me
Else
Return Nothing
End If
End Function
Public Function Format(fmt As String, obj As Object, provider As IFormatProvider) As String _
Implements ICustomFormatter.Format
Dim formatString As String = If(fmt IsNot Nothing, fmt, "<null>")
Console.WriteLine("Provider: {0}, Object: {1}, Format String: {2}",
provider, If(obj IsNot Nothing, obj, "<null>"), formatString)
If obj Is Nothing Then Return String.Empty
' If this is a byte and the "R" format string, format it with Roman numerals.
If TypeOf(obj) Is Byte AndAlso formatString.ToUpper.Equals("R") Then
Dim value As Byte = CByte(obj)
Dim remainder As Integer
Dim result As Integer
Dim returnString As String = String.Empty
' Get the hundreds digit(s)
result = Math.DivRem(value, 100, remainder)
If result > 0 Then returnString = New String("C"c, result)
value = CByte(remainder)
' Get the 50s digit
result = Math.DivRem(value, 50, remainder)
If result = 1 Then returnString += "L"
value = CByte(remainder)
' Get the tens digit.
result = Math.DivRem(value, 10, remainder)
If result > 0 Then returnString += New String("X"c, result)
value = CByte(remainder)
' Get the fives digit.
result = Math.DivRem(value, 5, remainder)
If result > 0 Then returnString += "V"
value = CByte(remainder)
' Add the ones digit.
If remainder > 0 Then returnString += New String("I"c, remainder)
' Check whether we have too many X characters.
Dim pos As Integer = returnString.IndexOf("XXXX")
If pos >= 0 Then
Dim xPos As Integer = returnString.IndexOf("L")
If xPos >= 0 And xPos = pos - 1 Then
returnString = returnString.Replace("LXXXX", "XC")
Else
returnString = returnString.Replace("XXXX", "XL")
End If
End If
' Check whether we have too many I characters
pos = returnString.IndexOf("IIII")
If pos >= 0 Then
If returnString.IndexOf("V") >= 0 Then
returnString = returnString.Replace("VIIII", "IX")
Else
returnString = returnString.Replace("IIII", "IV")
End If
End If
Return returnString
End If
' Use default for all other formatting.
If obj Is GetType(IFormattable)
Return CType(obj, IFormattable).ToString(fmt, CultureInfo.CurrentCulture)
Else
Return obj.ToString()
End If
End Function
End Class
Module Example
Public Sub Main()
Dim n As Integer = 10
Dim value As Double = 16.935
Dim day As DateTime = Date.Now
Dim provider As New InterceptProvider()
Console.WriteLine(String.Format(provider, "{0:N0}: {1:C2} on {2:d}", n, value, day))
Console.WriteLine()
Console.WriteLine(String.Format(provider, "{0}: {1:F}", "Today",
CType(Date.Now.DayOfWeek, DayOfWeek)))
Console.WriteLine()
Console.WriteLine(String.Format(provider, "{0:X}, {1}, {2}\n",
CByte(2), CByte(12), CByte(199)))
Console.WriteLine()
Console.WriteLine(String.Format(provider, "{0:R}, {1:R}, {2:R}",
CByte(2), CByte(12), CByte(199)))
End Sub
End Module
' The example displays the following output:
' Provider: InterceptProvider, Object: 10, Format String: N0
' Provider: InterceptProvider, Object: 16.935, Format String: C2
' Provider: InterceptProvider, Object: 1/31/2013 6:10:28 PM, Format String: d
' 10: $16.94 on 1/31/2013
'
' Provider: InterceptProvider, Object: Today: , Format String: <null>
' Provider: InterceptProvider, Object: Thursday, Format String: F
' Today: : Thursday
'
' Provider: InterceptProvider, Object: 2, Format String: X
' Provider: InterceptProvider, Object: 12, Format String: <null>
' Provider: InterceptProvider, Object: 199, Format String: <null>
' 2, 12, 199
'
' Provider: InterceptProvider, Object: 2, Format String: R
' Provider: InterceptProvider, Object: 12, Format String: R
' Provider: InterceptProvider, Object: 199, Format String: R
' II, XII, CXCIX
Często zadawane pytania
Dlaczego zaleca się interpolację ciągów przez wywołania String.Format
metody?
Interpolacja ciągów to:
Bardziej elastyczne. Można go używać w dowolnym ciągu bez konieczności wywołania metody obsługującej formatowanie złożone. W przeciwnym razie należy wywołać metodę Format lub inną metodę, która obsługuje formatowanie złożone, takie jak Console.WriteLine lub StringBuilder.AppendFormat.
Bardziej czytelny. Ponieważ wyrażenie do wstawiania do ciągu pojawia się w wyrażeniu interpolowanym, a nie na liście argumentów, ciągi interpolowane są znacznie łatwiejsze do kodowania i odczytywania. Ze względu na większą czytelność ciągi interpolowane mogą zastępować nie tylko wywołania metod formatowania złożonego, ale mogą być również używane w operacjach łączenia ciągów w celu uzyskania bardziej zwięzłego, jaśniejszego kodu.
Porównanie poniższych dwóch przykładów kodu ilustruje przewagę ciągów interpolowanych za pośrednictwem łączenia ciągów i wywołań metod formatowania złożonego. Użycie wielu operacji łączenia ciągów w poniższym przykładzie powoduje utworzenie pełnego i trudnego do odczytania kodu.
string[] names = { "Balto", "Vanya", "Dakota", "Samuel", "Koani", "Yiska", "Yuma" };
string output = names[0] + ", " + names[1] + ", " + names[2] + ", " +
names[3] + ", " + names[4] + ", " + names[5] + ", " +
names[6];
output += "\n";
var date = DateTime.Now;
output += String.Format("It is {0:t} on {0:d}. The day of the week is {1}.",
date, date.DayOfWeek);
Console.WriteLine(output);
// The example displays the following output:
// Balto, Vanya, Dakota, Samuel, Koani, Yiska, Yuma
// It is 10:29 AM on 1/8/2018. The day of the week is Monday.
open System
let names = [| "Balto"; "Vanya"; "Dakota"; "Samuel"; "Koani"; "Yiska"; "Yuma" |]
let output =
names[0] + ", " + names[1] + ", " + names[2] + ", " +
names[3] + ", " + names[4] + ", " + names[5] + ", " +
names[6] + "\n"
let date = DateTime.Now
output + String.Format("It is {0:t} on {0:d}. The day of the week is {1}.", date, date.DayOfWeek)
|> printfn "%s"
// The example displays the following output:
// Balto, Vanya, Dakota, Samuel, Koani, Yiska, Yuma
// It is 10:29 AM on 1/8/2018. The day of the week is Monday.
Module Example12
Public Sub Main()
Dim names = {"Balto", "Vanya", "Dakota", "Samuel", "Koani", "Yiska", "Yuma"}
Dim output = names(0) + ", " + names(1) + ", " + names(2) + ", " +
names(3) + ", " + names(4) + ", " + names(5) + ", " +
names(6)
output += vbCrLf
Dim dat = DateTime.Now
output += String.Format("It is {0:t} on {0:d}. The day of the week is {1}.",
dat, dat.DayOfWeek)
Console.WriteLine(output)
End Sub
End Module
' The example displays the following output:
' Balto, Vanya, Dakota, Samuel, Koani, Yiska, Yuma
' It is 10:29 AM on 1/8/2018. The day of the week is Monday.
Natomiast użycie ciągów interpolowanych w poniższym przykładzie daje znacznie jaśniejszy, bardziej zwięzły kod niż instrukcja łączenia ciągów i wywołanie Format metody w poprzednim przykładzie.
string[] names = { "Balto", "Vanya", "Dakota", "Samuel", "Koani", "Yiska", "Yuma" };
string output = $"{names[0]}, {names[1]}, {names[2]}, {names[3]}, {names[4]}, " +
$"{names[5]}, {names[6]}";
var date = DateTime.Now;
output += $"\nIt is {date:t} on {date:d}. The day of the week is {date.DayOfWeek}.";
Console.WriteLine(output);
// The example displays the following output:
// Balto, Vanya, Dakota, Samuel, Koani, Yiska, Yuma
// It is 10:29 AM on 1/8/2018. The day of the week is Monday.
open System
let names = [| "Balto"; "Vanya"; "Dakota"; "Samuel"; "Koani"; "Yiska"; "Yuma" |]
let output = $"{names[0]}, {names[1]}, {names[2]}, {names[3]}, {names[4]}, {names[5]}, {names[6]}"
let date = DateTime.Now
output + $"\nIt is {date:t} on {date:d}. The day of the week is {date.DayOfWeek}."
|> printfn "%s"
// The example displays the following output:
// Balto, Vanya, Dakota, Samuel, Koani, Yiska, Yuma
// It is 10:29 AM on 1/8/2018. The day of the week is Monday.
Module Example13
Public Sub Main()
Dim names = {"Balto", "Vanya", "Dakota", "Samuel", "Koani", "Yiska", "Yuma"}
Dim output = $"{names(0)}, {names(1)}, {names(2)}, {names(3)}, {names(4)}, " +
$"{names(5)}, {names(6)}"
Dim dat = DateTime.Now
output += $"{vbCrLf}It is {dat:t} on {dat:d}. The day of the week is {dat.DayOfWeek}."
Console.WriteLine(output)
End Sub
End Module
' The example displays the following output:
' Balto, Vanya, Dakota, Samuel, Koani, Yiska, Yuma
' It is 10:29 AM on 1/8/2018. The day of the week is Monday.
Gdzie można znaleźć wstępnie zdefiniowane ciągi formatu?
Dla wszystkich typów całkowitych i zmiennoprzecinkowych zobacz Standardowe ciągi formatu liczbowego i Niestandardowe ciągi formatu liczbowego.
Aby uzyskać informacje o wartościach daty i godziny, zobacz Standardowe ciągi formatu daty i godziny oraz niestandardowe ciągi formatu daty i godziny.
Aby zapoznać się z wartościami wyliczenia, zobacz Ciągi formatu wyliczenia.
Aby uzyskać informacje o TimeSpan wartościach, zobacz Ciągi formatu TimeSpan w warstwie Standardowa i Niestandardowe ciągi formatu TimeSpan.
Aby uzyskać informacje o Guid wartościach, zobacz sekcję Uwagi na stronie referencyjnej Guid.ToString(String) .
Jak mogę kontrolować wyrównanie ciągów wyników, które zastępują elementy formatu?
Ogólna składnia elementu formatu to:
{index[,alignment][: formatString]}
gdzie wyrównanie jest podpisaną liczbą całkowitą, która definiuje szerokość pola. Jeśli ta wartość jest ujemna, tekst w polu jest wyrównany do lewej. Jeśli jest dodatni, tekst jest wyrównany do prawej.
Jak mogę kontrolować liczbę cyfr po separatorze dziesiętny?
Wszystkie standardowe ciągi formatu liczbowego z wyjątkiem "D" (używane tylko z liczbami całkowitymi), "G", "R" i "X" umożliwiają określenie dokładności definiującej liczbę cyfr dziesiętnych w ciągu wynikowym. W poniższym przykładzie użyto standardowych ciągów formatu liczbowego do kontrolowania liczby cyfr dziesiętnych w ciągu wynikowym.
object[] values = { 1603, 1794.68235, 15436.14 };
string result;
foreach (var value in values)
{
result = String.Format("{0,12:C2} {0,12:E3} {0,12:F4} {0,12:N3} {1,12:P2}\n",
Convert.ToDouble(value), Convert.ToDouble(value) / 10000);
Console.WriteLine(result);
}
// The example displays output like the following:
// $1,603.00 1.603E+003 1603.0000 1,603.000 16.03 %
//
// $1,794.68 1.795E+003 1794.6824 1,794.682 17.95 %
//
// $15,436.14 1.544E+004 15436.1400 15,436.140 154.36 %
open System
let values: obj list = [ 1603, 1794.68235, 15436.14 ]
for value in values do
String.Format("{0,12:C2} {0,12:E3} {0,12:F4} {0,12:N3} {1,12:P2}\n", Convert.ToDouble(value), Convert.ToDouble(value) / 10000.)
|> printfn "%s"
// The example displays output like the following:
// $1,603.00 1.603E+003 1603.0000 1,603.000 16.03 %
//
// $1,794.68 1.795E+003 1794.6824 1,794.682 17.95 %
//
// $15,436.14 1.544E+004 15436.1400 15,436.140 154.36 %
Module Example7
Public Sub Main()
Dim values() As Object = {1603, 1794.68235, 15436.14}
Dim result As String
For Each value In values
result = String.Format("{0,12:C2} {0,12:E3} {0,12:F4} {0,12:N3} {1,12:P2}",
value, CDbl(value) / 10000)
Console.WriteLine(result)
Console.WriteLine()
Next
End Sub
End Module
' The example displays the following output:
' $1,603.00 1.603E+003 1603.0000 1,603.000 16.03 %
'
' $1,794.68 1.795E+003 1794.6824 1,794.682 17.95 %
'
' $15,436.14 1.544E+004 15436.1400 15,436.140 154.36 %
Jeśli używasz niestandardowego ciągu formatu liczbowego, użyj specyfikatora formatu "0", aby kontrolować liczbę cyfr dziesiętnych w ciągu wynikowym, jak pokazano w poniższym przykładzie.
decimal value = 16309.5436m;
string result = String.Format("{0,12:#.00000} {0,12:0,000.00} {0,12:000.00#}",
value);
Console.WriteLine(result);
// The example displays the following output:
// 16309.54360 16,309.54 16309.544
let value = 16309.5436m
String.Format("{0,12:#.00000} {0,12:0,000.00} {0,12:000.00#}", value)
|> printfn "%s"
// The example displays the following output:
// 16309.54360 16,309.54 16309.544
Module Example8
Public Sub Main()
Dim value As Decimal = 16309.5436D
Dim result As String = String.Format("{0,12:#.00000} {0,12:0,000.00} {0,12:000.00#}",
value)
Console.WriteLine(result)
End Sub
End Module
' The example displays the following output:
' 16309.54360 16,309.54 16309.544
Jak mogę kontrolować liczbę cyfr całkowitych?
Domyślnie operacje formatowania wyświetlają tylko cyfry niezerowe. Jeśli formatujesz liczby całkowite, możesz użyć specyfikatora dokładności z ciągami formatu standardowego "D" i "X", aby kontrolować liczbę cyfr.
int value = 1326;
string result = String.Format("{0,10:D6} {0,10:X8}", value);
Console.WriteLine(result);
// The example displays the following output:
// 001326 0000052E
open System
let value = 1326
String.Format("{0,10:D6} {0,10:X8}", value)
|> printfn "%s"
// The example displays the following output:
// 001326 0000052E
Module Example10
Public Sub Main()
Dim value As Integer = 1326
Dim result As String = String.Format("{0,10:D6} {0,10:X8}", value)
Console.WriteLine(result)
End Sub
End Module
' The example displays the following output:
' 001326 0000052E
Liczbę całkowitą lub zmiennoprzecinkową można wypełnić zerami wiodącymi, aby wygenerować ciąg wynikowy z określoną liczbą cyfr całkowitych przy użyciu niestandardowego specyfikatora formatu liczbowego "0", jak pokazano w poniższym przykładzie.
int value = 16342;
string result = String.Format("{0,18:00000000} {0,18:00000000.000} {0,18:000,0000,000.0}",
value);
Console.WriteLine(result);
// The example displays the following output:
// 00016342 00016342.000 0,000,016,342.0
open System
let value = 16342
String.Format("{0,18:00000000} {0,18:00000000.000} {0,18:000,0000,000.0}", value)
|> printfn "%s"
// The example displays the following output:
// 00016342 00016342.000 0,000,016,342.0
Module Example9
Public Sub Main()
Dim value As Integer = 16342
Dim result As String = String.Format("{0,18:00000000} {0,18:00000000.000} {0,18:000,0000,000.0}",
value)
Console.WriteLine(result)
End Sub
End Module
' The example displays the following output:
' 00016342 00016342.000 0,000,016,342.0
Ile elementów można uwzględnić na liście formatów?
Nie ma praktycznego limitu. Drugi parametr Format(IFormatProvider, String, Object[]) metody jest oznaczony atrybutem ParamArrayAttribute , który umożliwia dołączenie listy rozdzielanej lub tablicy obiektów jako listy formatów.
Jak mogę uwzględnić nawiasy klamrowe literału ("{" i "}") w ciągu wynikowym?
Jak na przykład zapobiec zgłaszaniu wyjątku FormatException przez następujące wywołanie metody?
result = String.Format("The text has {0} '{' characters and {1} '}' characters.",
nOpen, nClose);
let result =
String.Format("The text has {0} '{' characters and {1} '}' characters.", nOpen, nClose)
result = String.Format("The text has {0} '{' characters and {1} '}' characters.",
nOpen, nClose)
Pojedynczy nawias klamrowy otwierający lub zamykający jest zawsze interpretowany jako początek lub koniec elementu formatu. Aby być interpretowane dosłownie, należy go uniknąć. Nawias klamrowy jest unikany przez dodanie innego nawiasu klamrowego ("{" i "}}", zamiast "{" i "}"), tak jak w poniższym wywołaniu metody:
string result;
int nOpen = 1;
int nClose = 2;
result = String.Format("The text has {0} '{{' characters and {1} '}}' characters.",
nOpen, nClose);
Console.WriteLine(result);
let result =
String.Format("The text has {0} '{{' characters and {1} '}}' characters.", nOpen, nClose)
result = String.Format("The text has {0} '{{' characters and {1} '}}' characters.",
nOpen, nClose)
Jednak nawet nawiasy klamrowe ucieczki są łatwo błędnie interpretowane. Zalecamy uwzględnienie nawiasów klamrowych na liście formatów i użycie elementów formatu w celu wstawienia ich w ciągu wynikowym, jak pokazano w poniższym przykładzie.
string result;
int nOpen = 1;
int nClose = 2;
result = String.Format("The text has {0} '{1}' characters and {2} '{3}' characters.",
nOpen, "{", nClose, "}");
Console.WriteLine(result);
let result =
String.Format("The text has {0} '{1}' characters and {2} '{3}' characters.", nOpen, "{", nClose, "}")
result = String.Format("The text has {0} '{1}' characters and {2} '{3}' characters.",
nOpen, "{", nClose, "}")
Dlaczego moje wywołanie metody String.Format zgłasza wyjątek FormatException?
Najczęstszą przyczyną wyjątku jest to, że indeks elementu formatu nie odpowiada obiektowi na liście formatów. Zazwyczaj oznacza to, że indeksy formatu elementów zostały nieprawidłowo ponumerowane lub nie pamiętasz, aby uwzględnić obiekt na liście formatów. Próba uwzględnienia niezaużytego znaku nawiasu klamrowego po lewej lub prawej stronie zwraca również znak FormatException. Czasami wyjątek jest wynikiem literówki; na przykład typowy błąd polega na błędnym typie "[" (lewy nawias kwadratowy) zamiast "{" (lewy nawias klamrowy).
Jeśli metoda Format(System.IFormatProvider,System.String,System.Object[]) obsługuje tablice parametrów, dlaczego mój kod zgłasza wyjątek podczas korzystania z tablicy?
Na przykład następujący kod zgłasza FormatException wyjątek:
Random rnd = new Random();
int[] numbers = new int[4];
int total = 0;
for (int ctr = 0; ctr <= 2; ctr++)
{
int number = rnd.Next(1001);
numbers[ctr] = number;
total += number;
}
numbers[3] = total;
Console.WriteLine("{0} + {1} + {2} = {3}", numbers);
open System
let rnd = Random()
let mutable total = 0
let numbers = Array.zeroCreate<int> 4
for i = 0 to 2 do
let number = rnd.Next 1001
numbers[i] <- number
total <- total + number
numbers[3] <- total
Console.WriteLine("{0} + {1} + {2} = {3}", numbers)
Imports System.Collections.Generic
Module Example5
Public Sub Main()
Dim rnd As New Random()
Dim numbers(3) As Integer
Dim total As Integer = 0
For ctr = 0 To 2
Dim number As Integer = rnd.Next(1001)
numbers(ctr) = number
total += number
Next
numbers(3) = total
Console.WriteLine("{0} + {1} + {2} = {3}", numbers)
End Sub
End Module
Jest to problem z rozpoznawaniem przeciążenia kompilatora. Ponieważ kompilator nie może przekonwertować tablicy liczb całkowitych na tablicę obiektów, traktuje tablicę całkowitą jako pojedynczy argument, więc wywołuje metodę Format(String, Object) . Wyjątek jest zgłaszany, ponieważ istnieją cztery elementy formatu, ale tylko jeden element na liście formatów.
Ponieważ ani Visual Basic, ani C# nie mogą przekonwertować tablicy całkowitej na tablicę obiektów, przed wywołaniem Format(String, Object[]) metody należy wykonać konwersję samodzielnie. Poniższy przykład zawiera jedną implementację.
Random rnd = new Random();
int[] numbers = new int[4];
int total = 0;
for (int ctr = 0; ctr <= 2; ctr++)
{
int number = rnd.Next(1001);
numbers[ctr] = number;
total += number;
}
numbers[3] = total;
object[] values = new object[numbers.Length];
numbers.CopyTo(values, 0);
Console.WriteLine("{0} + {1} + {2} = {3}", values);
open System
let rnd = Random()
let numbers = Array.zeroCreate<int> 4
let mutable total = 0
for i = 0 to 2 do
let number = rnd.Next 1001
numbers[i] <- number
total <- total + number
numbers[3] <- total
let values = Array.zeroCreate<obj> numbers.Length
numbers.CopyTo(values, 0)
Console.WriteLine("{0} + {1} + {2} = {3}", values)
Imports System.Collections.Generic
Module Example6
Public Sub Main()
Dim rnd As New Random()
Dim numbers(3) As Integer
Dim total As Integer = 0
For ctr = 0 To 2
Dim number As Integer = rnd.Next(1001)
numbers(ctr) = number
total += number
Next
numbers(3) = total
Dim values(numbers.Length - 1) As Object
numbers.CopyTo(values, 0)
Console.WriteLine("{0} + {1} + {2} = {3}", values)
End Sub
End Module