Смекни!
smekni.com

Введение в C#: классы (стр. 2 из 2)

Делегаты

Язык программирования C# хотя и допускает, но все же не поощряет использование указателей. В некоторых ситуациях бывает особенно трудно обойтись без указателей на функции. Для этих целей в C# реализованы так называемые делегаты (delegates), которые иногда еще называют безопасными аналогами указателей на функцию. Ниже приведен простейший пример использования метода-делегата:

using System;

delegate void MyDelegate();

class Example_5

{

static void Func()

{

System.Console.WriteLine(«MyDelegate.Func()»);

}

public static void Main()

{

MyDelegate f = new MyDelegate(Func);

f();

}

}

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

Еще одним отличием делегатов от простых указателей на функции является возможность вызова нескольких методов с помощью одного делегата. Рассмотримэтонаконкретномпримере:

using System;

delegate void MyDelegate(string message);

class Example_6

{

public static void Func1(string message)

{

Console.WriteLine(”{0}: MyDelegate.Func1”, message);

}

public static void Func2(string message)

{

Console.WriteLine(”{0}: MyDelegate.Func2”, message);

}

public static void Main()

{

MyDelegate f1, f2, f3;

f1 = new MyDelegate(Func1);

f2 = new MyDelegate(Func2);

f3 = f1 + f2;

f1(”Calling delegate f1”);

f2(”Calling delegate f2”);

f3(”Calling delegate f3”);

}

}

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

Calling delegate f1: MyDelegate.Func1

Calling delegate f2: MyDelegate.Func2

Calling delegate f3: MyDelegate.Func1

Calling delegate f3: MyDelegate.Func2

Из этого следует, что вызов метода-делегата f3, полученного с помощью операции сложения f1 + f2, приводит к последовательному выполнению обоих этих методов. Подобно применению операции сложения с целью объединения делегатов, можно использовать и операцию вычитания, которая, как нетрудно догадаться, выполняет обратное действие.

Способы передачи параметров

Анализируя особенности реализации классов языка C#, хотелось бы уделить внимание и способам передачи параметров метода по ссылке. Иногда возникает потребность в том, чтобы функция возвращала сразу несколько значений. Рассмотрим это на примере программы, вычисляющей квадратный корень:

using System;

class Example_7

{

static int GetRoots(double a, double b, double c,

out double x1, out double x2)

{

double d = b * b - 4 * a * c;

if (d > 0)

{

x1 = -(b + Math.Sqrt(d)) / (2 * a);

x2 = -(b - Math.Sqrt(d)) / (2 * a);

return 2;

} else

if (d == 0)

{

x1 = x2 = -b / (2 * a);

return 1;

} else

{

x1 = x2 = 0;

return 0;

}

}

public static void Main()

{

double x1, x2;

int roots = GetRoots(3, -2, -5, out x1, out x2);

Console.WriteLine(”roots #: {0}”, roots);

if (roots == 2)

Console.WriteLine(”x1 = {0}, x2 = {1}”, x1, x2);

else

if (roots == 1)

Console.WriteLine(”x = {0}”, x1);

}

}

Чтобы функция GetRoots возвращала оба корня уравнения (x1 и x2), мы указали транслятору, что переменные x1 и x2 должны быть переданы по ссылке, применив для этого параметр out. Обратите внимание на то, что нам не обязательно инициализировать переменные x1 и x2 перед вызовом функции GetRoots. Обозначив функцию ключевым словом out, мы добьемся того, что ее аргументы могут использоваться только для возврата какого-то значения, но не для его передачи внутрь функции. Таким образом, подразумевается, что переменная будет инициализирована в теле самой функции. В случае же, если нам по какой-то причине потребуется передать в параметре функции некоторое значение с возможностью его последующего изменения, можно воспользоваться параметром ref. Действие этого параметра очень похоже на действие out, но он позволяет еще и передавать значение параметра телу функции. Второе отличие ключевого слова ref состоит в том, что передаваемый параметр функции должен быть инициализирован предварительно.

Такой метод очень напоминает использование параметра var в списке аргументов функций, принятое в языке программирования Паскаль, и является еще одним отличием от языка Java, где параметры всегда передаются по значению.

Заключение

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

Списоклитературы

C# Language Specification. MicrosoftCorporation, 2000.

Гуннерсон Э. Введение в C#. СПб.: Питер, 2001.

Бесплатная версия .NET Framework SDK Beta 1: www.microsoft.com/downloads.

Обширнейшая информация по платформе .NET: www.gotdotnet.com.

Официальная конференция по языку C#: news://msnews.microsoft.com/ microsoft.public.dotnet.languages.csharp.

Инструментарий С#

Прежде чем начать работу с языком программирования C#, необходимо установить на компьютере набор инструментальных средств под названием .Net Framework SDK, бета-версия которого доступна для бесплатной загрузки непосредственно c Web-страницы корпорации Microsoft [3]. Кроме того, понадобится хороший текстовый редактор, поддерживающий синтаксически настраиваемый ориентированный режим (syntax highlight) и позволяющий выделять ключевые слова в исходных текстах того или иного языка программирования. Я рекомендую программу SharpDevelop (www.icsharpcode.net), распространяемую независимыми программистами на условиях лицензии GNU. В крайнем случае можно использовать любой редактор, способный работать с исходными текстами на языке Cи/Cи++, или даже обычный текстовый редактор Notepad.

Основные отличия типов struct и class
Тип class Тип struct
Представление экземпляра типа указатель значение
Местоположение объекта куча стек
Значение по умолчанию null заполняется нулями
Результат операции присваивания для экземпляров типа копируется указатель копируется сам объект
Базовый тип встроенный тип string встроенный тип int

C# и Java

Язык программирования C# часто и небезосновательно сравнивают с Java. Оба языка были созданы для аналогичных целей и имеют много общего, в том числе синтаксис, базирующийся на Cи++. В то же время есть и множество различий, относящихся к базовым типам, классам, способам передачи параметров, реализации интерфейсов и т. д. Основным же несходством между C# и Java является то, что Java-приложения работают со средой Java Frameworks and Runtime, а C#-приложения — со средой .NET Framework and Runtime. В полном объеме концепция .NET будет реализована только в новой операционной системе Windows XP (также известна как Whistler), хотя она уже около года активно продвигается корпорацией Microsoft. Похоже, если вы планируете создавать приложения, совместимые с платформой Microsoft, явно стоит поближе познакомиться с Microsoft .NET. Лучшим же языком для создания .NET-приложений, по утверждению самой корпорации Microsoft, является C#.

От двух до...

Исходный текст любого исполняемого приложения, написанного на языке программирования C#, содержит статический метод Main(), — аналог знакомой программистам Си/Си++ функции main(). Именно с этого метода начинается выполнение программы.

Что же произойдет, если исходный текст будет содержать два или более методов Main(), как показано ниже?

using System;

class SayHello

{

public static void Main()

{

Console.WriteLine(”Hello friend!”);

}

}

class SayBye

{

public static void Main()

{

Console.WriteLine(”Bye, bye...”);

}

}

Разумеется, компиляция этого примера вызовет сообщение об ошибке, так как классы SayHello и SayBye абсолютно «равноправны» с точки зрения транслятора. Процесс компиляции будет прерван. Однако существует специальный ключ компилятора /main, с помощью которого можно указать класс, содержащий нужный нам метод Main(). Вышеприведенный пример, откомпилированный с ключом /main:SayHello, напечатает сообщение:

Hello friend!

Если же откомпилировать тот же самый пример, указав ключ /main:SayBye, то текст будет иным:

Bye, bye...