Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Questions

.pdf
Скачиваний:
9
Добавлен:
11.03.2016
Размер:
1.14 Mб
Скачать

клавиатуры. В случае успешной отправки смс на экран выводится сообщение об успешной отправки и баланс на счету (остаток).

3. Объясните на форуме, чем, по-вашему, отличается наследование и реализация интерфейсов от наследования классов? Почему лучше использовать интерфейсы, чем абстрактные классы?

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

Интерфейсы, по сравнению с абстрактными классами, представляются более глубоким,

более масштабным и более гибким подходом в описании работы того, или иного класса (набора классов).

Но не всегда целесообразно отдавать предпочтение интерфейсам над абстрактными классами. Например, если нам необходимо описать действия определенных членов класса, но без разницы в том, как этот класс реализует их (члены), то стоит использовать интерфейс(ы). Если же нам интересно задать модель самой реализации некоторого набора полей, методов, свойств,

класса …, то здесь следует описать абстрактный класс. Но в любом случае незаменимых подходов нет.

Дополнения.

Если класс наследует два интерфейса, которые декларируют два одинаковых члена (метода), то при описании классом этого члена достаточно просто описать один из двоих этих методов, что автоматически опишет и второй, ведь оба эти методы имеют одинаковую сигнатуру:

interface IControl

{

void Paint();

}

interface ISurface

{

void Paint();

}

class SampleClass : IControl, ISurface

{

// Both ISurface.Paint and IControl.Paint call this method. public void Paint()

{

}

}

Если же каждый интерфейс декларирует методы с одинаковой сигнатурой, но в классе данные методы описывают разный функционал, то обращение к членам (методам) должно происходить явно – с указанием более полного имени члена, с добавлением имени интерфейса перед именем члена, например:

public class SampleClass : IControl, ISurface

{

void IControl.Paint()

{

System.Console.WriteLine("IControl.Paint");

}

void ISurface.Paint()

{

System.Console.WriteLine("ISurface.Paint");

}

}

Члены класса IControl.Paint доступен только через IControl интерфейс, и ISurface.Paint доступен

лишь через ISurface. Оба метода применяются раздельно, и ни один из них не может напрямую

применяться в экземпляре класса. На пример:

SampleClass obj = new SampleClass(); //obj.Paint(); // Ошибка компиляции

IControl c = (IControl)obj; екплисит приведение c.Paint(); // Calls IControl.Paint on SampleClass.

ISurface s = (ISurface)obj;

s.Paint(); // Calls ISurface.Paint on SampleClass.

Избыточная имплементация в классах применяется в случае, когда оба интерфейса описывают разные члены, но с одинаковыми именами, например свойство и метод:

interface ILeft

{

int P { get;}

}

interface IRight

{

int P();

}

Для возможного наследования классом двоих и более интерфейсов, класс должен применять

избыточную имплементацию для одного из членов класса – для свойства, или метода, или обоих

сразу во избежание ошибки компиляции, например:

class Middle : ILeft, IRight

{

public int P() { return 0; } int ILeft.P { get { return 0; } }

}

Закрытая реализация

Следующая программа содержит интерфейс с именем lEven, который определяет два

метода isEven () и i s Odd (), устанавливающие факт четности и нечетности числа,

соответственно. Класс MyClass реализует интерфейс lEven, причем его член isOdd() реализуется

явным образом.

// Явная реализация члена интерфейса. using System;

interface IEven

{

bool isOdd(int x ) ; bool isEven(int x) ;

}

class MyClass : Ieven

{

//Явная реализация, bool IEven.isOdd(int x)

{

if((x%2) != 0) return true; else return false;

}

//Обычная реализация,

public bool isEven(int x)

{

IEven о = this; // Ссылка на вызывающий объект. return !o.isOdd(x);

}

}

class Demo

{

public static void Main()

{

MyClass ob = new MyClass(); bool result;

result = ob.isEven(4);

if ( result ) Console.WriteLine("4 - четное число."); else Console.WriteLine("3 - нечетное число.");

// result = ob.isOdd(); // Ошибка, член не виден.

}

}

Поскольку метод isOddO реализован в явном виде, он недоступен вне класса MyClass. Такой

способ реализации делает его надежно закрытым. Внутри класса MyClass к методу isOddO

можно получить доступ только через ссылку на интерфейс. Вот почему он прекрасно вызывается

для объекта о в реализации метода isEven ().

Единственный способ вызова явно заданного метода состоит в использовании интерфейсной ссылки.

Теперь перейдем к атрибутам.

Итак, как вы уже наверное прочитали - атрибут – это метод связывания декларативной информации с кодом (типами, методами, свойствами). После того, как атрибут добавлен, можно проверить его наличие во время исполнения и использовать для разных целей.

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

-описание интерфейса с функциями из dll написанных в коде процессора.

-пометка функций, который будут выставлены как web-сервисы

-описание методов для использования объектов в COM+

-описание способа сериализации в XML

7. Делегаты и события.

Давайте обсудим, что такое делегаты и зачем они нужны.

В языках С и C++ можно объявить указатель на функцию, передавать это указатель и затем вызывать по нему нуную функцию. Вот пример на C:

#include <stdio.h>

int add(int x, int y)

{

return x + y;

}

void main()

{

int

(*f)(int, int);

/* declare a pointer to a function */

int

z;

 

f = &add; /* assign the address of the add function to the f pointer */

z = add(13, 17); /* call the add function directly */

z = (*f)(13, 17); /* call the add function through the f pointer */

}

Вот еще один пример:

typedef size_t (*FUNC) (const char*);

Это означает, что я могу создать указатель и положить в него адрес функции

Void printSize (const char *str)

{

FUNC f = strlen;

Printf(“%s is %ld chars\n”, str, f(str));

}

Проблема указателей C в том, что в них можно положить что-угодно

void throwException(const char* str)

{

FUNC f = (FUNC)strcat; f(str); //bye, bye

}

Указатели на функции дают возможность организовывать обратные вызовы (callback). Это часто использовалось в Win32 API.

Делегаты обеспечивают строгую типизацию. И компилятор проверят, чтобы тип функции соответствовал объявлению делегата. Вот вышеприведенный пример, переписанный на C#:

using System;

public class DelegateExample

{

public delegate int TypeSafeAddFunctionDelegate(int x, int y);

public static int Add(int x, int y)

{

return x + y;

}

static void Main()

{

int z;

// Declare a new instance of our delegate (a type-safe function

pointer)

TypeSafeAddFunctionDelegate f = new TypeSafeAddFunctionDelegate(Add);

z = Add(13, 17); z = f(13, 17);

}

}

.NET Framework использует делегаты для обеспечения обратных вызовов, реализации событий,

аналогично тому, как раньше это делалось в Win32 API.

Теперь вопросы:

1. Переделайте пример так, чтобы он работал с параметрами типа float.

Пример:

using System;

public class DelegateExample

{

public delegate float TypeSafeAddFunctionDelegate(float x, float y);

public static float Add(float x, float y)

{

return x + y;

}

static void Main()

{

float z;

// Declare a new instance of our delegate (a type-safe function pointer) TypeSafeAddFunctionDelegate f = new TypeSafeAddFunctionDelegate(Add);

z = Add(13, 17); z = f(13, 17);

}

}

4. Подумайте, какие из следующих утверждений, касающихся событий в C#, верны, а какие – нет.

Обсудите на форуме.

A.Много подписчиков могут подписаться на одно событие +

B.События не могут нести контекстной информации вместе с собой. --

C.События нотифицируют подписчиков в том случае, если что-то произошло. +

D.Публикатор события определяет, когда событие будет вызываться. --

E.События базируются на делегатах. +

5. Обсудите преимущества использования событий.

События удобны тем, что однажды задав методы-обработчики для некоторого события,

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

Кроме того, использование событий избавляет разработчика от чрезмерного кодирования.

8. Потоки.

Надеюсь, вы успешно продвигаетесь в изучении продвинутых аспектов C#. Сегодня мы рассмотрим вопросы, связанные с последней и очень важной темой – использованием потоков в C#.

Рассмотрим следующий код:

// асинхронный процесс static void AsyncProcess()

{

// some code to process

}

....

// объявление потока

ThreadStart newProcessEntry = new ThreadStart(AsyncProcess); Thread newProcess = new Thread(newProcessEntry);

// старт потока

Каким из следующих способов можно запустить поток newProcess?

A. newProcess.Start();

+

B. newProcessEntry.Start();

--

C. newProcess.Start(newProcessEntry);

--

D. newProcessEntry.Run();

--

E. newProcess.Run();

--

Обсудите вашу точку зрения в форуме

Нечего обсуждать. Только вариант A допустим.

2. Напишите программу, создающую три потока одного типа. Каждому из потоков в параметре конструктора должна передаваться строка с его именем (например, «Первый»), затем он должен прокручиваться в цикле n раз (n задается в параметрах командной строки) и завершать свою работу.

При каждом проходе цикла поток должен печатать номер прохода цикла и свое имя, затем засыпать на какой-то промежуток времени и продолжать выполнение. При завершении поток должен печатать строку следующего формата: «Поток <Имя> завершен».

Пример:

using System;

using System.Threading; class MyThread

{

public int totalCount; public int count; string thrdName;

public MyThread(string name)

{

totalCount = 10;

count = 0; thrdName = name;

}

// Начало (входная точка) потока, public void Run()

{

Console.WriteLine(thrdName + " стартовал."); do

{

Thread.Sleep(700);//задержка между выводом

//каждой новой строки текущего потока Console.WriteLine("В потоке " + thrdName +

", count - " + count); count++;

}

while (count < totalCount); Console.WriteLine(thrdName + " завершен.\n");

}

}

class MultiThread

{

public static void Main()

{

Console.WriteLine("Основной поток стартовал."); // Сначала создаем объект класса MyThread.

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

{

MyThread mt = new MyThread("Поток № " + (i + 1)); // Затем из этого объекта создаем поток.

Thread newThrd = new Thread(new ThreadStart(mt.Run)); // Наконец, запускаем выполнение потока. newThrd.Start();

while (mt.count < mt.totalCount) Thread.Sleep(3000);//основной поток все время спит

//пока происходит вывод на консоль //текущего потока

}

Console.WriteLine("Основной поток завершен."); Console.Read();

}

}

3. Что такое «критическая секция» в терминах многопоточности? Приведите пример, в котором фигурирует критическая секция. Каким образом можно выделить критическую секцию в C#?

Критическая секция (Critical Section) – это некоторый участок кода, в котором некоторые потоки получают доступ к общему ресурсу (может быть переменная, метод). Таким образом,

данный ресурс доступен из других потоков. Критическая секция, если необходимо, может быть синхронизирована различными способами, один из них – использование конструкции lock().

Пример:

using System;

using System.Threading;

class Program

{

public static string WAIT = "";

public static void Main(string[] args)

{

Thread firstTHREAD = new Thread(new ThreadStart(Method_)); Thread secondTHREAD = new Thread(new ThreadStart(Method_l));

firstTHREAD.Start();

secondTHREAD.Start();

Console.Read();

}

public static void Method_()

{

lock (WAIT)

{

int i = 0; do

{

i ++; Thread.Sleep(500); Console.Write("_");

}

while (i < 10);

}

}

public static void Method_l()

{

lock (WAIT)

{

int i = 0; do

{

i++; Thread.Sleep(500); Console.Write("|");

}

while (i < 10);

}

}

}

4. Какие из следующих способов использования lock являются правильными?

A.public void InsertData()

{

try

{

lock{_cmdBCP.ExecuteNonQuery();}

}

catch

{

System.Console.WriteLine("Caught an exception");

}

finally

{

unlock;

}

}

B.public void InsertData()

{

try

{

lock(this) {_cmdBCP.ExecuteNonQuery();}

}

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]