Программирование

Автор работы: Пользователь скрыл имя, 28 Марта 2012 в 11:49, курс лекций

Описание

Лекции по дисциплине "Программирование"

Содержание

Лекция 1. Состав языка Типы данных Переменные и операции

Лекция 2. Линейные программы

Лекция 3. Простейшие операторы. Операторы ветвления

Лекция 4. Операторы цикла и передачи управления

Лекция 5. Обработка исключительных ситуаций

Лекция 6. Классы: основные понятия Описание класса

Лекция 7. Параметры методов

Лекция 8. Конструкторы и свойства

Лекция 9. . Массивы

Лекция 10. Символы и строки

Лекция 11 Дополнительные возможности методов. Индексаторы

Лекция 12. Операции класса. Деструкторы

Лекция 13. Наследование классов

Лекция 14. Интерфейсы

Лекция 15. Стандартные интерфейсы .NET

Лекция 16. Структуры и перечисления

Лекция 17. Делегаты

Лекция 18. События

Работа состоит из  1 файл

Лекции C#.doc

— 847.00 Кб (Скачать документ)

                    поскольку структуры не могут участвовать в иерархиях, для их элементов не могут использоваться спецификаторы protected и protectedinternal;

                    структуры не могут быть абстрактными (abstract), к тому же по умолчанию они бесплодны (sealed);

                    методы структур не могут быть абстрактными и виртуальными;

                    переопределяться (то есть описываться со спецификатором override) могут только методы, унаследованные от базового класса object;

                    параметр this интерпретируется как значение, поэтому его можно использовать для ссылок, но не для присваивания;

                    при описании структуры нельзя задавать значения полей по умолчанию — это будет сделано в конструкторе по умолчанию, создаваемом автоматически (конструктор присваивает значимым полям структуры нули, а ссылочным — значение null).

В листинге 18.1 приведен пример описания структуры, представляющей комплексное число. Из всех операций приведено только описание сложения.

Листинг 18.1. Пример структуры

using System;

namespace ConsoleApplication1

{

    struct Complex

    {

        public double re, im;

         public Complex( double re_, double im_ )

        {

            re = re_; im = im_;       // можно использовать this.re, this.im

        }

         public static Complex operator + ( Complex a, Complex b )

        {

            return new Complex( a.re + b.re, a.im + b.im );

        }

         public override string ToString()

        {

            return ( string.Format( "({0,2:0.##};{1,2:0.##})", re, im ) );

        }

    }

       class Class1

    {   static void Main()

        {

            Complex a = new Complex( 1.2345, 5.6 );

            Console.WriteLine( "a = " + a );

 

            Complex b;

            b.re = 10; b.im = 1;

            Console.WriteLine( "b = " + b );

 

            Complex c = new Complex();

            Console.WriteLine( "c = " + c );

             c = a + b;

            Console.WriteLine( "c = " + c );

        }

    }

}

 

Результат работы программы:

a = (1,23;5,6)

b = (10; 1)

c = ( 0; 0)

c = (11,23;6,6)

 

При выводе экземпляра структуры на консоль выполняется упаковка, то есть неявное преобразование в ссылочный тип. Упаковка применяется и в других случаях, когда структурный тип используется там, где ожидается ссылочный. При обратном преобразовании выполняется распаковка. При присваивании структур и при передаче структур в качестве параметров по значению создается копия значений полей.

Особенно значительный выигрыш в эффективности можно получить, используя массивы структур вместо массивов классов. Например, для массива из 100 экземпляров класса создается 101 объект, а для массива структур — один объект. Пример работы с массивом структур, описанных в предыдущем листинге:

Complex [] mas = new Complex[4];

 

for ( int i = 0; i < 4; ++i )

{

    mas[i].re = i;

    mas[i].im = 2 * i;

}

 

foreach ( Complex elem in mas ) Console.WriteLine( elem );

 

Перечисления

При написании программ часто возникает потребность определить несколько связанных между собой именованных констант. Для этого удобно воспользоваться перечисляемым типом данных, все возможные значения которого задаются списком целочисленных констант, например:

enum Menu { Read, Write, Append, Exit }

enum Радуга { Красный, Оранжевый, Желтый, Зеленый, Снний, Фиолетовый }

 

Для каждой константы задается ее символическое имя. По умолчанию константам присваиваются последовательные значения типа int, начиная с 0, но можно задать и собственные значения, например:

enum Nums { two = 2, three, four, ten = 10, eleven, fifty = ten + 40 };

 

Константам three и four присваиваются значения 3 и 4, константе eleven — 11. Имена перечисляемых констант внутри каждого перечисления должны быть уникальными, а значения могут совпадать.

Синтаксис перечисления:

[ атрибуты ] [ спецификаторы ] enum имя_перечисления [ : базовый_тип ]

    тело_перечисления [ ; ]

 

Допускаются спецификаторы new, public, protected, internal и private. Базовый тип — это тип элементов, из которых построено перечисление. По умолчанию используется тип int, но можно задать тип и явным образом, выбрав его среди целочисленных типов (кроме char).

Тело перечисления состоит из имен констант, каждой из которых может быть присвоено значение. Если значение не указано, оно вычисляется прибавлением единицы к значению предыдущей константы.

Перечисления часто используются как вложенные типы, идентифицируя значения из какого-либо ограниченного набора. Пример такого перечисления приведен в листинге 18.2.

Листинг 18.2. Пример перечисления

using System;

namespace ConsoleApplication1

{

    struct Боец

    {

        public enum Воинское_Звание

        {

            Рядовой, Сержант, Майор, Генерал

        }

         public string Фамилия;

        public Воинское_Звание Звание;

    }   

    class Class1

    {   static void Main()

        {

            Боец x;

            x.Фамилия = "Иванов";

            x.Звание = Боец.Воинское_Звание.Сержант;

             Console.WriteLine( x.Звание + " " + x.Фамилия );

        }

    }

}

 

Результат работы программы:

Сержант Иванов

 

Перечисления удобно использовать для представления битовых флагов, например:

enum Flags : byte

{

    b0, b1, b2, b3 = 0x04, b4 = 0x08, b5 = 0x10, b6 = 0x20, b7 = 0x40

}

 

Операции с перечислениями

С переменными перечисляемого типа можно выполнять арифметические операции (+, –, ++, ––), логические поразрядные операции (^, &, |, ~), сравнивать их с помощью операций отношения (<, <=, >, >=, ==, !=) и получать размер в байтах (sizeof).

При использовании переменных перечисляемого типа в целочисленных выражениях и операциях присваивания требуется явное преобразование типа.

Пример:

Flags a = Flags.b2 | Flags.b4;

Console.WriteLine( "a = {0}   {0,2:X}", a );

++a;

 

Console.WriteLine( "a = {0}   {0,2:X}", a );

int x = (int) a;

Console.WriteLine( "x = {0}   {0,2:X}", x );

 

Flags b = (Flags) 65;

Console.WriteLine( "b = {0}   {0,2:X}", b );

 

Результат работы этого фрагмента программы:

a = 10    0A

a = 11    0B

x = 11     B

b = 65    41

 

Базовый класс System.Enum

Все перечисления в C# являются потомками базового класса System.Enum, который снабжает их некоторыми полезными методами. Более продробно о нем можно прочитать в учебнике.

Лекция 17. Делегаты

Делегат — это вид класса, предназначенный для хранения ссылок на методы. Делегат, как и любой другой класс, можно передать в качестве параметра, а затем вызвать инкапсулированный в нем метод. Делегаты используются для поддержки событий, а также как самостоятельная конструкция языка. Рассмотрим сначала второй случай.

Описание делегатов

Описание делегата задает сигнатуру методов, которые могут быть вызваны с его помощью:

[ атрибуты ] [ спецификаторы ] delegate тип имя_делегата ( [ параметры ] )

 

Допускаются спецификаторы new, public, protected, internal и private. Тип описывает возвращаемое значение методов, вызываемых с помощью делегата, а необязательными параметрами делегата являются параметры этих методов. Делегат может хранить ссылки на несколько методов и вызывать их поочередно; естественно, что сигнатуры всех методов должны совпадать.

Пример описания делегата:

public delegate void D ( int i );

 

Здесь описан тип делегата, который может хранить ссылки на методы, возвращающие void и принимающие один параметр целого типа. Объявление делегата можно размещать непосредственно в пространстве имен или внутри класса.

Использование делегатов

Для того чтобы воспользоваться делегатом, необходимо создать его экземпляр и задать имена методов, на которые он будет ссылаться. При вызове экземпляра делегата вызываются все заданные в нем методы.

Делегаты применяются в основном для следующих целей:

                    получения возможности определять вызываемый метод не при компиляции, а динамически во время выполнения программы;

                    обеспечения связи между объектами по типу «источник — наблюдатель»;

                    создания универсальных методов, в которые можно передавать другие методы;

                    поддержки механизма обратных вызовов.

Рассмотрим сначала пример реализации первой из этих целей. В листинге 19.1 объявляется делегат, с помощью которого один и тот же оператор используется для вызова двух разных методов (C00l и Hack).

Листинг 19.1. Простейшее использование делегата

using System;

namespace ConsoleApplication1

{

    delegate void Del ( ref string s );               // объявление делегата

 

    class Class1

    {

        public static void C00l ( ref string s )                  // метод 1

        {

            string temp = "";

            for ( int i = 0; i < s.Length; ++i )

            {

                if      ( s[i] == 'o' || s[i] == 'O') temp += '0';

                else if ( s[i] == 'l' )               temp += '1';

                else                                  temp += s[i];

            }

            s = temp;

        }

 

        public static void Hack ( ref string s )                  // метод 2

        {

            string temp = "";

            for ( int i = 0; i < s.Length; ++i )

                if ( i / 2 * 2 == i ) temp += char.ToUpper( s[i] );

                else                  temp += s[i];

 

            s = temp;

        }

 

        static void Main()

        {

            string s = "cool hackers";

            Del d;                                     // экземпляр делегата

 

            for ( int i = 0; i < 2; ++i )

            {

                d = new Del( C00l );              // инициализация методом 1

                if ( i == 1 ) d = new Del(Hack);  // инициализация методом 2

 

                d( ref s );     // использование делегата для вызова методов

                Console.WriteLine( s );

            }

        }

    }

}

 

Результат работы программы:

c001 hackers

C001 hAcKeRs

 

Использование делегата имеет тот же синтаксис, что и вызов метода. Если делегат хранит ссылки на несколько методов, они вызываются последовательно в том порядке, в котором были добавлены в делегат.

Добавление метода в список выполняется либо с помощью метода Combine, унаследованного от класса System.Delegate, либо, что удобнее, с помощью перегруженной операции сложения. Вот как выглядит измененный метод Main из предыдущего листинга, в котором одним вызовом делегата выполняется преобразование исходной строки сразу двумя методами.

static void Main()

{

        string s = "cool hackers";

        Del d = new Del( C00l );

        d += new Del( Hack );             // добавление метода в делегат

 

        d( ref s );

        Console.WriteLine( s );           // результат: C001 hAcKeRs

}

 

При вызове последовательности методов с помощью делегата необходимо учитывать следующее:

                    сигнатура методов должна в точности соответствовать делегату;

                    методы могут быть как статическими, так и обычными методами класса;

                    каждому методу в списке передается один и тот же набор параметров;

                    если параметр передается по ссылке, изменения параметра в одном методе отразятся на его значении при вызове следующего метода;

                    если параметр передается с ключевым словом out или метод возвращает значение, результатом выполнения делегата является значение, сформированное последним из методов списка (в связи с этим рекомендуется формировать списки только из делегатов, имеющих возвращаемое значение типа void);

                    если в процессе работы метода возникло исключение, не обработанное в том же методе, последующие методы в списке не выполняются, а происходит поиск обработчиков в объемлющих делегат блоках;

                    попытка вызвать делегат, в списке которого нет ни одного метода, вызывает генерацию исключения System.NullReferenceException.

Паттерн «наблюдатель»

Рассмотрим применение делегатов для обеспечения связи между объектами по типу «источник — наблюдатель». В результате разбиения системы на множество совместно работающих классов появляется необходимость поддерживать согласованное состояние взаимосвязанных объектов. При этом желательно избежать жесткой связанности классов, так как это часто негативно сказывается на возможности многократного использования кода.

Для обеспечения связи между объектами во время выполнения программы применяется следующая стратегия. Объект, называемый источником, при изменении своего состояния, которое может представлять интерес для других объектов, посылает им уведомления. Эти объекты называются наблюдателями. Получив уведомление, наблюдатель опрашивает источник, чтобы синхронизировать с ним свое состояние. Примером такой стратегии может служить связь электронной таблицы с созданными на ее основе диаграммами.

Программисты часто используют одну и ту же схему организации и взаимодействия объектов в разных контекстах. За такими схемами закрепилось название паттерны, или шаблоныпроектирования. Описанная стратегия известна под названием паттерн «наблюдатель».

Наблюдатель (observer) определяет между объектами зависимость типа «один ко многим», так что при изменении состоянии одного объекта все зависящие от него объекты получают извещение и автоматически обновляются. Рассмотрим пример (листинг 19.2), в котором демонстрируется схема оповещения источником трех наблюдателей. Гипотетическое изменение состояния объекта моделируется сообщением «OOPS!». Один из методов в демонстрационных целях сделан статическим.

Листинг 19.2. Оповещение наблюдателей с помощью делегата

Информация о работе Программирование