Опубликован: 11.09.2006 | Уровень: специалист | Доступ: свободно
Лекция 1:

Введение в windows-формы

Лекция 1: 12345678910 || Лекция 2 >

Делегаты

Когда вы изучали синтаксис языка C#, то проходили понятие делегатов и событий. Изучение синтаксиса обычно проходит в консольных приложениях, где смысл использования делегатов и событий зачастую остается неясным. Между тем, это основа всего Windows-программирования. Рассмотрим вначале еще раз, что же это такое, а затем интерпретируем наши представления для создания Windows-форм.

В обычной жизни делегат — это дипломатический представитель, наделяемый особыми полномочиями своей организацией. Руководство организации заранее определяет, какие функции (методы) должен выполнить делегат: например, осуществить ежегодную проверку филиала, какие параметры следует передать (передать пакет документов) и что получить в ответ (получить ежегодную отчетность). Событием, инициализирующим работу делегата, может быть завершение рабочего года. Организация может располагать несколькими филиалами и не иметь представления на этапе планирования, куда отправится данный сотрудник в качестве делегата.

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

Запустите Visual Studio .NET. Создайте новое консольное приложение и назовите его Delegate. В классе Class1 объявляем делегат:

class Class1
  {
    delegate void Mydelegate (string s);

//…продолжение кода.
}

Синтаксис объявления делегата такой: сначала пишем ключевое слово delegate, затем — тип возвращаемого значения ( void в нашем примере), потом — произвольное имя делегата (у нас это Mydelegate ), после которого в круглых скобках перечисляем параметры (у нас только один параметр типа string ). Объявленный делегат появится в окне Class View (со специальным значком для делегатов) (рис. 1.30).

Созданный делегат в окне Class View

Рис. 1.30. Созданный делегат в окне Class View

В этом же классе добавим метод, который просто-напросто будет выводить некоторую переменную s на экран:

class Class1
	{
		delegate void Mydelegate( string s);

		static void Metod2В большинстве учебников по программированию, даже написанных на русском языке, принято давать названия объектов на английском языке. В результате достигается железная строгость изложения и путаница у новичков, которые тратят дополнительные усилия на разбор  названий, предопределенных средой слов, и поиском их перевода в Lingvo.  Конечно, в коммерческих распределенных проектах следует придерживаться общих правил, но  для большей ясности далее в некоторых местах  я буду писать "Metod"  а не "Method", "Chelovek" а не "Man". ( string s)
		{
			Console.WriteLine(s);
		}
//…продолжение кода.
}

Когда мы создаем класс, то вначале мы его объявляем, а затем создаем объект класса (или его экземпляр). Мы объявили делегат Mydelegate, а теперь создадим экземпляр этого делегата del:

[STAThread]
	static void Main(string[] args)
	{
		Mydelegate del = new Mydelegate(Metod);

//…продолжение кода.
}

Делегат Mydelegate связывается здесь с методом Metod. Теперь созданному экземпляру делегата передадим в качестве параметра переменную типа string, заключенную в кавычки:

[STAThread]
	static void Main(string[] args)
	{
  Mydelegate del = new Mydelegate(Metod);
  del("переменная типа string, которую принимает Metod, вызываемый делегатом del");
}

Запустите приложение (Ctrl+F5 — для консольных приложений — чтобы иметь возможность его разглядеть) (рис. 1.31).

Передача переменной делегатом методу

увеличить изображение
Рис. 1.31. Передача переменной делегатом методу

Как это работает? Экземпляру делегата del мы передаем переменную типа string, заключенную в скобках. Экземпляр del принадлежит делегату Mydelegate, который принимает метод Metod. Этот метод, в свою очередь, принимает переменную string s, которая выводится затем на экран. Обратите внимание, что сигнатуры делегата Mydelegate и метода Metod одинаковы! Если мы изменим тип принимаемой методом переменной на, например, int, среда выдаст ошибку.

using System;

namespace Delegate
{
	
	class Class1
	{
		delegate void Mydelegate( string s);

		static void Metod( string s)
		{
			Console.WriteLine(s);
		}


	
		[STAThread]
		static void Main(string[] args)
		{
			Mydelegate del = new Mydelegate(Metod);
			del("переменная типа string, которую принимает Metod, вызываемый делегатом del");
		}
	}
}
Листинг 1.1. Полный листинг проекта Delegate

Создайте новое консольное приложение. Назовите его Delegate2. Поскольку этот пример очень похож на предыдущий, просто приведу полный листинг с комментариями:

using System;

namespace Delegate2
{
	//Создаем новый класс chelovek
	class chelovek
	{
		//Объявляем переменную slovo
		public string slovo;
		//Создаем метод govorit
		public void govorit( string s)
		{
			Console.WriteLine( slovo + s);
		}
		class Class1
		{
			//Объявляем делегат Mydelegate,  который имеет ту же саму сигнатуру, что и метод  govorit
			delegate void Mydelegate(string s);

			[STAThread]
			static void Main(string[] args)
			{
				//Создаем экземпляр student класса chelovek
				chelovek student = new chelovek();
				//Создаем экземпляр del делегата  Mydelegate
				Mydelegate del = new Mydelegate(student.govorit);
				//Переменной slovo экземпляра student присваиваем значение "привет"
				student.slovo = "привет";
				// Экземпляру делегата del передаем переменную в кавычках
				del("  - Сказал студент через делегат");
				//Переменной slovo экземпляра student присваиваем значение "пока"
				student.slovo = "пока";
				// Экземпляру делегата del передаем переменную в кавычках
				del(" - Сказал студент через делегат");
			}
		}
	}
}
Листинг 1.2.

В этом примере мы дважды передаем переменную одному экземпляру делегата (рис. 1.32).

Передача переменной одному экземпляру делегата дважды

Рис. 1.32. Передача переменной одному экземпляру делегата дважды

Конечно же, здесь тот же самый результат можно было получить без всякого введения делегатов — просто инициализируя переменную slovo. Но пока для нас важно не найти наилучший способ получения заданного результата, а разобраться, как же работают делегаты. Создайте новое консольное приложение и назовите его Matem. Далее опять привожу полный код с комментариями:

using System;

namespace Matem
{
	//Создаем новый класс matematika
	class matematika
	{
		//Объявляем переменную a
		public int a;
		//Создаем метод calculate
		public void calculate()
		{
			int b = a*a;
			int c = a*a*a;
			int d = a*a*a*a;
			Console.WriteLine ("Само число: " + a + "\nКвадрат: " + b + "\nКуб: " + c + " \nЧетвертая степень:" + d);
		}
	}
	class Class1
	{
		[STAThread]
		static void Main(string[] args)
			{
			//Создаем экземпляр primer класса matematika
				matematika primer = new matematika();
			//Переменной a экземпляра primer присваиваем значение 2
				primer.a = 2;
			//Вызываем метод calculate
				primer.calculate();
				
			}
	}
}
Листинг 1.3.

Результатом выполнения этой программы будет вычисление квадрата, куба и четвертой степени значения переменной (рис. 1.33):

Результат приложения Matem

Рис. 1.33. Результат приложения Matem

Теперь создадим делегата и его экземпляр (можно создать новое консольное приложение — Matem2 — или изменить существующее):

using System;

namespace Matem2
{
	//Создаем новый класс matematika
	class matematika
	{
		//Объявляем переменную a
		public int a;
		//Создаем метод calculate
		public void calculate(int chislo)
		{
			int b = a*a;
			int c = a*a*a;
			int d = a*a*a*a;
			Console.WriteLine ("Само число: " + a + "\nКвадрат: " + b + "\nКуб: " + c + " \nЧетвертая степень:" + d);
		}
	}
	class Class1
	{
		delegate void Mydelegate(int chislo);
		[STAThread]
		static void Main(string[] args)
		{
			//Создаем экземпляр primer класса matematika
			matematika primer = new matematika();
			//Создаем экземпляр del делегата Mydelegate
			Mydelegate del = new Mydelegate(primer.calculate);
			//Переменной a экземпляра primer присваиваем значение 2
			primer.a = 2;
			// Экземпляру делегата del передаем переменную
			del(1);
			//Переменной a экземпляра primer присваиваем значение 3
			primer.a = 3;
			// Экземпляру делегата del передаем переменную
			del(2);
			//Переменной a экземпляра primer присваиваем значение 4
			primer.a = 4;
			// Экземпляру делегата del передаем переменную
			del(3);
				
		}
	}
}
Листинг 1.4.

Результатом выполнения этой программы будет последовательный вывод самого числа, его квадрата, куба и четвертой степени (рис. 1.34):

Результат приложения Matem2

Рис. 1.34. Результат приложения Matem2
Лекция 1: 12345678910 || Лекция 2 >
Елена Дьяконова
Елена Дьяконова

При нажатии на Сумма в примере ArbitraryMethod из Лекция 7, VS 2013 выдается ошибка: 

Необработанное исключение типа "System.InvalidOperationException" в System.Windows.Forms.dll

Дополнительные сведения: Недопустимая операция в нескольких потоках: попытка доступа к элементу управления "lblResult" не из того потока, в котором он был создан.

Затем:

Необработанное исключение типа "System.InvalidOperationException" в mscorlib.dll

Дополнительные сведения: Для каждой асинхронной операции метод EndInvoke может вызываться только один раз.

Александр Сороколет
Александр Сороколет

Свойство WindowState формы blank Maximized. Не открывается почемуто на всё окно, а вот если последующую форму бланк открыть уже на макс открывается :-/