Язык C#Источник: КомпьютерПресс, 9'2000 Алексей Федоров
Оглавление
В этом обзоре мы познакомимся с новым языком программирования C# (читается C Sharp - си-диез, то есть нота «си», повышенная на полтона), недавно объявленным фирмой Microsoft. У читателя может возникнуть вполне логичный вопрос: зачем нужен еще один язык программирования, когда у Microsoft есть и Basic, и C/C++, и Java, не говоря уже о подмножестве Visual Basic - Visual Basic for Application и скриптовых языках VBScript и JScript? По словам менеджеров фирмы Microsoft, язык C# создавался в первую очередь для разработчиков, использующих C и С++, чтобы позволить им более эффективно создавать Internet-приложения. Так, C# будет тесно интегрирован с языком XML, протоколом SOAP и другими Web-технологиями (на момент написания данного обзора детали этой интеграции объявлены не были). Очевидно, что реализовать какие-либо новые возможности на уровне языка в языках С/С++ нельзя, так как в этом случае был бы нарушен ANSI-стандарт; язык Visual Basic не предоставляет ряда возможностей С/С++; с языком Java также невозможно обращаться как со своим собственным. Поэтому фирма Microsoft выбрала иной путь - создала новый язык. Язык C# - это простой объектно-ориентированный язык, напоминающий С++ и Java, но при этом в нем нет некоторых конструкций. Например, C# не поддерживает макросов, шаблонов, директив #include , а также различных способов доступа к объектам - вместо того, чтобы думать над тем, когда использовать точку ( . ), ссылку ( -> ) или оператор области действия ( :: ), вы всегда используете точку. Для того чтобы снизить возможность внесения ошибок в создаваемый код, в C# введен механизм сборки мусора (garbage-collection): вас больше не должны заботить указатели, ссылки или утечки памяти - за всем этим следит исполняющее ядро языка. В языке нет глобальных переменных, множественного наследования и ряда других конструкций. Язык C#, вместе с Visual Basic (Visual Basic .NET, объединившем в себе функциональность Visual Basic и VBScript), Visual C++ и скриптовым языком JScript (JScript .NET), будет входить в состав Microsoft Visual Studio .NET (ранее называлась Visual Studio 7). Все эти языки обеспечивают доступ к платформе Microsoft .NET (ранее эта платформа называлась Next Generation Windows Services NGWS), которая содержит общее исполняющее ядро и обширную библиотеку классов. Ядро работает на уровне общего языка, известного под названием Common Language Subset (CLS, также называется Common Language Specification), который обеспечивает взаимодействие между всеми языками и библиотекой классов. Для разработчиков это означает, что C# будет иметь доступ ко всем средствам, знакомым разработчикам на Visual Basic и Visual C++. Отметим, что в составе Microsoft Visual Studio .NET нет средства разработки на языке Java - Microsoft Visual J++. По мнению многих аналитиков, Microsoft Visual J++, тесно связанный с платформой Windows, не получил широкого распространения, так как не обладал никакими преимуществами перед с Visual Basic и Visual C++. Также следует вспомнить о судебном иске фирмы Sun по поводу нарушения фирмой Microsoft лицензионного соглашения и введения расширений в язык; обсуждение виртуальной машины Microsoft и т.п. Более того, лицензия Microsoft на язык Java заканчивается в марте будущего года и скорее всего продлена не будет. Фирма Rational Software работает над компилятором языка Java, который будет интегрироваться с Visual Studio .Net. Дата выпуска этого компилятора пока не объявлена. Но вернемся к теме нашего обзора - языку C#. По традиции, заведенной еще Керниганом и Ричи в далеких уже 70-х, принято знакомиться с возможностями языка, написав программу, выводящую на экран фразу «Hello, world». На языке C# такая программа выглядит следующим образом: using System; class Hello { static void Main() { Console.WriteLine("Hello, world"); } } Давайте подробно рассмотрим каждую строку этой программы. Директива using System указывает на то, что мы обращаемся к пространству имен (namespace) System , предоставляемому ядром Microsoft .NET. Это пространство имен содержит класс Console , используемый в методе Main() . Пространства имен служат для логической организации элементов библиотеки классов. Директива using позволяет использовать члены пространства имен более простым образом. Так, ниже мы используем вызов Console.WriteLine , который является сокращенным вариантом вызова System.Console.WriteLine . Отметим, что эта концепция схожа с директивой Use в языке Object Pascal. Функция Main является статическим членом класса Hello . Как мы отметили выше, глобальных переменных в языке не существует - переменные и функции всегда объявляются внутри объявлений классов или структур. Строка «Hello, world» выводится на экран методом WriteLine класса Console . Здесь мы используем единую библиотеку классов, доступную из C#, Visual Basic и Visual C++. Язык C# не имеет собственной библиотеки классов. Программы на C# сохраняются в файлах с расширением .cs - наша программа может быть сохранена в файле hello.cs, будучи откомпилированной пакетным компилятором csc : csc hello.cs После того как мы получили некоторое представление о языке C#, давайте рассмотрим его основные конструкции более подробно. Типы данныхВ языке C# существует две разновидности типов данных: значимые типы ( value types ) и ссылочные типы ( reference types ). К значимым типам относятся простые типы ( char , int , float ), перечисляемые типы ( enum ) и структуры ( struct ), то есть типы, напрямую содержащие данные. Ссылочными типами являются классы, интерфейсы, массивы (поддерживаются одно- и многомерные массивы) и делегаты: типы, хранящие ссылки на объекты. Для задания новых типов данных разработчики могут использовать перечисления и структуры, а также классы, интерфейсы и делегатов. Предопределенные типы данныхЯзык C# содержит ряд предопределенных значимых и ссылочных типов, большинство из которых пришло из языков С/С++. К предопределенным значимым типам относятся целочисленные типы (со знаком - sbyte , short , int , long и без знака - byte , ushort , uint , ulong ), числа с плавающей точкой ( float и double ) и типы bool , char и decimal . Предопределенные ссылочные типы представлены типами object и string . Тип object является универсальным базовым типом для всех остальных типов. Для каждого предопределенного типа существует ключевое слово, которому соответствует системное определение. Например, ключевому слову int соответствует определение System.Int32 . В языке C# все типы данных, включая и значимые типы, могут рассматриваться как объекты. Это позволяет вызывать методы даже таких примитивных типов, как int . Например: using System; class Demo { static void Main() { Console.WriteLine(3.ToString()); } } Здесь мы используем метод ToString для вывода значения константы типа int . Согласитесь, что это напоминает язык Java. ВыраженияБольшинство выражений в C# унаследовано из языков С/С++, но здесь есть ряд добавлений и изменений. Отметим, что поддерживаются выражения с меткой и оператор goto (можно ожидать новую волну обсуждений по поводу этого оператора, но мне кажется, что он будет существовать до тех пор, пока существует ассемблерная инструкция JMP ), объявления локальных констант и локальных переменных перечислением ( const int b = 2, c = 3; ), вычисляемые выражения и функции, операторы switch , while , do , for , foreach (для перебора элементов коллекций), break , continue , return , throw , try , checked/unchecked (для контроля переполнения при выполнении арифметических операций и преобразования целочисленных типов) и lock . КлассыОбъявления классов используются для задания новых ссылочных типов. Язык C# не поддерживает множественного наследования, но класс может реализовать несколько интерфейсов. Членами класса могут быть константы, поля, методы, свойства, индексаторы, события, операторы, конструкторы, деструкторы и вложенные описания типов. Каждый член класса может иметь описатель доступа.
СтруктурыСтруктуры во многом схожи с классами - они могут реализовывать интерфейсы, могут иметь члены, но отличаются от классов тем, что являются значимыми, а не ссылочными типами и не поддерживают наследования. ИнтерфейсыИнтерфейсы (ключевое слово interface ) служат для описания способа обращения к классу или структуре. Интерфейсы могут содержать методы, свойства, индексаторы и события. Например, ниже показан интерфейс, содержащий индексатор, событие, метод и свойство. interface Idemo { string this[int index] { get; set; } event EventHandler E; void F(int value); string P { get; set; } } public delegate void EventHandler(object sender, Event e); Интерфейсы могут задавать множественное наследование; классы и структуры могут использоваться для реализации нескольких интерфейсов. ДелегированиеДелегирование позволяет адресовать одни и те же указатели на функции из языка C++ и других языков. В отличие от указателей на функции, делегаты являются объектно-ориентированными и типизированными. Делегаты - это ссылочные типы, созданные на базе общего класса System.Delegate . ПеречислениеТип данных enum используется для описания группы связанных символических констант. Этот тип данных делает код более простым и позволяет использовать визуальные средства, облегчающие написание такого кода. Пространства именВ программах на C# используются пространства имен. Эти пространства имен служат как для внутренней, так и для внешней организации системы - для подачи способа представления программных элементов для программ. В рассмотренной выше демонстрационной программе мы уже видели, как используется пространство имен. Для реализации пространства имен используется ключевое слово namespace : namespace Microsoft.CSharp.Introduction { public class HelloMessage { public string GetMessage() { return "Hello, world"; } } } Реализованное выше пространство имен имеет имя Microsoft.CSharp.Introduction - пространство имен Introduction содержится в пространстве имен CSharp , которое, в свою очередь, содержится в пространстве имен Microsoft . Эта иерархия показана ниже: namespace Microsoft { namespace CSharp { namespace Introduction {....} } } Теперь мы можем переписать нашу демонстрационную программу так, чтобы она использовала класс HelloMessage . Можно использовать либо полное имя класса - в нашем случае это: Microsoft.CSharp.Introduction.HelloMessage using Microsoft.CSharp.Introduction; class Hello { static void Main() { HelloMessage m = new HelloMessage(); System.Console.WriteLine(m.GetMessage()); } } В языке C# также можно использовать псевдонимы. Это бывает полезно в тех случаях, когда возникают противоречия в именованиях методов в двух или более библиотеках. СвойстваСвойство - это именованный атрибут, ассоциированный с объектом или классом. Примерами свойств могут быть длина строки, размер шрифта, заголовок окна, имя клиента и т.п. Свойства являются расширениями полей: и те и другие - это именованные члены с ассоциированными типами, а синтаксис доступа к полям и свойствам одинаков. В отличие от полей свойства имеют механизм для ассоциации действий по чтению и записи атрибутов объекта. Для задания свойств в языке C# используется специальный синтаксис. Первая часть объявления свойства схожа с объявлением поля, вторая часть включает описание способа получения и установки значения - они называются get accessor и set accessor . Объявление свойства Caption класса Button показано ниже: public class Button: Control { private string caption; public string Caption { get { return caption; } set { caption = value; Repaint(); } } } Свойства доступны для чтения и для записи. При обращении к значению свойства вызывается механизм чтения (get accessor) , при изменении значения вызывается механизм записи ( set accessor ). Как мы отмечали выше, доступ к свойствам аналогичен доступу к полям: Button b = new Button(); b.Caption = "ABC"; // установить заголовок string s = b.Caption; // получить заголовок b.Caption += "DEF"; // получить и установить ИндексаторыЕсли свойства в языке C# можно рассматривать как расширенные поля, то индексаторы - это расширенные массивы. В качестве примера рассмотрим интерфейсный элемент ListBox , в котором отображается набор строк. Предположим, что класс ListBox «хочет» сделать доступным массив, в котором хранятся строки, а также «хочет», чтобы содержимое интерфейсного элемента автоматически обновлялось при изменении массива строк. Для решения этой задачи можно использовать индексатор. Синтаксис объявления индексатора схож с синтаксисом объявления свойства - отличием является то, что индексаторы безымянны (используется ключевое слово this ), а дополнительные параметры указываются в квадратных скобках: public class ListBox: Control { private string[] items; public string this[int index] { get { return items[index]; } set { items[index] = value; Repaint(); } } } Ниже показан пример использования индексатора. ListBox listBox = ...; listBox[0] = "hello"; Console.WriteLine(listBox[0]); СобытияСобытия позволяют классу объявлять нотификации, к которым клиенты могут присоединять исполняемый код в виде обработчиков событий. Объявление события во многом схоже с объявлением поля, за исключением того, что здесь используется ключевое слово event . В приведенном ниже примере показано объявление события Click типа EventHandler для класса Button . public delegate void EventHandler(object sender, Event e); public class Button: Control { public event EventHandler Click; public void Reset() { Click = null; } } Внутри класса Button член Click соответствует полю типа EventHandler , извне же член Click может использоваться только в левой части операторов += и -= . Это ограничение позволяет клиентскому коду только добавлять или удалять обработчики событий. В приведенном ниже примере клиентский код в классе Form1 добавляет обработчик события Button1_Click для события Click класса Button . В методе Disconnect обработчик события удаляется: using System; public class Form1: Form { public Form1() { // Добавить Button1_Click как обработчик // события Button1.Click Button1.Click += new EventHandler(Button1_Click); } Button Button1 = new Button(); void Button1_Click(object sender, Event e) { Console.WriteLine("Button1 was clicked!"); } public void Disconnect() { // Удалить обработчик события Button1.Click Button1.Click - = new EventHandler(Button1_Click); } } АтрибутыC# является процедурным языком и, как все процедурные языки, содержит некоторые декларативные элементы. Например, доступность метода класса описывается атрибутами public , protected , internal , protected internal или private . Поддержка атрибутов в языке C# позволяет программистам создавать новые типы декларативной информации и извлекать эту информацию во время работы программы. Например, можно объявить атрибут HelpAttribute , который будет использоваться для ассоциирования классов и методов с документацией по ним: [AttributeUsage(AttributeTargets.All)] public class HelpAttribute: System.Attribute { public HelpAttribute(string url) { this.url = url; } public string Topic = null; private string url; public string Url { get { return url; } } } Выше показана реализация атрибута класса HelpAttribute , имеющего один позиционный параметр (string url) и один именованный аргумент (string Topic) . Позиционные параметры служат для задания параметров конструкторов в классах с атрибутами, именованные - для реализации свойств с возможностью чтения и записи. Использование атрибутов показано ниже. [Help("http://www.mycompany.com/…/Class1.htm")] public class Class1 { [Help("http://www.mycompany.com/…/Class1.htm", Topic ="F")] public void F() {} } Для доступа к атрибутам во время исполнения программы используются встроенные механизмы ядра Microsoft .NET. Например: using System; class Test { static void Main() { Type type = typeof(Class1); object[] arr = _ type.GetCustomAttributes(typeof(HelpAttribute)); if (arr.Length == 0) Console.WriteLine("Class1 has no Help attribute."); else { HelpAttribute ha = (HelpAttribute) arr[0]; Console.WriteLine("Url = {0}, Topic = {1}", _ ha.Url, ha.Topic); } } } ЗаключениеВ данном обзоре мы познакомились с новым языком C#, который является одним из основных программных элементов новой платформы Microsoft .NET. Мы рассмотрели основные возможности этого языка, обсудили синтаксические конструкции и показали несколько примеров их использования. Язык C# еще находится в стадии разработки, и еще не все его возможности реализованы. После завершения работы над спецификацией языка она будет передана в комитет ECMA (http://www.ecma.org), который занимается различными стандартами, в частности стандартом языка JavaScript (ECMAScript). В заключение отметим, что в прошлом году фирма Sun направляла в комитет ECMA спецификацию языка Java, но отозвала ее (сославшись на то, что в результате процесса стандартизации Sun потеряет возможность управлять развитием языка), и теперь развитием и стандартизацией Java занимается Java Community Process. Несколько фактов о языке C#Язык C# вобрал в себя лучшие черты языков С++ и Java; одним из его разработчиков был Андерс Хейлсберг (Anders Heilsberg) - создатель TurboPascal и главный архитектор Delphi (до версии 4.0).
|