Класс Object

В C# предусмотрен специальный класс object, который неявно считается базовым классом для всех остальных классов и типов, включая и типы значений. Иными словами, все остальные типы являются производными от object. Это, в частности, означает, что переменная ссылочного типа object может ссылаться на объект любого другого типа. Кроме того, переменная типа object может ссылаться на любой массив, поскольку в C# массивы реализуются как объекты. Формально имя object считается в C# еще одним обозначением класса System.Object, входящего в библиотеку классов для среды .NET Framework.
Практическое значение этого в том, что помимо методов и свойств, которые вы определяете, также появляется доступ к множеству общедоступных и защищенных методов-членов, которые определены в классе Object. Эти методы присутствуют во всех определяемых классах.
Методы System.Object
Ниже перечислены все методы данного класса:
ToString()
Метод ToString() возвращает символьную строку, содержащую описание того объекта, для которого он вызывается. Кроме того, метод ToString() автоматически вызывается при выводе содержимого объекта с помощью метода WriteLine(). Этот метод переопределяется во многих классах, что позволяет приспосабливать описание к конкретным типам объектов, создаваемых в этих классах.
Применяйте этот метод, когда нужно получить представление о содержимом объекта — возможно, в целях отладки. Он предлагает очень ограниченные средства форматирования данных. Например, даты в принципе могут быть отображены в огромном разнообразии форматов, но DateTime.ToString() не оставляет никакого выбора в этом отношении. Если нужно более сложное строковое представление, которое, например, принимает во внимание установленные предпочтения или местные стандарты, то понадобится реализовать интерфейс IFormattable.
GetHashCode()
Этот метод используется, когда объект помещается в структуру данных, известную как карта (map), которая также называется хеш-таблицей или словарем. Применяется классами, которые манипулируют этими структурами, чтобы определить, куда именно в структуру должен быть помещен объект. Если вы намерены использовать свой класс как ключ словаря, то должны переопределить GetHashCode(). Существуют достаточно строгие требования относительно того, как нужно реализовывать перегрузку.
Хеш-код можно использовать в любом алгоритме, где хеширование применяется в качестве средства доступа к хранимым объектам. Следует, однако, иметь в виду, что стандартная реализация метода GetHashCode() не пригодна на все случаи применения.
Equals() и ReferenceEquals()
По умолчанию метод Equals (object) определяет, ссылается ли вызывающий объект на тот же самый объект, что и объект, указываемый в качестве аргумента этого метода, т.е. он определяет, являются ли обе ссылки одинаковыми. Метод Equals (object) возвращает логическое значение true, если сравниваемые объекты одинаковы, в противном случае — логическое значение false. Он может быть также переопределен в создаваемых классах. Это позволяет выяснить, что же означает равенство объектов для создаваемого класса. Например, метод Equals (object) можно определить таким образом, чтобы в нем сравнивалось содержимое двух объектов.
Как несложно догадаться, учитывая существование трех различных методов сравнения объектов, среда .NET использует довольно сложную схему определения эквивалентности объектов. Следует учитывать и использовать тонкие различия между этими тремя методами и операцией сравнения ==. Кроме того, также существуют ограничения, регламентирующие, как следует переопределять виртуальную версию Equals() с одним параметром, если вы решитесь на это — поскольку некоторые базовые классы из пространства имен System.Collections вызывают этот метод и ожидают от него определенного поведения.
Finalize()
Назначение этого метода в C# примерно соответствует деструкторам С++, и он вызывается при сборке мусора для очистки ресурсов, занятых ссылочным объектом. Реализация Finalize() из Object на самом деле ничего не делает и игнорируется сборщиком мусора. Обычно переопределять Finalize() необходимо, если объект владеет неуправляемыми ресурсами, которые нужно освободить при его уничтожении. Сборщик мусора не может сделать это напрямую, потому что он знает только об управляемых ресурсах, поэтому полагается на финализацию, определенную вами.
GetType()
Этот метод возвращает экземпляр класса, унаследованный от System.Type. Этот объект может предоставить большой объем информации о классе, членом которого является ваш объект, включая базовый тип, методы, свойства и т.п. System.Type также представляет собой стартовую точку технологии рефлексии .NET.
Clone()
Этот метод создает копию объекта и возвращает ссылку на эту копию (а в случае типа значения — ссылку на упаковку). Отметим, что при этом выполняется неглубокое копирование, т.е. копируются все типы значений в классе. Если же класс включает в себя члены ссылочных типов, то копируются только ссылки, а не объекты, на которые они указывают. Этот метод является защищенным, а потому не может вызываться для копирования внешних объектов. К тому же он не виртуальный, а потому переопределять его реализацию нельзя.
Давайте рассмотрим применение некоторых из этих методов на конкретном примере:
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ConsoleApplication1 < class Program < static void Main(string[] args) < var m = Environment.Version; Console.WriteLine("Тип m: "+m.GetType()); string s = m.ToString(); Console.WriteLine("Моя версия .NET Framework: " + s); Version v = (Version)m.Clone(); Console.WriteLine("Значение переменной v: "+v); Console.ReadLine(); >> >
Пацей 3 сем / Лабы / 2_ОсновыNET_Массивы_кортежи_строки
№ 2 Основы CLR и .NET. Типы. Массивы, кортежи и строки Задание 1) Типы a. Определите переменные всех возможных примитивных типов С# и проинициализируйте их. b. Выполните 5 операций явного и 5 неявного приведения. c. Выполните упаковку и распаковку значимых типов. d. Продемонстрируйте работу с неявно типизированной переменной. e. Продемонстрируйте пример работы с Nullable переменной. 2) Строки a. Объявите строковые литералы. Сравните их. b. Создайте три строки на основе String. Выполните: сцепление, копирование, выделение подстроки, разделение строки на слова, вставки подстроки в заданную позицию, удаление заданной подстроки. c. Создайте пустую и null строку. Продемонстрируйте что можно выполнить с такими строками d. Создайте строку на основе StringBuilder. Удалите определенные позиции и добавьте новые символы в начало и конец строки. 3) Массивы a. Создайте целый двумерный массив и выведите его на консоль в отформатированном виде (матрица). b. Создайте одномерный массив строк. Выведите на консоль его содержимое, длину массива. Поменяйте произвольный элемент (пользователь определяет позицию и значение). c. Создайте ступечатый (не выровненный) массив вещественных чисел с 3-мя строками, в каждой из которых 2, 3 и 4 столбцов соответственно. Значения массива введите с консоли. d. Создайте неявно типизированные переменные для хранения массива и строки. 4) Кортежи a. Задайте кортеж из 5 элементов с типами int, string, char, string, ulong. b. Сделайте именование его элементов. c. Выведите кортеж на консоль целиком и выборочно (1, 3, 4 элементы) d. Выполните распаковку кортежа в переменные. e. Сравните два кортежа. 5) Создайте локальную функцию в main и вызовите ее. Формальные параметры функции – массив целых и строка. Функция должна вернуть кортеж, содержащий: максимальный и минимальный элементы массива, сумму элементов массива и первую букву строки . 6) Загрузите проект в свой репозиторий на GitHub. 7) Подготовить ответы на все вопросы.
Вопросы 1. Что такое .Net Framework и из чего он состоит? 2. Поясните, что такое CLR-среда. 3. Что такое FCL? 4. Какая наименьшая исполнимая единица в .NET? 5. Что такое IL? 6. Пояснить работу JIT-компилятора? 7. Что такое CTS (Common Type System)? 8. Какие аспекты поведения определяет тип System.Object? 9. Что находится в MSCorLib dll? 10. Что такое частные и общие сборки? 11. Что такое assembly manifest? 12. Что такое GAC? 13. Чем managed code отличается от unmanaged code 14. Как и для чего определен метод Main? 15. Варианты использования директивы using( using Directive ) в C#. 16. Как связаны между собой сборки и пространства имен? 17. Что такое примитивные типы данных? Перечислите их. 18. Что такое ссылочные типы? Какие типы относятся к ним? 19. Какие типы относятся к типам-значениям? 20. В чем отличие между ссылочными и значимыми типами данных? 21. Что такое упаковка и распаковка значимых типов? 22. Для чего используется тип dynamic? 23. Что такое неявно типизированная переменная? 24. Для чего используют Nullable тип? 25. Как объявить строковый литерал? Какие операции можно выполнять со строкой? 26. Какие есть способы для задания и инициализации строк? 27. Какие методы есть у типа String? 28. В чем отличие пустой и null строки? 29. Как можно выполнить сравнение строк? 30. В чем отличие типов String и StringBuilder? 31. Поясните явные преобразования переменных с помощью команд Convert. 32. Как выполнить консольный ввод/вывод? 33. Приведите примеры определения и инициализации одномерных и двумерных массивов. 34. Что такое ступенчатый массив? Как его задать? 35. Какие типы можно использовать в foreach? Приведите пример. 36. Что такое кортеж? Для чего и как он используется? 37. Что такое локальная функция?
Краткие теоретические сведения Приведенные здесь и далее теоретические сведения не являются достаточными для освоения тем (это краткий вводный материал). Необходимо использовать дополнительную литературу. Язык программирования C# является прямым наследником языка С++. Он унаследовал многие синтаксические конструкции языка С и объектноориентированную модель С++. В отличие от С++ С# является чисто объектноориентированным языком. В объектно-ориентированном программировании ход выполнения программы определяется объектами. Объекты это экземпляры класса. Класс это абстрактный тип данных, определяемый пользователем ( программистом). Класс включает в себя данные и функции для обработки этих данных. В С# запрещены глобальные функции. Все функции должны быть обязательно определены внутри класса. Не является исключением и главная функция языка С# Main( ) (в отличии от языка С пишется с прописной буквы). Объявление класса синтаксически имеет следующий вид: сlass имя_класса < // члены класса >Члены класса это данные и функции для работы с этими данными. Рассмотрим шаблон приложения, подготовленный для нас мастером: using System; namespace ConsoleApplication10 < ///
class Class1 < ///
[STAThread] static void Main( string [] args) < // // TODO: Add code to start application here // >> > Первая строчка проекта using System; , включает в себя директиву using , которая сообщает компилятору, где он должен искать классы (типы), не определенные в данном пространстве имен. Мастер, по умолчанию, указывает стандартное пространство имен System , где определена большая часть типов среды .NET. Следующей строчкой namespace ConsoleApplication10 мастер предложения определяет пространство имен для нашего приложения. По умолчанию в качестве имени выбирается имя проекта. Область действия
пространства имен определяется блоком кода, заключенного между открывающей и закрывающей фигурными скобками. Пространство имен обеспечивает способ хранения одного набора имен отдельно от другого. Имена, объявленные в одном пространстве имен не конфликтуют, при совпадении, с именами, объявленными в другом пространстве имен. В шаблоне приложения имеется множество строк, которые являются комментариями. В C# определены три вида комментариев: — многострочный (/*…*/) — однострочный (//…) — XML (///) – комментарий для поддержки возможности создания самодокументированного кода. Строчка [STAThread] является атрибутом. Атрибуты задаются в квадратных скобках. С помощью атрибута в программу добавляется дополнительная описательная информация, связанная с элементом кода, непосредственно перед которым задается атрибут. В нашем случае указывается однопоточная модель выполнения функции Main. Заголовок функции: static void Main( string [] args) Функция Main определена как статическая (static) с типом возвращаемого значения void. Функция Main( ) C# как и функция main( ) языка С может принимать аргументы. Аргумент — это строковый массив, содержащий элементы командной строки. Тело функции пустое и в нем содержится, в виде комментария, предложение добавить туда код для запуска приложения: // TODO: Add code to start application here Воспользуемся этим предложением и добавим в тело функции одну строчку: static void Main( string [] args) < // // TODO: Add code to start application here Console.WriteLine("Привет!"); // >Функции консольного ввода-вывода являются методами класса Console библиотеки классов среды .NET. Для ввода строки с клавиатуры используется метод Console.ReadLine(), а для ввода одного символа метод Console.Read(). Для консольного вывода также имеются две метода — метод Console.Write(), который выводит параметр, указанный в качестве аргумента этой функции, и
— метод Console.WriteLine(),который работает так же, как и Console.Write(), но добавляет символ новой строки в конец выходного текста. Для анализа работы этих методов модифицируйте функцию Main( ) так, как показано ниже : static void Main( string [] args) < // // TODO: Add code to start application here Console.WriteLine("Введите ваше имя"); string str=Console.ReadLine(); Console.WriteLine("Привет "+str+". "); Console.WriteLine("Введите один символ с клавитуры"); int kod=Console.Read(); char sim=( char )kod; Console.WriteLine("Код символа "+sim+" p61 ft21">// > Добавим Console.WriteLine(«Код символа <0>= «,sim,kod); Первым параметром списка является строка, содержащая маркеры в фигурных скобках. Маркер это номер параметра в списке. При выводе текста вместо маркеров будут подставлены соответствующие параметры из остального списка. После маркера через запятую можно указать, сколько позиций отводится для вывода значений. Например, запись означает, что для печати первого элемента списка отводится поле шириной в три символа. Причем, если значение ширины положительно, то производится выравнивание по правому краю поля, если отрицательно то по левому. Добавим 4 новые строчки в конец кода функции Main(): int s1=255; int s2=32; Console.WriteLine(» \n\n+\n——\n»,s1,s2,s1+s2); Console.WriteLine(» \n\n+\n——\n»,s1,s2,s1+s2); // Кроме того, после поля ширины через двоеточие можно указать форматную строку, состоящую из одного символа и необязательного значения точности. Существует 8 различных форматов вывода: С – формат национальной валюты, D – десятичный формат, E – научный (экспоненциальный) формат, F – формат с фиксированной точкой, G – общий формат, N – числовой формат, P – процентный формат,0>
X – шестнадцатеричный формат Например, запись <2,9:C2>– означает, что для вывода второго элемента из списка, отводится поле шириной в 9 символов. Элемент выводится в формате денежной единицы с количеством знаков после запятой равной двум. При выводе результата происходит округление до заданной точности.2,9:C2>
Object Класс
Некоторые сведения относятся к предварительной версии продукта, в которую до выпуска могут быть внесены существенные изменения. Майкрософт не предоставляет никаких гарантий, явных или подразумеваемых, относительно приведенных здесь сведений.
Поддерживает все классы в иерархии классов .NET и предоставляет низкоуровневые службы для производных классов. Является исходным базовым классом для всех классов .NET и корнем иерархии типов.
public ref class System::Object
public class Object
[System.Runtime.InteropServices.ClassInterface(System.Runtime.InteropServices.ClassInterfaceType.AutoDual)] [System.Serializable] public class Object
[System.Runtime.InteropServices.ClassInterface(System.Runtime.InteropServices.ClassInterfaceType.AutoDual)] [System.Serializable] [System.Runtime.InteropServices.ComVisible(true)] public class Object
type obj = class
[] [] type obj = class
[] [] [] type obj = class
Public Class Object
Примеры
В следующем примере определяется тип Point, производный от класса Object, и переопределяются многие виртуальные методы класса Object. Кроме того, в примере показано, как вызывать многие из статических методов и методов экземпляра класса Object.
using System; // The Point class is derived from System.Object. class Point < public int x, y; public Point(int x, int y) < this.x = x; this.y = y; >public override bool Equals(object obj) < // If this and obj do not refer to the same type, then they are not equal. if (obj.GetType() != this.GetType()) return false; // Return true if x and y fields match. var other = (Point) obj; return (this.x == other.x) && (this.y == other.y); >// Return the XOR of the x and y fields. public override int GetHashCode() < return x ^ y; >// Return the point's value as a string. public override String ToString() < return $"(, )"; > // Return a copy of this point object by making a simple field copy. public Point Copy() < return (Point) this.MemberwiseClone(); >> public sealed class App < static void Main() < // Construct a Point object. var p1 = new Point(1,2); // Make another Point object that is a copy of the first. var p2 = p1.Copy(); // Make another variable that references the first Point object. var p3 = p1; // The line below displays false because p1 and p2 refer to two different objects. Console.WriteLine(Object.ReferenceEquals(p1, p2)); // The line below displays true because p1 and p2 refer to two different objects that have the same value. Console.WriteLine(Object.Equals(p1, p2)); // The line below displays true because p1 and p3 refer to one object. Console.WriteLine(Object.ReferenceEquals(p1, p3)); // The line below displays: p1's value is: (1, 2) Console.WriteLine($"p1's value is: "); > > // This code example produces the following output: // // False // True // True // p1's value is: (1, 2) //
open System // The Point class is derived from System.Object. type Point(x, y) = member _.X = x member _.Y = y override _.Equals obj = // If this and obj do not refer to the same type, then they are not equal. match obj with | :? Point as other -> // Return true if x and y fields match. x = other.X && y = other.Y | _ -> false // Return the XOR of the x and y fields. override _.GetHashCode() = x ^^^ y // Return the point's value as a string. override _.ToString() = $"(, )" // Return a copy of this point object by making a simple field copy. member this.Copy() = this.MemberwiseClone() :?> Point // Construct a Point object. let p1 = Point(1,2) // Make another Point object that is a copy of the first. let p2 = p1.Copy() // Make another variable that references the first Point object. let p3 = p1 // The line below displays false because p1 and p2 refer to two different objects. printfn $"" // The line below displays true because p1 and p2 refer to two different objects that have the same value. printfn $"" // The line below displays true because p1 and p3 refer to one object. printfn $"" // The line below displays: p1's value is: (1, 2) printfn $"p1's value is: " // This code example produces the following output: // // False // True // True // p1's value is: (1, 2) //
using namespace System; // The Point class is derived from System.Object. ref class Point < public: int x; public: int y; public: Point(int x, int y) < this->x = x; this->y = y; > public: virtual bool Equals(Object^ obj) override < // If this and obj do not refer to the same type, // then they are not equal. if (obj->GetType() != this->GetType()) < return false; >// Return true if x and y fields match. Point^ other = (Point^) obj; return (this->x == other->x) && (this->y == other->y); > // Return the XOR of the x and y fields. public: virtual int GetHashCode() override < return x ^ y; >// Return the point's value as a string. public: virtual String^ ToString() override < return String::Format("(, )", x, y); > // Return a copy of this point object by making a simple // field copy. public: Point^ Copy() < return (Point^) this->MemberwiseClone(); > >; int main() < // Construct a Point object. Point^ p1 = gcnew Point(1, 2); // Make another Point object that is a copy of the first. Point^ p2 = p1->Copy(); // Make another variable that references the first // Point object. Point^ p3 = p1; // The line below displays false because p1 and // p2 refer to two different objects. Console::WriteLine( Object::ReferenceEquals(p1, p2)); // The line below displays true because p1 and p2 refer // to two different objects that have the same value. Console::WriteLine(Object::Equals(p1, p2)); // The line below displays true because p1 and // p3 refer to one object. Console::WriteLine(Object::ReferenceEquals(p1, p3)); // The line below displays: p1's value is: (1, 2) Console::WriteLine("p1's value is: ", p1->ToString()); > // This code produces the following output. // // False // True // True // p1's value is: (1, 2)
' The Point class is derived from System.Object. Class Point Public x, y As Integer Public Sub New(ByVal x As Integer, ByVal y As Integer) Me.x = x Me.y = y End Sub Public Overrides Function Equals(ByVal obj As Object) As Boolean ' If Me and obj do not refer to the same type, then they are not equal. Dim objType As Type = obj.GetType() Dim meType As Type = Me.GetType() If Not objType.Equals(meType) Then Return False End If ' Return true if x and y fields match. Dim other As Point = CType(obj, Point) Return Me.x = other.x AndAlso Me.y = other.y End Function ' Return the XOR of the x and y fields. Public Overrides Function GetHashCode() As Integer Return (x , )" End Function ' Return a copy of this point object by making a simple field copy. Public Function Copy() As Point Return CType(Me.MemberwiseClone(), Point) End Function End Class NotInheritable Public Class App Shared Sub Main() ' Construct a Point object. Dim p1 As New Point(1, 2) ' Make another Point object that is a copy of the first. Dim p2 As Point = p1.Copy() ' Make another variable that references the first Point object. Dim p3 As Point = p1 ' The line below displays false because p1 and p2 refer to two different objects. Console.WriteLine([Object].ReferenceEquals(p1, p2)) ' The line below displays true because p1 and p2 refer to two different objects ' that have the same value. Console.WriteLine([Object].Equals(p1, p2)) ' The line below displays true because p1 and p3 refer to one object. Console.WriteLine([Object].ReferenceEquals(p1, p3)) ' The line below displays: p1's value is: (1, 2) Console.WriteLine($"p1's value is: ") End Sub End Class ' This example produces the following output: ' ' False ' True ' True ' p1's value is: (1, 2) '
Комментарии
Дополнительные сведения об этом API см. в разделе Дополнительные примечания API для Object.
Конструкторы
Инициализирует новый экземпляр класса Object.
Встроенные ссылочные типы (справочник по C#)
C# имеет множество встроенных ссылочных типов. У них есть ключевые слова или операторы, которые являются синонимами типа в библиотеке .NET.
Тип object
Тип object является псевдонимом System.Object в .NET. В унифицированной системе типов C# все типы, стандартные и определяемые пользователем, ссылочные типы и типы значений напрямую или косвенно наследуются из System.Object. Переменным типа object можно назначать значения любого типа. Любой переменной object можно назначить значение по умолчанию с помощью литерала null . Когда переменная типа значения преобразуется в объект, она будет указана в поле. Если переменная типа object преобразуется в тип значения, он считается распакованным. Дополнительные сведения см. в разделе Упаковка-преобразование и распаковка-преобразование.
Тип string
Тип string представляет последовательность, состоящую из нуля или более символов в кодировке Юникод. string является псевдонимом для System.String в .NET.
Несмотря на то что 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, так как содержимое строк эквивалентно, но a не b ссылается на тот же экземпляр строки.
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 и могут быть написаны в трех формах, необработанных, кавычках и подробных выражениях.
Необработанные строковые литералы доступны начиная с C# 11. Необработанные строковые литералы могут содержать произвольный текст, не требуя 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 >""";
Компилятор выдает ошибку, если любая из текстовых строк распространяется слева от закрывающей кавычки. Открывающие и закрывающие последовательности кавычки могут находиться в одной строке, предоставляя строковый литерал не начинается и не заканчивается символом кавычки:
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 — это стандарт для веб-протоколов и других важных библиотек. Начиная с C# 11, можно добавить суффикс в строковый литерал, чтобы указать u8 кодировку UTF-8. Литералы UTF-8 хранятся в виде ReadOnlySpan объектов. Естественный тип строкового литерала UTF-8. ReadOnlySpan При использовании строкового литерала UTF-8 создается более четкое объявление, чем объявление эквивалента System.ReadOnlySpan , как показано в следующем коде:
ReadOnlySpan AuthWithTrailingSpace = new byte[] < 0x41, 0x55, 0x54, 0x48, 0x20 >; ReadOnlySpan AuthStringLiteral = "AUTH "u8;
Для хранения строкового литерала UTF-8 в виде массива требуется использование ReadOnlySpan.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 stringAction = str => <>; Action objectAction = obj => <>; // Valid due to implicit reference conversion of // objectAction to Action, but may fail // at run time. Action combination = stringAction + objectAction;
Вы можете создать делегат с правильным типом среды выполнения, создав новый объект делегата. В следующем примере показано, как это решение можно применить к предыдущему примеру.
Action stringAction = str => <>; Action objectAction = obj => <>; // Creates a new delegate instance with a runtime type of Action. Action wrappedObjectAction = new Action(objectAction); // The two Action delegate instances can now be combined. Action 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
- C# 11 — необработанные строковые литералы
- C# 11 — необработанные строковые литералы
См. также
- Справочник по C#
- Ключевые слова в C#
- События
- Использование типа dynamic
- Рекомендации по использованию строк
- Базовые операции со строками в .NET Framework
- Создание строк
- Операторы приведения и тестирования типов
- Практическое руководство. Безопасное приведение с помощью сопоставления шаблонов, а также операторов is и as
- Пошаговое руководство. Создание и использование динамических объектов (C# и Visual Basic)
- System.Object
- System.String
- System.Dynamic.DynamicObject
Совместная работа с нами на GitHub
Источник этого содержимого можно найти на GitHub, где также можно создавать и просматривать проблемы и запросы на вытягивание. Дополнительные сведения см. в нашем руководстве для участников.