Nuta
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Język C# ma wiele wbudowanych typów odwołań. Mają słowa kluczowe lub operatory, które są synonimami typu w bibliotece .NET.
Typ obiektu
Typ object jest aliasem dla System.Object platformy .NET. W ujednoliconym systemie języka C#, wszystkie typy, wstępnie zdefiniowane i zdefiniowane przez użytkownika, typy referencyjne i typy wartości dziedziczą bezpośrednio lub pośrednio z System.Objectklasy . Wartości dowolnego typu (z wyjątkiem ref struct, zobacz struktura ref) można przypisać do zmiennych typu object. Dowolną object zmienną można przypisać do jej wartości domyślnej przy użyciu literału null. Gdy zmienna typu wartości jest konwertowana na obiekt, jest ona w polu. Gdy zmienna typu object jest konwertowana na typ wartości, jest rozpakowana. Aby uzyskać więcej informacji, zobacz Boxing and Unboxing (Boxing and Unboxing).
Typ ciągu
Typ string reprezentuje sekwencję zero lub więcej znaków Unicode.
string jest aliasem dla System.String platformy .NET.
Chociaż string jest typem odwołania, operatory == równości i != są definiowane w celu porównania wartości string obiektów, a nie odwołań. Równość oparta na wartości sprawia, że testowanie równości ciągów jest bardziej intuicyjne. Na przykład:
string a = "hello";
string b = "h";
// Append to contents of 'b'
b += "ello";
Console.WriteLine(a == b);
Console.WriteLine(object.ReferenceEquals(a, b));
W poprzednim przykładzie jest wyświetlana wartość "True", a następnie "False", ponieważ zawartość ciągów jest równoważna, ale ab nie odwołuje się do tego samego wystąpienia ciągu.
string a = "good " + "morning";
Powyższy kod tworzy obiekt ciągu zawierający "dzień dobry".
Ciągi są niezmienne — nie można zmienić zawartości obiektu ciągu po utworzeniu obiektu. Na przykład podczas pisania tego kodu kompilator faktycznie tworzy nowy obiekt ciągu do przechowywania nowej sekwencji znaków, a nowy obiekt jest przypisany do b. Pamięć przydzielona b do (gdy zawierała ciąg "h"), kwalifikuje się do odzyskiwania pamięci.
string b = "h";
b += "ello";
Operator [] może służyć do odczytu dostępu do poszczególnych znaków ciągu. Prawidłowe wartości indeksu zaczynają się od 0 i muszą być mniejsze niż długość ciągu:
string str = "test";
char x = str[2]; // x = 's';
W podobny sposób [] operator może być również używany do iterowania poszczególnych znaków w ciągu:
string str = "test";
for (int i = 0; i < str.Length; i++)
{
Console.Write(str[i] + " ");
}
// Output: t e s t
Literały ciągu
Literały ciągu są typu string i mogą być zapisywane w trzech formach, nieprzetworzonych, cytowanych i dosłownych.
Nieprzetworzone literały ciągu zawierają dowolny tekst bez konieczności sekwencji ucieczki. Nieprzetworzone literały ciągu mogą zawierać białe znaki i nowe wiersze, osadzone cudzysłowy i inne znaki specjalne. Nieprzetworzone literały ciągu są ujęte w co najmniej trzy podwójne cudzysłowy (""):
"""
This is a multi-line
string literal with the second line indented.
"""
Można nawet dołączyć sekwencję trzech (lub więcej) znaków podwójnego cudzysłowu. Jeśli tekst wymaga osadzonej sekwencji cudzysłowów, zaczynasz i kończysz nieprzetworzony literał ciągu z większą częścią cudzysłowu, zgodnie z potrzebami:
"""""
This raw string literal has four """", count them: """" four!
embedded quote characters in a sequence. That's why it starts and ends
with five double quotes.
You could extend this example with as many embedded quotes as needed for your text.
"""""
Nieprzetworzone literały ciągu zwykle mają sekwencje cudzysłowu początkowego i końcowego w osobnych wierszach od osadzonego tekstu. Wielowierszowe literały ciągów nieprzetworzonych obsługują ciągi, które same są ciągami cytowania:
var message = """
"This is a very important message."
""";
Console.WriteLine(message);
// output: "This is a very important message."
Gdy cudzysłowy początkowe i końcowe znajdują się w osobnych wierszach, nowe linie po cudzysłowie otwierającym i poprzedzającym cudzysłów końcowych nie są uwzględniane w końcowej zawartości. Sekwencja cudzysłowu zamykającego określa lewą kolumnę literału ciągu. Możesz wciąć nieprzetworzony literał ciągu, aby był zgodny z ogólnym formatem kodu:
var message = """
"This is a very important message."
""";
Console.WriteLine(message);
// output: "This is a very important message."
// The leftmost whitespace is not part of the raw string literal
Kolumny po prawej stronie sekwencji cudzysłowu końcowego są zachowywane. To zachowanie umożliwia nieprzetworzone ciągi dla formatów danych, takich jak JSON, YAML lub XML, jak pokazano w poniższym przykładzie:
var json= """
{
"prop": 0
}
""";
Wskazówka
Program Visual Studio i zestaw deweloperski języka C# zapewniają pewne wyróżnianie poprawności i składni, gdy nieprzetworzone literały ciągu zawierają dane JSON lub wyrażenia regularne.
Narzędzia analizują tekst. Jeśli narzędzia mają pewność, że tekst reprezentuje kod JSON lub wyrażenie regularne, edytor udostępnia kolorowanie składni.
Możesz ulepszyć to środowisko, dodając komentarz nad deklaracją wskazującą format:
-
// lang=jsonwskazuje nieprzetworzone literał ciągu reprezentuje dane JSON. -
// lang=regexwskazuje nieprzetworzone literał ciągu reprezentuje wyrażenie regularne.
Gdy literał nieprzetworzonego ciągu jest używany jako argument, w którym parametr używa parametru System.Diagnostics.CodeAnalysis.StringSyntaxAttribute , aby wskazać format, te narzędzia weryfikują pierwotny literał ciągu dla niektórych typów formatów. Obsługiwane są zarówno pliki JSON, jak i regex.
W przypadku niektórych formatów komentarz lub atrybut włącza sugestie dotyczące kodu oferują poprawki literałów ciągu na podstawie formatu.
Kompilator zgłasza błąd, jeśli którykolwiek z wierszy tekstu rozciąga się po lewej stronie sekwencji cudzysłowu zamykającego. Sekwencje cudzysłowu otwierającego i zamykającego mogą znajdować się w tym samym wierszu, co oznacza, że literał ciągu nie rozpoczyna się ani kończy znakiem cudzysłowu:
var shortText = """He said "hello!" this morning.""";
Możesz połączyć nieprzetworzone literały ciągu z interpolacją ciągów, aby uwzględnić znaki cudzysłowu i nawiasy klamrowe w ciągu wyjściowym.
Literały ciągów cytowanych są ujęte w znaki podwójnego cudzysłowu ("):
"good morning" // a string literal
Literały ciągu mogą zawierać dowolny literał znaku. Sekwencje ucieczki są uwzględniane. W poniższym przykładzie użyto sekwencji \\ ucieczki ukośnika odwrotnego, \u0066 litery f i \n nowego wiersza.
string a = "\\\u0066\n F";
Console.WriteLine(a);
// Output:
// \f
// F
Uwaga
Kod \udddd ucieczki (gdzie dddd jest liczbą czterocyfrową) reprezentuje znak Unicode U+dddd. Rozpoznano również osiem cyfrowych kodów ucieczki Unicode: \Udddddddd.
Literały ciągu dosłownego zaczynają się od @ i są również ujęte w znaki podwójnego cudzysłowu. Na przykład:
@"good morning" // a string literal
Zaletą ciągów dosłownych jest to, że sekwencje ucieczki nie są przetwarzane, co ułatwia pisanie. Na przykład następujący tekst pasuje do w pełni kwalifikowanej nazwy pliku systemu Windows:
@"c:\Docs\Source\a.txt" // rather than "c:\\Docs\\Source\\a.txt"
Aby uwzględnić podwójny cudzysłów w ciągu @-quoted, podwaja go:
@"""Ahoy!"" cried the captain." // "Ahoy!" cried the captain.
Literały ciągu UTF-8
Ciągi na platformie .NET są przechowywane przy użyciu kodowania UTF-16. UTF-8 jest standardem dla protokołów sieci Web i innych ważnych bibliotek. Sufiks można dodać u8 do literału ciągu, aby określić kodowanie UTF-8. Literały UTF-8 są przechowywane jako ReadOnlySpan<byte> obiekty. Naturalnym typem literału ciągu UTF-8 jest ReadOnlySpan<byte>. Użycie literału ciągu UTF-8 tworzy bardziej wyraźną deklarację niż deklarowanie równoważnego System.ReadOnlySpan<T>, jak pokazano w poniższym kodzie:
ReadOnlySpan<byte> AuthWithTrailingSpace = new byte[] { 0x41, 0x55, 0x54, 0x48, 0x20 };
ReadOnlySpan<byte> AuthStringLiteral = "AUTH "u8;
Aby zapisać literał ciągu UTF-8 jako tablicę, należy użyć polecenia ReadOnlySpan<T>.ToArray() , aby skopiować bajty zawierające literał do tablicy modyfikowalnej:
byte[] AuthStringLiteral = "AUTH "u8.ToArray();
Literały ciągu UTF-8 nie są stałymi czasu kompilacji; są stałymi środowiska uruchomieniowego. W związku z tym nie można ich użyć jako wartości domyślnej dla opcjonalnego parametru. Literały ciągów UTF-8 nie mogą być łączone z interpolacją ciągów. Nie można użyć tokenu $ i sufiksu w tym samym wyrażeniu u8 ciągu.
Typ delegata
Deklaracja typu delegata jest podobna do podpisu metody. Ma wartość zwracaną i dowolną liczbę parametrów dowolnego typu:
public delegate void MessageDelegate(string message);
public delegate int AnotherDelegate(MyType m, long num);
Na platformie .NET System.Action i System.Func typy zawierają definicje ogólne dla wielu typowych delegatów. Prawdopodobnie nie trzeba definiować nowych niestandardowych typów delegatów. Zamiast tego można tworzyć wystąpienia podanych typów ogólnych.
A delegate to wbudowany typ odwołania, który może służyć do hermetyzacji nazwanej lub anonimowej metody. Delegaty są podobne do wskaźników funkcji w języku C++; jednak delegaty są bezpieczne i bezpieczne. Aby uzyskać informacje o aplikacjach delegatów, zobacz Delegaty i Delegaty ogólne. Delegaty są podstawą dla zdarzeń. Pełnomocnik można utworzyć wystąpienie, kojarząc go z nazwaną lub anonimową metodą.
Delegat musi zostać utworzone za pomocą metody lub wyrażenia lambda, które ma zgodny typ zwracany i parametry wejściowe. Aby uzyskać więcej informacji na temat stopnia wariancji dozwolonego w podpisie metody, zobacz Variance in Delegates (Wariancja w delegatach). Aby używać z metodami anonimowymi, delegat i kod, który ma być skojarzony z nim, są deklarowane razem.
Delegowanie kombinacji lub usuwania kończy się niepowodzeniem z wyjątkiem środowiska uruchomieniowego, gdy typy delegatów biorące udział w czasie wykonywania różnią się z powodu konwersji wariantu. W poniższym przykładzie pokazano sytuację, która kończy się niepowodzeniem:
Action<string> stringAction = str => {};
Action<object> objectAction = obj => {};
// Valid due to implicit reference conversion of
// objectAction to Action<string>, but might fail
// at run time.
Action<string> combination = stringAction + objectAction;
Delegata można utworzyć z poprawnym typem środowiska uruchomieniowego, tworząc nowy obiekt delegata. W poniższym przykładzie pokazano, jak można zastosować to obejście do poprzedniego przykładu.
Action<string> stringAction = str => {};
Action<object> objectAction = obj => {};
// Creates a new delegate instance with a runtime type of Action<string>.
Action<string> wrappedObjectAction = new Action<string>(objectAction);
// The two Action<string> delegate instances can now be combined.
Action<string> combination = stringAction + wrappedObjectAction;
Można zadeklarować wskaźniki funkcji, które używają podobnej składni. Wskaźnik funkcji używa calli instrukcji zamiast tworzenia wystąpienia typu delegata i wywoływania metody wirtualnej Invoke .
Typ dynamiczny
Typ dynamic wskazuje, że użycie zmiennej i odwołań do jej elementów członkowskich pomija sprawdzanie typu kompilatora czasu. Zamiast tego te operacje są rozwiązywane w czasie wykonywania.
dynamic Typ upraszcza dostęp do interfejsów API MODELU COM, takich jak interfejsy API usługi Office Automation, do dynamicznych interfejsów API, takich jak biblioteki IronPython, oraz do modelu DOM (DOCUMENT Object Model).
Typ dynamic zachowuje się jak typ object w większości okoliczności. W szczególności dowolne wyrażenie inne niż null można przekonwertować na dynamic typ. Typ dynamic różni się od object tych operacji, które zawierają wyrażenia typu dynamic , nie są rozpoznawane ani typ sprawdzany przez kompilator. Kompilator pakuje razem informacje o operacji, a informacje te są później używane do oceny operacji w czasie wykonywania. W ramach procesu zmienne typu dynamic są kompilowane w zmienne typu object. W związku z tym typ dynamic istnieje tylko w czasie kompilacji, a nie w czasie wykonywania.
Poniższy przykład kontrastuje zmienną typu dynamic ze zmienną typu object. Aby sprawdzić typ każdej zmiennej w czasie kompilacji, umieść wskaźnik dyn myszy na lub obj w instrukcjach WriteLine . Skopiuj następujący kod do edytora, w którym jest dostępna funkcja IntelliSense. Funkcja IntelliSense wyświetla dynamiczne obiekty dyn idla elementu obj.
class Program
{
static void Main(string[] args)
{
dynamic dyn = 1;
object obj = 1;
// Rest the mouse pointer over dyn and obj to see their
// types at compile time.
System.Console.WriteLine(dyn.GetType());
System.Console.WriteLine(obj.GetType());
}
}
Instrukcje WriteLine wyświetlają typy dyn czasu wykonywania i obj. W tym momencie oba mają ten sam typ, liczbę całkowitą. Zostaną wyświetlone następujące dane wyjściowe:
System.Int32
System.Int32
Aby zobaczyć różnicę między dyn i obj w czasie kompilacji, dodaj następujące dwa wiersze między deklaracjami a WriteLine instrukcjami w poprzednim przykładzie.
dyn = dyn + 3;
obj = obj + 3;
Zgłaszany jest błąd kompilatora dla próby dodania liczby całkowitej i obiektu w wyrażeniu obj + 3. Jednak dla elementu dyn + 3nie zgłoszono żadnego błędu . Wyrażenie, które zawiera dyn , nie jest sprawdzane w czasie kompilacji, ponieważ typ dyn to dynamic.
W poniższym przykładzie użyto dynamic kilku deklaracji. Metoda Main kontrastuje również sprawdzanie typu czasu kompilacji przy użyciu sprawdzania typów czasu wykonywania.
using System;
namespace DynamicExamples
{
class Program
{
static void Main(string[] args)
{
ExampleClass ec = new ExampleClass();
Console.WriteLine(ec.ExampleMethod(10));
Console.WriteLine(ec.ExampleMethod("value"));
// The following line causes a compiler error because ExampleMethod
// takes only one argument.
//Console.WriteLine(ec.ExampleMethod(10, 4));
dynamic dynamic_ec = new ExampleClass();
Console.WriteLine(dynamic_ec.ExampleMethod(10));
// Because dynamic_ec is dynamic, the following call to ExampleMethod
// with two arguments does not produce an error at compile time.
// However, it does cause a run-time error.
//Console.WriteLine(dynamic_ec.ExampleMethod(10, 4));
}
}
class ExampleClass
{
static dynamic _field;
dynamic Prop { get; set; }
public dynamic ExampleMethod(dynamic d)
{
dynamic local = "Local variable";
int two = 2;
if (d is int)
{
return local;
}
else
{
return two;
}
}
}
}
// Results:
// Local variable
// 2
// Local variable
specyfikacja języka C#
Aby uzyskać więcej informacji, zobacz następujące sekcje specyfikacji języka C#:
- §8.2.3 Typ obiektu
- §8.2.4 Typ dynamiczny
- §8.2.5 Typ ciągu
- §8.2.8 Typy delegatów
- Nieprzetworzone literały ciągu
- Literały ciągu UTF-8
Zobacz też
- Słowa kluczowe języka C#
- Wydarzenia
- Używanie typu dynamicznego
- Najlepsze rozwiązania dotyczące używania ciągów
- Tworzenie nowych ciągów
- Operatory testowania typów i rzutów
- Jak bezpiecznie rzutować przy użyciu dopasowywania wzorców i operatorów i
- Przewodnik: tworzenie i używanie obiektów dynamicznych
- System.Object
- System.String
- System.Dynamic.DynamicObject