Интернет магазин китайских планшетных компьютеров



Компьютеры - Сравнение C Sharp и Java

24 апреля 2011


Оглавление:
1. Сравнение C Sharp и Java
2. Реализации
3. Использование



Правильный заголовок этой статьи — Сравнение C# и Java. Он показан некорректно из-за технических ограничений.

В этой статье сравниваются языки программирования C# и Java — два очень похожих между собой современных языка со сборкой мусора и компиляцией при выполнении с C-подобным синтаксисом. Настоящая страница даёт обзор сходства и различия этих однотипных языков. Читателю следует избегать искушения «вести счёт», а вместо этого обратить внимание на причины, по которым было сделано то или иное решение.

Язык

Синтаксис

Оба языка используют в качестве синтаксической основы язык программирования C. В частности, от него унаследованы без изменений:

  • обозначения начала/конца блока кода фигурными скобками;
  • обозначения, ассоциативность и приоритет большинства встроенных операций;
  • синтаксис описания и использования переменных и функций;
  • синтаксис всех основных конструкций: условного оператора, циклов, оператора множественного выбора;
  • отсутствие процедур;
  • наименования встроенных элементарных типов;
  • использование точки с запятой
  • … и много более мелких особенностей.

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

Синтаксических различий также достаточно.

Синтаксис Java C#
Импорт статических имён
позволяет отдельно импортировать некоторые или все статические методы и переменные класса и использовать их имена без квалификации в импортирующем модуле импортируется только сборка и при каждом использовании импортируемых статических имён требуется указывать класс
Константы в операторе switch должны относиться либо к целочисленному, либо к перечислимому типу можно использовать текстовые строки
Оператор перехода goto от использования goto сознательно отказались, однако существует механизм, позволяющий выйти на внешний цикл из вложенного, пометив его меткой и используя операторы break, continue вместе с меткой goto сохранился, его обычное использование — передача управления на разные метки case в операторе switch и выход из вложенного цикла
Константы констант как таковых нет, вместо них используются статические переменные класса с модификатором final — эффект от их использования точно такой же отдельное понятие именованной типизированной константы и ключевое слово const
Точность вычислений с плавающей точкой Java содержит конструкцию strictfp, гарантирующую одинаковые результаты операций с плавающей точкой на всех платформах. C# полагается на реализацию, гарантии строго одинаковых результатов вычислений нет.
Отключение проверок В Java все динамические проверки включаются/выключаются только на уровне пакета C# содержит конструкции checked и unchecked, позволяющие локально включать и выключать динамическую проверку арифметического переполнения.

В целом синтаксис C# несколько объёмнее и богаче, чем Java, в частности, там присутствуют такие особенности, как возможность разделения описания одного класса на несколько модулей, описание свойств, возможность управления виртуальностью методов.

Механизм работы с динамическими данными и сборка мусора

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

И в Java, и в C# есть сильные и слабые ссылки на объекты. Оба языка поддерживают методы-финализаторы. Из-за неопределённости момента удаления объекта финализаторы не могут использоваться для освобождения системных ресурсов, занятых объектом, что вынуждает создавать дополнительные методы для «очистки» объекта и вызывать их явно.

C# содержит в стандартной библиотеке интерфейс IDisposable и специальную конструкцию using, гарантирующую своевременный вызов метода очистки:

// DisposableClass реализует интерфейс IDisposable и описывает его метод Dispose
class DisposableClass : IDisposable
{
  public void Dispose
  {
    // ... Здесь освобождаются занятые экземпляром ресурсы
  }
}
 
using )
{
  // ... Код, использующий объект obj
}
// ... Здесь для объекта obj гарантированно уже вызван метод Dispose

В Java подобной конструкции нет и очистка объектов может быть выполнена только вручную:

class AnyClass {
  void clear {
    // ... Здесь находится код очистки 
  }
}
 
AnyClass obj =  new AnyClass;
try {
  // ... код, использующий объект obj
}
finally {
  obj.clear; // - явный вызов метода очистки объекта по завершении его использования
}

В Java 7 добавлена конструкция «try-with-resources», обеспечивающая автоматическую очистку полностью аналогично C#:

try ) {
    return br.readLine; 
}

При выходе из блока try все объекты, которым присвоено значение в его заголовке, будут очищены. Обязательное условие — классы этих объектов должны реализовывать системный интерфейс java.lang.AutoCloseable.

Java позволяет зарегистрировать слушателя, который будет получать сообщения, когда ссылка подвергается сборке мусора, что даёт улучшение производительности WeakHashMap.

C# позволяет отменить выполнение финализатора для данного объекта методом GC.SuppressFinalize. Это бывает полезным, поскольку финализация считается относительно дорогой операцией при сборке мусора, и объект с финализатором «живёт» дольше.

Объектные средства

Оба языка — объектно-ориентированные, с синтаксисом, унаследованным от C++, но значительно переработанным. Код и данные могут описываться только внутри классов.

Инкапсуляция

В Java модификатор protected в описании, помимо доступа из классов-потомков, разрешает доступ из всех классов, входящих в тот же пакет, что и класс-владелец.

В C# для объектов, которые должны быть видны в пределах сборки введён отдельный модификатор internal, а protected сохраняет свой изначальный смысл, взятый из C++ — доступ только из классов-потомков. Допускается комбинировать internal и protected — тогда получится область доступа, соответствующая protected в Java.

Внутренние классы

Оба языка позволяют определить класс внутри класса. Внутренние классы Java имеют доступ к нестатическим членам родительского класса, то есть «знают о this»; кроме того, внутри методов можно определять локальные классы, имеющие доступ по чтению к локальным переменным, и безымянные локальные классы, которые фактически позволяют создавать экземпляры объектов и интерфейсов, перекрывающие методы своего класса. На этом механизме в Java-программах может строиться обработка событий.

Подход C# более напоминает C++. Внутренние классы в C# имеют доступ только к статическим членам внешнего класса, а для доступа к нестатическим членам нужно явно указывать экземпляр внешнего класса. Локальные внутренние классы в C# не поддерживаются, обработка событий в нём не требует таких классов, поскольку строится на других механизмах.

Методы

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

В C# примитивные типы и структуры передаются по значению, остальные типы передаются по ссылке. C# также поддерживает явное описание передачи параметров по ссылке. При использовании out компилятор контролирует наличие в методе присваивания значения. В Java параметры метода передаются только по значению, но поскольку для экземпляров классов передаётся ссылка, ничто не мешает изменить в методе экземпляр, переданный через параметр.

Виртуальность методов

C# копирует концепцию виртуальных методов C++: виртуальный метод должен быть явно объявлен с ключевым словом virtual, прочие методы виртуальными не являются. C# требует явного объявления о перекрытии виртуального метода в производном классе ключевым словом override. Если требуется скрыть виртуальный метод, то есть просто ввести новый метод с тем же именем и сигнатурой, требуется указать ключевое слово new. Запрещается заслонять абстрактные методы. Объявление override-метода с ключевым словом sealed запрещает переопределять этот метод в классах-потомках, однако по-прежнему позволяет скрыть его.

В Java, наоборот, все открытые методы, кроме статических, являются виртуальными, а переопределить метод так, чтобы механизм виртуальности не включился, невозможно. Метод всегда виртуально перекрывает метод базового класса с теми же именем и сигнатурой, если он есть. Ключевое слово final позволяет запретить создание метода с такой же сигнатурой в производных классах.

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

Виртуальность всех методов потенциально небезопасна: если программист по ошибке объявит метод, который уже есть в базовом классе, не имея намерения его перекрывать, а просто не обратив внимания на то, что такой метод уже есть, то новый метод перекроет одноимённый метод в базовом классе, хотя это и не входит в намерения разработчика. В C# подобная ошибка тоже возможна, но компилятор выдаст предупреждение, что перекрывающий метод объявлен без new и override. В Java 5 появился аналогичный механизм — если метод перекрывает виртуальный метод класса-предка, компилятор выдаёт предупреждение; чтобы предупреждение не выдавалось, необходимо отметить перекрывающий метод аннотацией «@Override».

Типы данных

Примитивные типы

Оба языка поддерживают идею примитивных типов, и оба для трансляции примитивных типов в объектные обеспечивают их автоматическое «заворачивание» в объекты и «разворачивание». У C# имеется больше примитивных типов, чем у Java, за счёт беззнаковых целых типов, имеющихся парно ко всем знаковым, и специального типа decimal для высокоточных вычислений с фиксированной запятой.

В Java отказались от большинства беззнаковых типов ради упрощения языка. Одна из известных проблем с такими типами — сложность определения типа результата арифметических операций над двумя аргументами, один из которых является знаковым, другой — беззнаковым. Независимо от того, какие правила в отношении подобных операций примет язык, в некоторых ситуациях это приведёт к ошибкам» даст в результате не −10000, а 55536).

Структуры

C# позволяет создавать пользовательские типы-значения, используя ключевое слово struct. Это прямое наследие языка С++ от которого создатели Java сознательно отказались. В отличие от экземпляров классов, экземпляры типов-значений создаются не в куче, а на стеке вызовов или в составе экземпляра объекта, в котором они объявлены, что в некоторых случаях повышает производительность кода. С точки зрения программиста они подобны классам, но с несколькими ограничениями: у них не может быть явного конструктора без параметров, от них нельзя наследовать и они не могут явно наследоваться от других типов, но могут реализовывать интерфейсы. Кроме того, значения struct-типов поддерживают логику присваивания значения. Начиная с версии 1.6, в Java тоже имеется возможность создавать объекты на стеке, но происходит это автоматически без участия пользователя.

В Java для того, чтобы от класса нельзя было наследоваться, его можно объявить финальным final, тем самым получив частичный аналог конструкции struct. В C# для тех же целей используется модификатор sealed.

Перечислимые типы

Перечислимые типы в C# происходят от примитивных целочисленных типов. Допустимым значением перечислимого типа является любое значение лежащего в его основе примитивного, хотя для его присваивания может потребоваться явное приведение типа. Это позволяет комбинировать значения перечислимого типа побитовой операцией «или», если они являются битовыми флагами.

В Java перечислимые типы являются классами, их значения, соответственно — объектами. Тип-перечисление может иметь методы, реализовывать интерфейсы. Единственные допустимые значения типа — те, что перечислены в объявлении. Для комбинации их вместе как флагов требуется специальный объект набора перечислений. Возможно задавать разные реализации методов для каждого значения.

Массивы и коллекции

Массивы и коллекции тоже получили выражение в синтаксисе обоих языков, благодаря особой разновидности цикла for. В обоих языках массив является объектом класса Array, но в Java он не реализует какие-либо интерфейсы коллекций, хотя по массивам возможна итерация циклом for. Оба языка имеют в стандартной библиотеке классы типичных коллекций.

В Java могут быть объявлены, строго говоря, только одномерные массивы. Многомерный массив в Java — массив массивов. В C# есть как настоящие многомерные массивы, так и массивы массивов, которые в C# обычно называются «неровными», или «ступенчатыми». Многомерные массивы всегда «прямоугольные», в то время как массивы массивов могут хранить строки разной длины. Многомерные массивы ускоряют доступ к памяти, а неровные массивы работают медленнее, но экономят память, когда не все строки заполнены. Многомерные массивы требуют для своего создания лишь один вызов оператора new, а ступенчатые требуют явно выделять память в цикле для каждой строки.

Параметризованные типы

В обоих языках типы могут быть параметризованными, что поддерживает парадигму обобщённого программирования. Синтаксически определение типов достаточно близко — в обоих языках оно унаследовано от шаблонов C++, хотя и с некоторыми модификациями.

Шаблоны Java являются чисто языковой конструкцией и реализованы лишь в компиляторе. Компилятор заменяет все обобщённые типы на их верхние границы и вставляет соответствующее приведение типов в те места, где используется шаблон. В результате получается байт-код, который не содержит ссылок на обобщённые типы и их параметры. Такая техника реализации обобщённых типов называется затиранием типов. Это означает, что информация об исходных обобщённых типах во время выполнения недоступна, и обусловливает некоторые ограничения, такие как невозможность создавать новые экземпляры массивов из аргументов обобщённого типа. Среда выполнения Java не знакома с системой обобщённых типов, вследствие чего новым реализациям JVM понадобились лишь минимальные обновления для работы с новым форматом классов.

C# пошёл другим путём. Поддержка обобщённости была интегрирована в саму виртуальную среду выполнения, впервые появившись в .NET 2.0. Язык здесь стал лишь внешним интерфейсом для доступа к этим возможностям среды. Как и в Java, компилятор производит статическую проверку типов, но в дополнение к этому JIT производит проверку корректности во время загрузки. Информация об обобщённых типах полностью присутствует во время выполнения и позволяет полную поддержку рефлексии обобщённых типов и создание их новых реализаций.

Подход Java требует дополнительных проверок во время выполнения, не гарантирует, что клиент кода будет следовать соответствию типов, и не обеспечивает рефлексии для обобщённых типов. Java не позволяет специализировать обобщённые типы примитивными, в то время как C# обеспечивает обобщение как для ссылочных типов, так и для типов-значений, включая примитивные. Вместо этого Java предлагает использование завёрнутых примитивных типов в качестве параметров, но это даётся ценой дополнительного выделения динамической памяти. Как в Java, так и в C# специализации обобщённого типа на разных ссылочных типах дают одинаковый код , но для C# среда выполнения динамически генерирует оптимизированный код при специализации на типах-значениях, что позволяет их хранить и извлекать из контейнеров без операций за- и разворачивания.

Обработка событий

Java требует от программиста ручной реализации шаблона наблюдателя, хоть и обеспечивает некоторый синтаксический сахар в виде анонимных вложенных классов, что позволяет определить тело класса и тут же создать его экземпляр в одной точке кода.

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

Замыкания предлагаются к включению в Java SE 7. Эти замыкания, как делегаты в C#, имели бы полный доступ ко всем локальным переменным в данной области видимости, а не только доступ для чтения к переменным, помеченным словом final.

Перегрузка операций

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

Java не включает перегрузку операций во избежание злоупотреблений ею и для поддержания простоты языка.

Свойства

C# поддерживает концепцию «свойств» — псевдополей класса, к которым обеспечивается полностью контролируемый доступ путём создания методов для извлечения и записи значения поля. Описания свойств производятся с помощью конструкций get и set.

C# также включает так называемые индексаторы, которые можно считать особым случаем перегрузки операций, или параметризованными свойствами. Индексатор — это свойство с именем this, которое может иметь один или более параметров, причём индексы могут быть любого типа. Это позволяет создавать классы, экземпляры которых ведут себя подобно массивам:

myList = 5;
string name = xmlNode.Attributes;
orders = customerMap;

Использование свойств не одобряется некоторыми авторитетными программистами. В частности, Джеффри Рихтер пишет:

«Лично мне свойства не нравятся, и я был бы рад, если бы их поддержку убрали из Microsoft .NET Framework и сопутствующих языков программирования. Причина в том, что свойства выглядят как поля, на самом деле являясь методами.»

Согласно общепринятому в C# стилю именования, имена свойств визуально отличаются от полей тем, что начинаются с прописной буквы.

Условная компиляция

C#, в отличие от Java, поддерживает условную компиляцию с использованием директив препроцессора. В нём также есть атрибут Conditional, означающий, что указанный метод вызывается только тогда, когда определена данная константа компиляции. Таким путём можно вставлять в код, например, проверки допущений, которые будут работать только в отладочной версии, когда определена константа DEBUG. В стандартной библиотеке .NET таков метод Debug.Assert.

Java версий 1.4 и выше включает в язык возможность проверки допущений, включаемую во время выполнения. Кроме того, конструкции if с константными условиями могут разворачиваться на этапе компиляции. Существуют сторонние реализации препроцессоров для Java, они используются преимущественно при разработке приложений для мобильных устройств.

Пространства имён, сборки, пакеты

C# использует пространства имён, напоминающие одноимённый механизм C++. Каждый класс относится к некоторому пространству имён, те классы, для которых пространство имён не указано явно, относятся к безымянному пространству имён по умолчанию. Пространства имён могут быть вложенными друг в друга.

В Java имеются пакеты, отчасти похожие на пространства имён C#. Пакеты могут быть вложенными, каждый описываемый класс относится к некоторому пакету, при отсутствии явного указания пакета класс относится к глобальному безымянному пакету.

В обоих языках для обращения к объекту, объявленному в другом пространстве имён или пакете, нужно объявить в программе требуемый пакет как используемый. Обращение к объекту производится через квалифицированное имя, в качестве квалификатора используется имя пакета. Если требуется обращение к объекту без квалификации, программный модуль должен содержать директиву разыменования: using в C# и import в Java.

В C# пространства имён никак не связаны с компилированными модулями. Несколько сборок могут содержать одно и то же пространство имён, в одной сборке может объявляться несколько пространств имён, не обязательно вложенных. Модификаторы области видимости C# никак не связаны с пространствами имён. В Java объявленные в одном пакете классы по умолчанию образуют единый компилированный модуль. Модификатор области видимости по умолчанию ограничивает область видимости полей и методов класса пределами пакета.

В Java структура файлов и каталогов исходных текстов пакета по умолчанию связана со структурой пакета — пакету соответствует каталог, входящим в него подпакетам — подкаталоги этого каталога, файлы исходных текстов располагаются в каталогах, соответствующих пакету или подпакету, в который они входят. Таким образом, дерево исходных текстов повторяет структуру пакета. В C# местонахождение файла с исходным текстом никак не связано с его пространством имён.

Расположение исходного текста в файлах

В C# классы могут располагаться в файлах произвольным образом. Имя файла исходного кода никак не связано с именами определяемых в нём классов. Допускается расположить в одном файле несколько общедоступных классов. Начиная с версии 2.0, C# позволяет также разбить класс на два и более файла. Последняя особенность активно используется визуальными средствами построения интерфейса: часть класса, в которой находятся поля и методы, управляемые конструктором интерфейса, выделяются в отдельный файл, чтобы не загромождать автоматически генерируемым кодом файл, непосредственно редактируемый программистом.

В Java каждый файл может содержать только один общедоступный класс, причём Java требует, чтобы имя файла совпадало с именем этого класса, что исключает путаницу в именах файлов и классов. Более того, согласно рекомендуемому Sun соглашению об оформлении кода, размер файла исходного кода не должен превышать 2000 строк кода, поскольку в файле большего размера труднее разбираться. Большой размер файла также считается признаком плохого проектного решения.

Исключения

Оба языка поддерживают механизм обработки исключений, синтаксически оформленный совершенно одинаково: в языке имеется оператор генерации исключения throw и блок обработки исключений try{}catch{}finally{}, обеспечивающий перехват возникших внутри блока исключений, их обработку, а также гарантированное выполнение завершающих действий.

Java поддерживает проверяемые исключения: программист должен явно указать для каждого метода типы исключений, которые метод может выбросить, эти типы перечисляют в объявлении метода после ключевого слова throws. Если метод использует методы, выбрасывающие проверяемые исключения, он должен либо явно перехватывать все эти исключения, либо содержать их в собственном описании. Таким образом, код явно содержит перечень исключений, которые могут быть выброшены каждым методом. Иерархия типов исключений содержит также два типа, наследники которых не являются проверяемыми и не должны описываться. Они выделены для исключений времени выполнения, которые могут возникнуть в любом месте, либо обычно не могут быть обработаны программистом, и не должны указываться в объявлении throws.

C# проверяемые исключения не поддерживает. Их отсутствие является сознательным выбором разработчиков. Андерс Хейлсберг, главный архитектор C#, считает, что в Java они были в какой-то степени экспериментом и себя не оправдали.

Вопрос о пользе проверяемых исключений дискуссионный. Подробнее см. статью Обработка исключений.

Параллельное программирование

В целом механизмы параллельного программирования в C# аналогичны тем, что предоставляет Java, различие состоит в деталях реализации. В обоих случаях имеется библиотечный класс Thread, реализующий понятие «потока». Java предоставляет два способа создания собственных потоков: либо путём расширения класса Thread, либо путём реализации интерфейса Runnable. В обоих случаях программист должен определить наследуемый метод run, содержащий тело потока — код, который будет в нём выполняться. C# вместо этого использует механизм делегатов: для создания потока создаётся экземпляр стандартного класса Thread, которому передаётся в виде параметра конструктора делегат, содержащий метод — тело потока.

В обоих языках есть возможность создать синхронно исполняемый блок кода; в Java это делается с помощью оператора synchronized, в C# — оператором lock. В Java имеется также возможность объявлять синхронные методы, используя модификатор synchronized в заголовке описания метода. Такие методы при исполнении блокируют свой объект-хозяин. Аналогичная возможность в .NET реализуется с помощью атрибута реализации метода MethodImplAttribute MethodImplOptions.Synhronized, но, в отличие от Java, эта возможность формально не является частью языка C#.

В обоих языках доступны также идентичные средства синхронизации, основанные на отправке и ожидании сигнала от одного потока к другому. В Java это методы notify, notifyAll и wait, в C# — методы Pulse, PulseAll, Wait. Различие состоит лишь в том, что в Java эти методы реализуется в классе Object, поэтому для синхронизации не требуется никаких дополнительных библиотек, а в C# эти методы реализованы как статические в отдельном библиотечном классе Monitor. В C# стандартная библиотека содержит также несколько дополнительных примитивов синхронизации параллельного исполнения потоков: мьютексы, семафоры, синхронизирующие таймеры. С версии 1.5 в JDK SE включены пакеты java.util.concurrent, java.util.concurrent.atomic и java.util.concurrent.locks содержащие исчерпывающий набор средств для реализации параллельных вычислений.

Низкоуровневый код

Java Native Interface позволяет программам вызывать из Java низкоуровневые, системно-зависимые функции. Как правило, JNI используется при написании драйверов. При написании JNI-библиотек разработчик должен использовать специальный API, предоставляемый бесплатно. Выпускаются также специализированные библиотеки для взаимодействия Java с COM. В своё время MS ввела поддержку COM-объектов в Java на уровне языка в своей JVM, что послужило причиной отзыва Sun Microsystems лицензии на выпуск JVM у MS.

Технология Platform Invoke, реализованная в .NET, позволяет вызывать из C# внешний код, который Microsoft называет неуправляемым. Через атрибуты в метаданных программист может точно управлять передачей параметров и результатов, избегая таким образом необходимости дополнительного кода адаптации. P/Invoke предоставляет почти полный доступ к процедурным API, но не даёт прямого доступа к библиотекам классов C++.

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

C# разрешает ограниченное использование указателей, которые проектировщики языков зачастую считают опасными. Подход C# в этом деле — требование ключевого слова unsafe при блоках кода или методах, использующих эту возможность. Это ключевое слово предупреждает пользователей такого кода о его потенциальной опасности. Оно также требует явного задания компилятору опции /unsafe, которая по умолчанию выключена. Такой «небезопасный» код используется для улучшения взаимодействия с неуправляемым API и иногда для повышения эффективности определённых участков кода.

C# также позволяет программисту отключить нормальную проверку типов и другие возможности безопасности CLR, разрешая использование переменных-указателей при условии применения ключевого слова unsafe. JNI, P/Invoke и unsafe-код одинаково рискованны, чреваты дырами в безопасности системы и нестабильностью приложения. Преимуществом управляемого unsafe-кода над P/Invoke или JNI является то, что он позволяет программисту продолжать работать в знакомой среде C# для выполнения задач, которые при других методах потребовали бы вызова неуправляемого кода, написанного на другом языке.



Просмотров: 4740


<<< Сервлет
OpenOffice.org Draw >>>