Язык C#
В этом обзоре мы познакомимся с новым языком программирования 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
превратится в исполняемый
файл hello.exe, запуск которого на выполнение
приведет к выводу строки «Hello, world» на экран.
После того как мы получили некоторое представление о языке 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# не поддерживает множественного наследования, но класс может реализовать несколько интерфейсов. Членами класса могут быть константы, поля, методы, свойства, индексаторы, события, операторы, конструкторы, деструкторы и вложенные описания типов. Каждый член класса может иметь описатель доступа.
Описатель | Назначение |
---|---|
public | Члены доступны из всего кода |
protected | Члены доступны только из наследуемых классов |
internal | Члены доступны только из данного класса |
protected internal | Члены доступны только из наследуемых классов данного класса |
private | Члены доступны только из данного класса |
Структуры
Структуры во многом схожи с классами — они могут реализовывать интерфейсы, могут иметь члены, но отличаются от классов тем, что являются значимыми, а не ссылочными типами и не поддерживают наследования.
Интерфейсы
Интерфейсы (ключевое слово 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, как показано
ниже.
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# можно получить на Web-сайте фирмы Microsoft (http://msdn.microsoft.com).
КомпьютерПресс 9'2000