Единая система типов C# (и. NET) • Common Type System (CTS) – спецификации Microsoft, описывающие определение типов и их поведение • Common Language Specification (CLS) – подмножество типов CTS, которые могут быть использованы в коде с разными языками программирования
Единая система типов является основой межъязыкового взаимодействия ü Единая система типов для C#, Visual Basic, JScript, Pascal, J#, С++ ü Единая библиотека базовых классов ü Межъязыковое наследование ü Межъязыковая обработка исключений ü Переход при отладке между модулями на разных языках
Типы-значения (value types) (размерные, структурные) • Простые типы-значения (int, float, …) • Перечисления (enum) • Структуры (struct) Ссылочные типы (reference types) • • • Классы (class) Делегаты (delegate) Интерфейсы (interface) Строки (System. String) System. Object Массивы (System. Array)
Ссылочные типы и типы-значения Value Types Переменная содержит… Значение хранится в… Инициализируется При присваивании… Reference Types …значение …ссылку на значение … стеке …динамической памяти (managed heap) 0, false, ‘ ’ null …копируется значение …копируется ссылка
Ссылочные типы и типы-значения struct S {…}; int i = 3; S s 1 = new S(); S s 2 = s 1; class T {…}; T t 1 = new T(); T t 2 = new T(); T t 3 = t 2; Stack Managed Heap i (3) s 1 s 2 t 1 t 2 t 3 T T
Встроенные типы-значения C# sbyte short бит ushort int uint long бит ulong бит char бит float CLS Тип CTS Длина нет + System. Sbyte System. Byte + System. Int 16 8 бит 16 нет + нет System. UInt 16 System. Int 32 System. UInt 32 + System. Int 64 16 бит 32 бит 64 нет + + System. UInt 64 64 System. Char 16 System. Single 32 бит
Класс Object - самый базовый класс class Object {… public virtual string To. String(); public virtual bool Equals(object obj); public static bool Equals( object obj. A, object obj. B ); public static bool Reference. Equals( object obj. A, object obj. B ); public virtual int Get. Hash. Code(); public Type Get. Type(); … } ü Методы класса object могут быть вызваны для объектов любого типа ü Переменной типа object может быть присвоено значение любого типа
Система типов CLR
Упаковка(boxing) и распаковка(unboxing) -1 ü Упаковка (boxing) - преобразование размерного типа (value type) в ссылочный. ü Упаковка обычно выполняется при передаче объекта размерного типа (value type) как значение для параметра, имеющего тип object. int x = 5; object obj = x; string s = x. To. String(); s = (123. 56). To. String(); int res = (int)obj; // Явная упаковка // Неявная упаковка // Распаковка
Упаковка(boxing) и распаковка(unboxing) -2 ü При упаковке • в управляемой куче выделяется память для объекта; • поля объекта копируются в выделенную память в управляемой куче. ü Распаковка состоит в получении указателя на поля данных исходного размерного типа в управляемой куче. ü При распаковке копирование полей не выполняется.
Упаковка и распаковка. Пример public class T { public int x; public T(int x) { this. x = x; } public void Set. Value ( int val ) { x = val; } } public struct S { public int x; public S(int x) { this. x = x; } public void Set. Value ( int val ) { x = val; } } public class Class 1{ static void Main(string[] args) { int i = 1; object obji = i; obji = 5; Console. Write. Line( " i = {0} obji = {1}", i, obji); // Output i = 1 obji = 5 T t = new T(1); object objt = t; t. Set. Value(2); ((T)objt). Set. Value(5); Console. Write. Line( " t. x = {0} ((T)objt). x = {1}", t. x, // Output t. x = S s = new S(1); object objs = s; s. Set. Value(2); ((S)objs). Set. Value(5); Console. Write. Line( " s. x = {0} ((S)objs). x = {1}", s. x, // Output s. x = }} Stack Managed Heap i obji boxing i t objt s T objs boxing s ((T)objt). x); 5 ((T)objt). x = 5 ((S)objs). x); 2 ((S)objs). x = 1
Арифметические типы ü Неявные преобразования арифметических типов разрешены, если это не приводит к потере информации int iv = 10; long lv = iv; ü Явное преобразование может привести к потере информации long lv = long. Max. Value; int iv = (int)lv;
Операторы сhecked и unchecked ü Только для целочисленных типов проверяется переполнение при выполнении операций try { int i 0 = int. Max. Value; int i 1 = i 0 + 100; int i 2 = checked(i 0 + 100); } catch(Overflow. Exception ex) { Console. Write. Line("Try 1: n" + ex. Message ); } Настройка компилятора: Project / Properties… Build / Advanced… Check For Arithmetic Overflow / Underflow ( true / false)
Вычисления с плавающей запятой double d 1 = 0; double d 2 = 0; double res = d 1 / d 2; Console. Write. Line("d 1 = {0} d 2 = {1} res = {2}", d 1, d 2, res); double d 0 = 0; d 1 = -1. 0; d 2 = 1. 0; double res 1 = d 1 / d 0; Console. Write. Line("d 1 = {0} d 0 = {1} res 1 = {2}", d 1, d 0, res 1); double res 2 = d 2 / d 0; Console. Write. Line("d 2 = {0} d 0 = {1} res 2 = {2}", d 2, d 0, res 2); res = res 1 + res 2; Console. Write. Line("res 1 = {0} res 2 = {1} res = {2}", res 1, res 2, res); double d 3 = double. Positive. Infinity; res 1 = d 3 + 1. 23; res 2 = d 3 * 0; Console. Write. Line("d 3 = {0} res 1 = {1} res 2 = {2}", d 3, res 1, res 2); double d 4 = double. Na. N; res 1 = d 4 * 0; res 2 = d 4 / double. Positive. Infinity; Console. Write. Line("d 4 = {0} res 1 = {1} res 2 = {2}", d 4, res 1, res 2); Результат: d 1 = 0 d 2 = 0 res = Na. N d 1 = -1 d 0 = 0 res 1 = -бесконечность d 2 = 1 d 0 = 0 res 2 = бесконечность res 1 = -бесконечность res 2 = бесконечность res = Na. N d 3 = бесконечность res 1 = бесконечность res 2 = Na. N d 4 = Na. N res 1 = Na. N res 2 = Na. N
Статический класс Convert ü Содержит методы для преобразования значений одного базового типа данных к другому базовому типу. В частности, в классе определены методы public static int To. Int 32( string value ); public static double To. Double( string value ); public static int To. Int 32( double value ); // с округлением ü Методы бросают исключение, если преобразование невозможно. try { double d 1 = 1. 5; int i 1 = Convert. To. Int 32(d 1); Console. Write. Line(i 1); // 2 double d 2 = 2. 5; int i 2 = Convert. To. Int 32(d 2); Console. Write. Line(i 2); // 2 double d 3 = 1. 23452345; float f 1 = Convert. To. Single(d 3); Console. Write. Line(f 1); // 1. 234523 double d 4 = double. Max. Value; float f 2 = Convert. To. Single(d 4); Console. Write. Line(f 2); // бесконечность int i 3 = Convert. To. Int 32(d 4); // исключение Console. Write. Line(i 3); } catch (Exception ex) { Console. Write. Line(ex. Message); }
Массивы ü Ссылочный тип. Память всегда выделяется в управляемой куче. ü Абстрактный базовый класс System. Array. ü CLR поддерживает • Одномерные массивы • Многомерные массивы • Ступенчатые (jagged) массивы ( не совместимы с CLS)
Одномерные массивы типовзначений int[] a = new int[3] {1, 2, 5}; b; // b == null c = { 7, 13 }; d = c; // d и c – это один и тот же массив! Stack Managed Heap a b (null) 1 c 2 d 5 7 13
Одномерные массивы ссылочных типов class T {. . . T(int par 1, int par 2) {. . . } Stack T[] a; T[] b = new T[2]; T[] c = new T[2] {new T(2, 3), new T(12, 5)}; c[0] = c[1]; T[] d = c; Managed Heap a (null) b b[0] (null) c T b[1] (null) d c[0] c[1] T
Выход за границы массива ü В массивах C# всегда хранится информация о числе измерений массива и числе элементов в каждом измерении. ü В массивах C# проверяется выход индекса за границы массива. ü Отключить проверку выхода за границы массива можно только для массивов с элементами размерных типов, включив их в блок unsafe (требует настройки компилятора).
Массивы нулевой длины ü Можно объявить массив нулевой длины. Массив не содержит элементов, но ссылка отлична от null. try { double[] arr 1 = new double[0]; Console. Write. Line(arr 1. Length); double[] arr 2 = null; Console. Write. Line(arr 2. Length); } catch (Exception ex) { Console. Write. Line(ex. Message); } // // // Вывод: 0 Object reference not set to an instance of an object.
Инициализация элементов массива Приведение типов ü По умолчанию при создании массива элементы размерных типов инициализируются нулевыми значениями, элементы ссылочных типов – значением null. ü Неявное преобразование массива типа T 1[ ] к массиву типа T 2[ ] возможно только, если • T 1 и T 2 – ссылочные типы • допустимо неявное преобразование T 1 ->T 2 • массивы имеют одинаковую размерность ü Явное и неявное преобразование массивов с элементами размерных типов (value types) запрещено.
Некоторые методы класса Array ü Свойства для получения размеров массива int[] a = new int[3]; a. Length - число элементов в массиве a. Rank – число измерений массива а. Get. Length(int i) – размер i-го измерения ü Копирование одномерного массива int[] a = new int[3]; int[] b = (int[])a. Clone(); // Копирует массив
Многомерные массивы ü Прямоугольные массивы int[, ] c = new int[2, 3] { {1, 2, 3 }, {4, 5, 6} }; c[1, 2] = 10; // c. Length == 6 // c. Get. Length(0) == 2 // c. Get. Length(1) == 3 // c. Rank == 2 c[0, 0] c[0, 1] c[0, 2] c[1, 0] c[1, 1] c[1, 2] ü Можно копировать при помощи Clone().
Многомерные ступенчатые (jagged) массивы ( другие названия - вложенные, зубчатые, невыравненные) int[][] c = new int[2][]; c[0] = new int[3] { 0, 1, 2 }; c[1] = new int[2] { 3, 4 }; … // c. Length == 2 // c[0]. Length == 3 ü Разные строки могут иметь разную длину c[0] c[1] c[0][0] c[0][1] c[1][0] c[1][1] c[0][2] ü Будьте внимательны при работе с Clone().
Строки. Класс System. String ü Неизменяемые последовательности символов Unicode. ü В созданной строке нельзя изменить ни отдельные символы, ни длину. При операциях со строками создаются новые объекты, память для которых распределяется в управляемой куче. ü При компиляции исходного текста все литеральные строки размещаются в метаданных модуля в одном экземпляре (в хэш-таблице). ü Нелитеральные строки можно добавить в хэштаблицу с помощью метода string. Intern(string);
Приемы работы со строками ü Возможен поэлементный доступ string s = "Hello, World!"; Console. Write. Line(s[0]); // H foreach(char c in s) Console. Write. Line("{0}", c); ü Операция сложения определена как конкатенация строк string s 1 = "Hello"; string s 2 = "World"; string s 3 = s 1 + ", " + s 2 + "!" ;
Приемы работы со строками -2 ü Статический метод Concat (9 перегрузок) выполняет объединение строк или строковых представлений объектов public static string Concat ( params Object[] args ) ; ü Статический метод Join (2 перегрузки) выполняет объединение строк, вставляя строку-разделитель между элементами public static string Join ( string separator, string[] value ); ü Статический метод Format (5 перегрузок) формирует строку с использованием строки форматирования public static string Format(string format, params Object[]args);
Метод Split ü Метод Split (6 перегрузок) формирует из строки массив строк, используя как разделители заданные символы public string[] Split ( params char[] separator ); ü Пример string str = "ab cd; abc; 1234"; string[] sar 1 = str. Split('; ', ' '); foreach (string i in sar 1) Console. Write. Line(i); char[] delim = {'; '}; string[] sar 2 = str. Split(delim, 2); foreach (string i in sar 2) Console. Write. Line(i); Вывод: ab cd abc 1234 ab cd abc; 1234
Строки. Класс System. Text. String. Builder ü Изменяемые последовательности символов Unicode. ü Строки можно модифицировать без перераспределения памяти. ü При создании объекта (6 Ctors) можно распределить память “с запасом”. ü Свойство int Capacity { get; set; }.
Класс System. Text. String. Builder - 2 String. Builder sb = new String. Builder( "abc“, 64); Console. Write. Line( "{0} {1} {2}", sb. Length, sb. Capacity); // abc 3 64 sb. Append(“xy”); Console. Write. Line( "{0} {1} {2}", sb. Length, sb. Capacity); // abcxy 5 64 string str = sb. To. String(); Stack Managed Heap sb ’a’ ’b’ ’c’ ’x’ ’y’ … 64
Пример Arrays_Demo String. Builder [] st = new String. Builder[2] {new String. Builder("abc"), new String. Builder("efg")}; String. Builder[] st_copy = (String. Builder[]) st. Clone(); st[1][2] = 'z'; Console. Write. Line("nst"); foreach(String. Builder elem in st) Console. Write(" {0}", elem); Console. Write. Line("nst_copy"); foreach(String. Builder elem in st_copy) Console. Write(" {0}", elem); Stack Managed Heap st st_copy st[0] st[1] String. Builder (”abc”) st_copy[0] st_copy[1] String. Builder (“efg”)
Средства консольного ввода/вывода ü Для организации консольного ввода/вывода предназначены статические методы класса System. Console … Console. Write. Line(“Hello, World!”); Console. Write(“Hello, World!”); … ü Методы Write и Write. Line определены как методы с переменным числом параметров … Console. Write. Line(“{0}, {1}{2}”, ”Hello”, ”World”, ”!”); …
Консольный ввод ü Ввод очередного символа и целой строки int i = Console. Read(); string str = Console. Read. Line(); ü Преобразование введенной строки в число string str = Console. Read. Line(); int i = Int 32. Parse(str); float f = float. Parse(str); double d = double. Parse(str); ü При передаче в качестве параметра неправильной строки бросается исключение.
Консольный вывод: форматирование ü Общий вид строки форматирования {N, M: F
Консольный вывод: форматирование. Пример Общий вид строки форматирования {N, M: F