Системные типы данных и псевдонимы С#
Как уже говорилось, любой встроенный тип данных С# - это всего лишь псевдоним для существующего типа, определенного в пространстве имен System. В табл. 3. перечислены все системные типы данных, соответствующие им псевдонимы С#, а также информация о совместимости данных типов с CLS.
Псевдо-ним C# | Соответствует ли CLS | Систем- ный тип | Диапазон хранимой информации | Назначение |
sbyte | нет | SByte | от -128 до 127 | Знаковое 8-битовое число |
byte | да | Byte | от 0 до 255 | Беззнаковое 8-битовое число |
short | да | Int16 | от -32768 до 32767 | Знаковое 16-битовое число |
ushort | нет | UInt16 | от 0 до 65535 | Беззнаковое 16-битовое число |
int | да | Int32 | от -2 147 483 648 до 2 147 483 647 | Знаковое 32-битовое число |
uint | нет | UInt32 | от 0 до 4 294 967 295 | Беззнаковое 32-битовое число |
long | да | Int64 | от -9 223 372 036 854 775 808 до 9 223 372 036 854 775 807 | Знаковое 64-битовое число |
ulong | нет | UInt64 | от 0 до 18 446 744 073 709 551 615 | Беззнаковое 64-битовое число |
char | да | Char | от U+000 до U+ffff | Один 16-битовый символ Unicode |
float | да | Single | от 1,5*10-45 до 3,4*1038 | 32-битовое значение с плавающей запятой |
double | да | Double | от 5,0*10-324 до 1,7*10308 | 64-битовое значение с плавающей запятой |
bool | да | Boolean | true или false | Представляет «истину» или «ложь» |
decimal | да | Decimal | от 100 до 1028 | 96-битовое знаковое значение |
string | да | String | ограничен только системной памятью | Представляет набор символов Unicode |
object | да | Object | практически все что угодно. Все типы происходят от System.Object, поэтому объектом является все | Класс, базовый для всех типов во вселенной .NET |
Таблица 3. Системные типы данных и псевдонимы C#
Обратите также внимание, что только часть типов С# является СLS-совместимой. Если вы создаете свои типы, которые будут использоваться в многоязыковой среде, желательно ограничиться лишь CLS-совместимыми типами. Запоминать на самом деле надо не так много: достаточно принять за правило не использовать беззнаковые типы в определениях любых открытых членов типов. Этим вы гарантируете, что ваши классы, интерфейсы и структуры смогут нормально работать с любым языком .NET.
Значения по умолчанию для встроенных типов данных
Как уже говорилось, у всех встроенных типов данных в .NET есть свои значения по умолчанию. Когда вы создаете экземпляр класса, его переменным-членам автоматически присваиваются эти значения. Однако если вы создаете переменную не внутри класса, а внутри метода, значения по умолчанию для них уже применяться не будут. В этой ситуации вы должны обязательно присвоить им начальные значения.
Константы
Кроме переменных в программах часто используются их в некотором смысле противоположности - константы. Как и в С, и в С++, В С# константы определяются при помощи ключевого слова const. Константы можно определять и на уровне методов, но гораздо чаще они используются на уровне определений классов.
public const int myIntConst = 5;
const int LocalConst=4;
Иногда удобно использовать служебный класс, созданный с единственной целью - служить в качестве хранилища констант. При этом нелишне будет позаботиться о том, чтобы пользователь не смог создать экземпляр этого класса. Чтобы запретить создание экземпляров данного класса, достаточно определить конструктор как private. Запретить создавать экземпляры данного класса можно еще одним способом: определив класс как абстрактный (при помощи ключевого слова abstract).
Использование специального класса для хранения всех констант представляется особенно полезным в свете того, что С# не позволяет определять глобальные константы.
Циклы в С#
В С# предусмотрено четыре конструкции для работы с циклами:
- for
- foreach/in
- while
- do/while
Как видно, в C# появился только один новый вид цикла – foreach/in – который позволяет последовательно обрабатывать все элементы массива:
int odd = 0, even = 0;
// объявление и инициализация массива
int[] arr = new int [] {0,1,2,5,7,8,11};
foreach (int i in arr)
{
if (i%2 == 0)
even++;
else
odd++;
}
Средства управления логикой работы программ в С#
Помимо циклов в любом языке программирования предусмотрены средства для управления логикой работы программ - операторы исходного перехода. В С# для этой цели предусмотрены две простые конструкции – if/else и switch. Эти конструкции аналогичны тем, что были в С++.
Но необходимо помнить: то, что не равно 0 - не является true для конструкции if/else в С#:
if (thoughtOfТheDay. Length) // Ошибка!
if (0!= thoughtOfТheDay.Length) // "true" или "false"
C++ | C# |
bool ss = false; if(!ss) { //... } int aa = 1; if(aa)// в С# так нельзя { //... } | bool ss = false; if(!ss) { //... } int aa = 1; if(aa!=0)//так и только так! { //... } |
Сопоставим небольшую программу, написанную на языках C# и C++, в которой используется оператор switch:
C++ | C# |
int a = 2; char * abc = new char[100]; abc = "Строка"; switch(a) { case 0: cout << "0" << endl; case 1: cout << "1" << endl; break; case 2: cout << "2" << endl; if(strcmp(abc,"Строка")==0) { cout << "abc = Строка" << endl; } else if(strcmp(abc,"Что-то еще")==0) {} default: cout << "default" << endl; break; } delete[] abc; | int a = 2; string abc = "Строка"; switch(a) { case 0: Console.WriteLine("Это 0"); goto case 1; // так и только так! case 1: Console.WriteLine("Это 1"); break; case 2: Console.WriteLine("Это 2"); switch(abc) { case("В switch можно исп строки!!!"): break; case ("Строка"): Сonsole.WriteLine("Yo!"); break; } goto default;//так и только так! default: Console.WriteLine("Default"); break; } |
Определение пользовательских методов класса
Как мы помним, метод - это набор действий, который рассматривается как единое целое и может быть выполнен в ходе работы программы. В С# не существует глобальных методов - любой метод обязательно должен быть членом класса или структуры. Методы могут принимать или не принимать параметры, могут возвращать или не возвращать значения (встроенных или пользовательских типов данных) и могут быть статическими или методами экземпляров.
Модификаторы доступа к методам
В С# для каждого метода существует свой уровень доступа, который определяет, откуда можно будет обратиться к данному методу (public, private, protected, internal, protected internal). Модификаторы более подробно были рассмотрены в первой лекции.
Статические методы и методы экземпляров
Как мы уже не один раз видели, методы могут быть объявлены как статические с использованием ключевого слова static. Однако что это значит? Статический метод (static method) может быть вызван напрямую через уровень класса, без необходимости создавать хотя бы один экземпляр объекта данного класса. По этой причине метод Main() всегда объявляется как statiс - чтобы этот метод мог начать выполняться еще до создания первого экземпляра класса, в котором он определен. Вызывать статические методы очень просто: достаточно указать вместе с именем этого метода имя класса, в котором он определен.
Методы экземпляров (instance methods), в отличие от статических методов, применяются на уровне экземпляров объектов. Если метод не объявлен как static, то он считается методом экземпляров по умолчанию. Для вызова метода экземпляра необходимо вначале создать объект класса, в котором определен данный метод.
Статические данные
Классы в С# могут содержать не только статические методы, но и статические данные - как правило, статические переменные. Чтобы лучше представить себе статические данные, вначале мы обратимся к обычным данным класса. Такие обычные данные каждый объект данного класса хранит отдельно и независимо от других объектов данного класса. Предположим, что у нас имеется следующий класс:
Class Foo { public int int Foo; }
Вы можете создать любое количество объектов Foo и присвоить переменной intFoo в каждом из них индивидуальные значения.
В отличие от обычных данных статические данные совместно используются всеми объектами того класса, в котором эти данные были определены. Вместо локальных копий переменной в каждом из объектов существует единственная копия статической переменной, которой пользуются все объекты. Можно сказать, что статические данные предназначены для хранения информации на уровне всего класса, а не отдельных объектов.
Модификаторы для параметров методов
Перечень этих модификаторов представлен в табл. 4:
Таблица 4. Модификаторы для параметров методов.
Модификатор Назначение
(нет) Если параметр никак не помечен, то по умолчанию считается, что ЭТОТ, параметр - входящий (ДЛЯ передачи методу), передаваемый как значение. Вместо пропуска модификатора можно использовать модификатор in - результат будет тем же самым
out Аналогично атрибуту [out] в IDL: исходящий параметр, который возвращается вызванным методом вызывающему
ref Аналогично атрибуту [in, out] в IDL: исходное значение присваивается
вызывающим методом, но оно может быть изменено вызванным. При этом происходит передача параметра по ссылке
params Этот модификатор позволяет передавать целый набор параметров как единое целое. В любом методе может быть только один модификатор params, и параметр с этим модификатором может быть только последним параметром в списке параметров метода.
Пример использования:
public void Add (int x, int y, out int ans)
{ans=x+y;}
вызов: Add (90,90,out ans);
public static void UseParams2(params object[] list)
{
for ( int i = 0 ; i < list.Length ; i++ )
Console.WriteLine(list[i]);
Console.WriteLine();
}
Отдельно заметим для программистов на С и С++: в С# вы можете привязывать параметры, передаваемые методам, к указателям (используя ключевое слово rеf) без необходимости использовать не самые изящные конструкции с операторами * и &.
Работа с массивами
Массивы в С# с точки зрения синтаксиса практически не отличаются от массивов в С, С ++ и Java. Однако если посмотреть на их внутреннее устройство, массив С# это тип, производный от класса System.Array. Поэтому все массивы С# обладают общим набором членов.
Массивы объявляются путем помещения квадратных скобок ([]) после указания типа данных для элементов этого массива, например:
// Массив символьных строк с 10 элементами {0,1,...,9}
string[] booksOnCOM= new string[10];
Если мы объявляем массив фиксированного начального размера, мы обязаны использовать ключевое слово nеw. Но если мы возлагаем обязанность по определению необходимого размера массива на компилятор, можно обойтись и без new:
int[] ages = {20, 22, 23, 0};
Важное различие между массивами С++ и С#, о котором необходимо упомянуть, заключается в том, что В С# элементам массива автоматически присваиваются значения по умолчанию в зависимости от используемого для них типа данных. Например, для массива целых чисел всем элементам будет изначально присвоено значение 0, для массива объектов - значение NULL и т. д.
Многомерные массивы
Помимо простых массивов - массивов с одним измерением в С# поддерживаются также две основные разновидности многомерных массивов. Первую разновидность многомерных массивов иногда называют «прямоугольным массивом». Такой тип массива образуется простым сложением нескольких измерений. При этом все строки и столбцы в данном массиве будут одинаковой длины.
Второй тип многомерного массива можно назвать «ломаным» (jagged). Такой массив содержит в качестве внутренних элементов некоторое количество внутренних массивов, каждый из которых может иметь свой внутренний уникальный размер.
Рассмотрим примеры объявления многомерных массивов:
· Многомерные
// 2-мерный массив, 4 строки и 2 столбца
int[,] myArray = new int[4,2];
// 3-мерный массив, размеры 4 на 2 на 3
int[,,] myArray = new int [4,2,3];
int[,] myArrayB = {{1,2}, {3,4}, {5,6}, {7,8}};
· «Ломаные»
// Jagged-массив одномерных массивов
int[][] myJaggedArray = new int[3][];
// Jagged-массив двумерных массивов
int[][,] myJaggedArray2D = new int [3][,];
// Перед использованием - инициализировать
myJaggedArray[0] = new int[5];
myJaggedArray[1] = new int[4];
myJaggedArray[2] = new int[2];
int[][] myJaggedArrayA = new int [][]
{
new int[] {1,3,5,7,9},
new int[] {0,2,4,6},
new int[] {11,22}
};
int[][] myJaggedArrayB = {
new int[] {1,3,5,7,9},
new int[] {0,2,4,6},
new int[] {11,22}
};
Базовый класс System.Array
Все наиболее важные различия между массивами в С++ и С# происходят оттого, что в С# все массивы являются производными от базового класса System.Array. За счет этого любой массив в С# наследует большое количество полезных методов и свойств, которые сильно упрощают работу программиста. Самые интересные методы и свойства (но, конечно, далеко не все) приведены в табл. 5:
Таблица 5. Некоторые методы класса System.Array.
Член класса Назначение
BinarySearch() Этот статический метод можно использовать только тогда, когда массив реализует интерфейс IComparer. Если этот интерфейс реализован, метод BinarySearch() позволяет найти элемент массива
Clear() Этот статический метод позволяет очистить указанный диапазон элементов (числовые элементы приобретут значения 0, а ссылки на объекты - null)
CopyTo() Используется для копирования элементов из исходного массива в массив назначения
GetEnumerator() Возвращает интерфейс IEnumerator для указанного массива.
GetLength() Length Метод GetLength() используется для определения количества элементов в указанном измерении массива. Length - это свойство только для чтения, с помощью которого можно получить количество элементов массива
GetLowerBound()GetUpperBound() Эти методы используются для определения нижней и верхней границы выбранного вами измерения массива
GetValue()SetValue() Возвращает или устанавливает значение указанного индекса для массива. Этот метод перегружен для нормальной работы как с одномерными, так и с многомерными массивами
Reverse() Этот статический метод позволяет расставить элементы одномерного массива в обратном порядке
Sort() Сортирует одномерный массив встроенных типов данных. Если элементы массива поддерживают интерфейс IComparer; то с помощью этого метода вы сможете производить сортировку и ваших пользовательских типов данных.
Комментариев нет:
Отправить комментарий