Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
C# имеет множество встроенных ссылочных типов. Эти типы включают ключевые слова или операторы, которые являются синонимами для типа в библиотеке .NET.
Справочные документы на языке C#, выпущенные последней версией языка C#. Она также содержит начальную документацию по функциям в общедоступных предварительных версиях для предстоящего языкового выпуска.
Документация определяет любую функцию, впервые представленную в последних трех версиях языка или в текущих общедоступных предварительных версиях.
Подсказка
Чтобы узнать, когда функция впервые появилась в C#, ознакомьтесь со статьей по журналу версий языка C#.
Тип object
Тип object является псевдонимом System.Object в .NET. В унифицированной системе типов C# все типы, стандартные и определяемые пользователем, ссылочные типы и типы значений напрямую или косвенно наследуются из System.Object. Назначение значений любого типа (за исключением ref structссылок) переменным типаobject. Литерал null можно назначить любой object переменной в качестве значения по умолчанию. При преобразовании переменной objectтипа значения в поле отображается значение. При преобразовании переменной типа object в тип значения значение будет отключено. Дополнительные сведения см. в разделе Упаковка-преобразование и распаковка-преобразование.
Тип string
Тип string представляет последовательность, состоящую из нуля или более символов в кодировке Юникод. В .NET string используется псевдоним System.String.
Хотя string это ссылочный тип, операторы == равенства и != сравнение значений string объектов, а не ссылок. Равенство на основе значений делает тестирование на равенство строк более интуитивно понятным. Например:
string a = "hello";
string b = "h";
// Append to contents of 'b'.
b += "ello";
Console.WriteLine(a == b);
Console.WriteLine(object.ReferenceEquals(a, b));
В предыдущем примере отображается значение True, а затем "False", так как содержимое строк эквивалентно, но ab не ссылайтесь на один и тот же экземпляр строки.
Оператор + объединяет строки:
string a = "good " + "morning";
Предыдущий код создает строковый объект, содержащий "доброе утро".
Строки неизменяемы . Вы не можете изменить содержимое строкового объекта после его создания. Например, при написании этого кода компилятор фактически создает новый строковый объект для хранения новой последовательности символов и назначает новый объект b. Память, выделенная b для (если она содержала строку h), затем может быть настроена для сборки мусора.
string b = "h";
b += "ello";
Оператор можно использовать []для доступа к отдельным символам строки. Допустимые значения индекса начинаются с 0 и должны быть меньше, чем длина строки:
string str = "test";
char x = str[2]; // x = 's';
Аналогичным образом можно использовать [] оператор для итерации каждого символа в строке:
string str = "test";
for (int i = 0; i < str.Length; i++)
{
Console.Write(str[i] + " ");
}
// Output: t e s t
Строковые литералы
Строковые литералы имеют тип string и имеют три формы: необработанные, кавычки и подробные сведения.
Необработанные строковые литералы содержат произвольный текст, не требуя escape-последовательностей. Необработанные строковые литералы могут включать пробелы и новые строки, внедренные кавычки и другие специальные символы. Необработанные строковые литералы заключены как минимум в три двойных кавычки (""):
"""
This is a multi-line
string literal with the second line indented.
"""
Можно даже включить последовательность из трех (или более) символов двойной кавычки. Если тексту требуется внедренная последовательность кавычки, вы начинаете и заканчиваете необработанный строковый литерал с дополнительными кавычками, по мере необходимости:
"""""
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.
"""""
Необработанные строковые литералы обычно имеют начальные и конечные последовательности кавычки в отдельных строках из внедренного текста. Многостроальные необработанные строковые литералы поддерживают строки, которые сами являются строками с кавычками:
var message = """
"This is a very important message."
""";
Console.WriteLine(message);
// output: "This is a very important message."
Когда начальные и конечные кавычки находятся в отдельных строках, новые строки после открывающей кавычки и предыдущие конечные кавычки не включаются в окончательное содержимое. Закрывающая последовательность кавычки определяет самый левый столбец для строкового литерала. Вы можете отступить необработанный строковый литерал, чтобы соответствовать общему формату кода:
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
Столбцы справа от конечной последовательности кавычки сохраняются. Это поведение позволяет необработанным строкам для таких форматов данных, как JSON, YAML или XML, как показано в следующем примере:
var json= """
{
"prop": 0
}
""";
Подсказка
Visual Studio и комплект средств разработки C# предоставляют некоторые проверки и синтаксис выделения, когда необработанные строковые литералы содержат данные JSON или регулярные выражения.
Средства синтаксического анализа текста. Если средства уверены, что текст представляет JSON или регулярное выражение, редактор предоставляет цвет синтаксиса.
Вы можете улучшить этот интерфейс, добавив комментарий над объявлением, указывающим формат:
-
// lang=jsonуказывает, что необработанный строковый литерал представляет данные JSON. -
// lang=regexуказывает, что необработанный строковый литерал представляет регулярное выражение.
Если необработанный строковый литерал используется в качестве аргумента, в котором параметр использует System.Diagnostics.CodeAnalysis.StringSyntaxAttribute формат, эти средства проверяют необработанный строковый литерал для некоторых типов форматов. Поддерживаются как JSON, так и regex.
В некоторых форматах комментарий или атрибут позволяют предлагать предложения кода для строковых литералов в зависимости от формата.
Компилятор возвращает ошибку, если любая из текстовых строк распространяется слева от закрывающей кавычки. Открывающие и закрывающие последовательности кавычки могут находиться в одной строке, предоставляя строковый литерал не начинается и не заканчивается символом кавычки:
var shortText = """He said "hello!" this morning.""";
Необработанные строковые литералы можно объединить с интерполяцией строк, чтобы включить символы кавычки и фигурные скобки в выходную строку.
Строковые литералы в кавычках заключаются в двойные кавычки ("):
"good morning" // a string literal
Строковые литералы могут содержать любые символьные литералы. Escape-последовательности включены. В следующем примере escape-последовательность \\ используется для получения обратной косой черты, \u0066 — для получения буквы f, и \n — для получения новой строки.
string a = "\\\u0066\n F";
Console.WriteLine(a);
// Output:
// \f
// F
Примечание.
Escape-код \udddd (где dddd состоит из четырех цифр) представляет символ Юникода U+dddd. Также распознаются восьмизначные escape-коды Юникода: \Udddddddd.
Буквальные строковые литералы начинаются с @ и также заключаются в двойные кавычки. Например:
@"good morning" // a string literal
Преимущество подробных строк заключается в том, что escape-последовательности не обрабатываются, что упрощает их запись. Например, следующий текст соответствует полному имени файла Windows:
@"c:\Docs\Source\a.txt" // rather than "c:\\Docs\\Source\\a.txt"
Чтобы включить двойную кавычку в строку с кавычками, дважды выполните следующие действия:
@"""Ahoy!"" cried the captain." // "Ahoy!" cried the captain.
Строковые литералы UTF-8
.NET сохраняет строки с помощью кодировки UTF-16. UTF-8 — это стандарт для веб-протоколов и других важных библиотек. Суффикс можно добавить в u8 строковый литерал, чтобы указать кодировку UTF-8. Компилятор сохраняет литералы UTF-8 в виде ReadOnlySpan<byte> объектов. При использовании строкового литерала UTF-8 создается более четкое объявление, чем объявление эквивалента System.ReadOnlySpan<T>, как показано в следующем коде:
ReadOnlySpan<byte> AuthWithTrailingSpace = new byte[] { 0x41, 0x55, 0x54, 0x48, 0x20 };
ReadOnlySpan<byte> AuthStringLiteral = "AUTH "u8;
Чтобы сохранить строковый литерал UTF-8 в виде массива, используйте ReadOnlySpan<T>.ToArray() для копирования байтов, содержащих литерал в изменяемый массив:
byte[] AuthStringLiteral = "AUTH "u8.ToArray();
Строковые литералы UTF-8 не являются константами времени компиляции; они константы среды выполнения. Поэтому их нельзя использовать в качестве значения по умолчанию для необязательного параметра. Не удается объединить строковые литералы UTF-8 с интерполяцией строк. Маркер и $ суффикс нельзя использовать u8 в том же строковом выражении.
Тип delegate
Объявление типа делегата аналогично сигнатуре метода. Оно имеет возвращаемое значение и любое число параметров любого типа:
public delegate void MessageDelegate(string message);
public delegate int AnotherDelegate(MyType m, long num);
В .NET типы System.Action и System.Func предоставляют общие определения для многих распространенных делегатов. Скорее всего, не нужно определять новые пользовательские типы делегата. Вместо этого можно создать экземпляры предоставленных универсальных типов.
Это delegate встроенный ссылочный тип, который можно использовать для инкапсулирования именованного или анонимного метода. Делегаты аналогичны используемым в языке C++ указателям функций, но являются типобезопасными и безопасными. Сведения о применении делегатов см. в разделах Делегаты и Универсальные делегаты. Делегаты являются основой событий. Создайте экземпляр делегата, связав его с именованным или анонимным методом.
Необходимо создать экземпляр делегата с помощью метода или лямбда-выражения, имеющего совместимый тип возврата и входные параметры. Дополнительные сведения о допустимой степени вариации сигнатур методов см. в разделе Вариативность в делегатах. Для использования с анонимными методами объявите делегат и код, которые будут связаны с ним вместе.
Сочетание делегатов или удаление завершается ошибкой при исключении среды выполнения, если типы делегатов, участвующие во время выполнения, отличаются из-за преобразования вариантов. В следующем примере показана ситуация, которая завершается ошибкой:
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;
Вы можете создать делегат с правильным типом среды выполнения, создав новый объект делегата. В следующем примере показано, как это решение может быть применено к предыдущему примеру.
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;
Вы можете объявить указатели функций, которые используют аналогичный синтаксис. Указатель функции использует инструкцию calli вместо создания экземпляра типа делегата и вызова виртуального метода Invoke.
Тип dynamic
Тип dynamic указывает, что переменная и ссылки на ее члены обходят проверку типа во время компиляции. Такие операции разрешаются во время выполнения. Тип dynamic упрощает доступ к API COM, таким как API автоматизации Office, к динамическим API, таким как библиотеки IronPython, и к HTML-модели DOM.
Тип dynamic в большинстве случаев ведет себя как тип object. В частности, можно преобразовать любое выражение, отличное от NULL, в тип dynamic. Тип dynamic отличается от object того, что компилятор не разрешает или операции проверки типа, содержащие выражения типа dynamic. Компилятор объединяет сведения об операции, которые впоследствии будут использоваться для оценки этой операции во время выполнения. В рамках этого процесса переменные типа dynamic компилируются в переменные типа object. Таким образом, тип dynamic существует только во время компиляции, но не во время выполнения.
В следующем примере переменная типа dynamic контрастирует с переменной типа object. Чтобы проверить тип каждой переменной во время компиляции, наведите указатель мыши на dyn или obj в операторах WriteLine. Скопируйте следующий код в редактор, где доступен IntelliSense. IntelliSense отображает dynamic для dyn и object для 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());
}
}
Операторы WriteLine отображают типы времени выполнения dyn и obj. На этом этапе оба имеют один и тот же тип — целое число. Выводятся следующие результаты:
System.Int32
System.Int32
Чтобы увидеть разницу между dyn и obj во время компиляции, добавьте между объявлениями и операторами WriteLine в предыдущем примере следующие две строки:
dyn = dyn + 3;
obj = obj + 3;
При попытке добавления целого числа и объекта в выражение obj + 3 выдается ошибка компилятора. При этом для dyn + 3 ошибка не возникает. Выражение, содержащееся dyn , не проверяется во время компиляции, так как тип dyn имеет значение dynamic.
В следующем примере dynamic используется в нескольких объявлениях. Метод Main также противопоставляет проверку типов во время компиляции.
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
Спецификация языка C#
Дополнительные сведения см. в следующих разделах статьи Спецификация языка C#:
- §8.2.3 Тип объекта
- §8.2.4 Динамический тип
- §8.2.5 Тип строки
- Типы делегатов §8.2.8
- Необработанные строковые литералы
- Строковые литералы UTF-8
См. также
- Ключевые слова в C#
- События
- Использование типа dynamic
- Рекомендации по использованию строк
- Создание строк
- Операторы приведения и тестирования типов
- Практическое руководство. Безопасное приведение с помощью сопоставления шаблонов, а также операторов is и as
- Пошаговое руководство. Создание и использование динамических объектов (C# и Visual Basic)
- System.Object
- System.String
- System.Dynamic.DynamicObject