Обзор языка C#
Пользовательские атрибуты
Естественно, что программист может определять и собственные, пользовательские атрибуты. Для этого достаточно создать класс, унаследованный от System.Attribute . В следующем примере мы покажем создание и использование атрибута, задающего гиперссылку на страничку с информацией о классе и его методах:
public class HelpUrlAttribute : System.Attribute { public HelpUrlAttribute(string url) { … } public string Url { get {…} } public string Tag { get {…} set {…} } } [HelpUrl("http://SomeUrl/MyClass")] class MyClass {} [HelpUrl("http://SomeUrl/MyClass", Tag="ctor")] class MyClass {}
Информация, записанная в пользовательских атрибутах, может быть использована во время исполнения программы с помощью механизма рефлексии (см. следующий пример).
Type type = typeof(MyClass); foreach(object attr in type.GetCustomAttributes() ) { if ( attr is HelpUrlAttribute ) { HelpUrlAttribute ha = (HelpUrlAttribute) attr; myBrowser.Navigate( ha.Url ); } }
Еще одним перспективным направлением для использования атрибутов является аспектно-ориентированное программирование - подход, в котором программист специально описывает степень участия каждой компоненты в общей системе в целях упрощения последующих изменений при сопровождении (подробнее об этом см. доклад Gregor Kiczales на ECOOP'99 Workshop on Aspect-Oriented Programming или страницу, посвященную этой методологии: http://aosd.net/)
Опасный код в С#
В общем и целом, C# достаточно успешно справляется с задачей скрытия излишних сложностей от программиста. Тем не менее, бывают случаи, когда программисту требуется полная свобода действий - например, речь может идти об ускорении каких-то фрагментов исходной программы или о необходимости работы со структурами, описанными в других языках и использующих указатели.
Специально для таких ситуаций в C# предусмотрена возможность написания опасного (unsafe) кода - для этого необходимо пометить метод или блок ключевым словом unsafe . Внутри опасных блоков можно применять операторы * и &, указатели, адресную арифметику и т.д., но, естественно, сгенерированная таким образом программа не будет гарантированно безопасной.
Еще одна особенность опасного кода - это возможность описания фиксированных (fixed) указателей. Дело в том, что прямой работе с указателями может помешать сборка мусора .NET, так как во время сборки мусора возможно перемещение всех объектов в куче. Понятно, что при перемещении объекта, с которым мы работаем через указатель, не может произойти ничего хорошего. Поэтому необходимо зафиксировать все указатели, с которыми работает опасный код; зафиксированные объекты сборщик мусора игнорирует.
Приведем пример использования опасного кода, который содержит строчку с целым строем звездочек:
class UnsafeTest { unsafe static void SquarePtrParam (int* p) { *p *= *p; } unsafe public static void Main() { int i = 5; SquarePtrParam (&i); Console.WriteLine (i); } }
Еще о C#
К сожалению, в этом кратком изложении очень многие особенности языка C# остались за кадром. Перечислим некоторые языковые механизмы, которые не были освещены в этой лекции:
- Исключения (впрочем, достаточно традиционные для современных языков: try - catch - finally )
- Встроенный механизм контроля версий (задача этого механизма - добиться, чтобы пользователям пришлось заменять или перекомпилировать старые библиотеки только в тех случах, когда это действительно необходимо)
- Возможность отключения контроля переполнения (ключевое слово unchecked )
- Вопросы взаимодействия с другими языками (например, межъязыковая разработка и отладка)
Кроме того, можно с уверенностью говорить, что C# будет развиваться и дальше, так как все языки программирования продолжают развиваться и C# находится на переднем крае современного языкотворчества. Например, в момент написании данного курса широко обсуждался вопрос о включении в C# поддержки параметрического полиморфизма (generics). Подобный механизм мог бы существенно расширить выразительные возможности, доступные программистам на C#.
C-бемоль
Для того, чтобы научиться написанию компиляторов, необходима практика. Однако, реальные языки программирования не очень хорошо подходят в качестве тренировочного полигона, так как при их реализации чаще всего приходится существенно усложнять структуру компилятора из-за всяких второстепенных особенностей языка.
Поэтому в качестве примера к нашему курсу мы разработали специальный язык, полученный путем усечения C#. Этот язык получил название C-бемоль, здесь мы вкратце опишем основные ограничения этого языка по сравнению с C# (более подробная спецификация этого языка приведена в приложении к курсу).
- Из типов данных поддержаны только следующие:
- встроенные типы int , char , float , bool , string , void
- классы (могут содержать поля и методы, но только вида public, private или static ; вложенные классы запрещены)
- интерфейсы (однако поддерживается только импорт существующих интерфейсов в целях совместимости с платформой .NET - описание новых интерфейсов запрещено)
- одномерные массивы
- тип данных "множество" ( set ), подобно одноименному типу в Паскале (этот тип введен в состав языка для того, чтобы продемонстрировать приемы реализации типов, отсутствующих в .NET)
- Из управляющих конструкций допускаются только if-then-else, while-do, do-while, присваивания, вызовы, пустой и составной операторы. Каждый оператор должен выдавать значение.
- Поддерживаются стандартные операции ( +, -, *, /, % ), причем тип операции всегда определяется по типу первого операнда.
- Перегрузка методов допускается, но при вызове список параметров должен определять вызываемый метод единственным образом.
- Все приведения должны быть записаны явным образом.
Курс сопровождается примером реализации C-бемоль, который может быть использован как дополнительный демонстрационный материал во время лекций.
Литература к лекции
- Т. Арчер "Основы C#", Русская редакция, 2001. 448 с.
- Э. Гуннерсон "Введение в C#", СПб.: Питер, 2001. 304 с.
- "Microsoft C# Language Specification", Microsoft Press, 2001. 412 p.
- J. Trupin "Sharp New Language. C# Offers the Power of C++ and Simplicity of Visual Basic", MSDN Magazine, September 2000.