среда, 25 августа 2010 г.

Основы C# - Часть 2

Системные типы данных и псевдонимы С#

Как уже говорилось, любой встроенный тип данных С# - это всего лишь псевдоним для существующего типа, определенного в пространстве имен 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; то с помощью этого метода вы сможете производить сортировку и ваших пользовательских типов данных.

Комментариев нет:

Отправить комментарий