Полное руководство. С# 4.0 - Шилдт Герберт
Шрифт:
Интервал:
Закладка:
Объявленные методы расширения вызываются для объекта таким же образом, каки методы экземпляра. Главное отличие заключается в том, что вызывающий объектпередается первому параметру метода расширения. Поэтому при выполнении выраженияval.AbsDivideBy(-2)
объект val передается параметру n метода расширения AbsDivideBy(), а значение-2 — параметру d.
Любопытно, что методы расширения Reciprocal() и AbsDivideBy() могутвполне законно вызываться и для литерала типа double, как показано ниже, поскольку они определены для этого типа данных.8.0.Reciprocal()8.0.AbsDivideBy(-1)
Кроме того, метод расширения RevCase() может быть вызван следующим образом."AbCDe".RevCase()
В данном случае возвращается строковый литерал с измененным на обратныйрегистром букв.PLINQ
В версии .NET Framework 4.0 внедрено новое дополнение LINQ под названиемPLINQ. Это средство предназначено для поддержки параллельного программирования. Оно позволяет автоматически задействовать в запросе несколько доступных процессоров. Подробнее о PLINQ и других средствах, связанных с параллельным программированием, речь пойдет в главе 24.
ГЛАВА 20. Небезопасный код, указатели, обнуляемые типы и разные ключевые слова
В этой главе рассматривается средство языка С#, которое обычно захватывает программистов врасплох.Это небезопасный код. В таком коде зачастую используются указатели. Совместно с небезопасным кодомуказатели позволяют разрабатывать на C# приложения,которые обычно связываются с языком C++, высокой производительностью и системным кодом. Более того, благодаря включению небезопасного кода и указателей в состав C#в этом языке появились возможности, которые отсутствуютв Java.
В этой главе рассматриваются также обнуляемые типы,определения частичных классов и методов, буферы фиксированного размера. И в заключение этой главы представлен ряд ключевых слов, не упоминавшихся в предыдущихглавах.Небезопасный код
В C# разрешается писать так называемый "небезопасный" код. В этом странном на первый взгляд утверждении нет на самом деле ничего необычного. Небезопаснымсчитается не плохо написанный код, а такой код, которыйне может быть выполнен под полным управлением в общеязыковой исполняющей среде (CLR). Как пояснялось вглаве 1, результатом программирования на C# обычно является управляемый код. Тем не менее этот язык программирования допускает написание кода, который не выполняется под полным управлением в среде CLR. Такой неуправляемый код не подчиняется тем же самым средствамуправления и ограничениям, что и управляемый код, и называется он небезопаснымпотому, что нельзя никак проверить, не выполняет ли он какое-нибудь опасное действие. Следовательно, термин небезопасный совсем не означает, что коду присущикакие-то изъяны. Это просто означает, что код может выполнять действия, которые неподлежат контролю в управляемой среде.
Если небезопасный код может вызвать осложнения, то зачем вообще создавать такой код? Дело в том, что управляемый код не позволяет использовать указатели. Еслиу вас имеется некоторый опыт программирования на С или C++, то вам должно бытьизвестно, что указатели представляют собой переменные, предназначенные для хранения адресов других объектов, т.е. они в какой-то степени похожи на ссылки в С#.Главное отличие указателя заключается в том, что он может указывать на любую область памяти, тогда как ссылка всегда указывает на объект своего типа. Но посколькууказатель способен указывать практически на любую область памяти, то существуетбольшая вероятность его неправильного использования. Кроме того, используя указатели, легко допустить программные ошибки. Именно поэтому указатели не поддерживаются при создании управляемого кода в С#. А поскольку указатели все-такиполезны и необходимы для некоторых видов программирования (например, утилитсистемного уровня), в C# разрешается создавать и использовать их. Но при этом всеоперации с указателями должны быть помечены как небезопасные, потому что онивыполняются вне управляемой среды.
В языке C# указатели объявляются и используются таким же образом, как и в C/C++.Если вы знаете, как пользоваться ими в C/C++, то вам нетрудно будет сделать это и в С#.Но не забывайте, что главное назначение C# — создание управляемого кода. А способность этого языка программирования поддерживать неуправляемый код следуетиспользовать для решения лишь особого рода задач. Это, скорее, исключение, чемправило для программирования на С#. По существу, для компилирования неуправляемого кода следует использовать параметр компилятора /unsafe.
Указатели составляют основу небезопасного кода, поэтому мы начнем его рассмотрение именно с них.Основы применения указателей
Указатель представляет собой переменную, хранящую адрес какого-нибудь другогообъекта, например другой переменной. Так, если в переменной х хранится адрес переменной у, то говорят, что переменная х указывает на переменную у. Когда указательуказывает на переменную, то значение этой переменной может быть получено илиизменено по указателю. Такие операции с указателями называют непрямой адресацией.Объявление указателя
Переменные-указатели должны быть объявлены как таковые. Ниже приведена общая форма объявления переменной-указателя:тип* имя_переменной;
где тип обозначает соотносимый тип, который не должен быть ссылочным. Это означает, что в C# нельзя объявить указатель на объект определенного класса. Соотносимый тип указателя иногда еще называют базовым. Обратите внимание на положениезнака * в объявлении указателя. Он должен следовать после наименования типа.А имя_переменной обозначает конкретное имя указателя-переменной.
Обратимся к конкретному примеру. Для того чтобы сделать переменную ip указателем на значение типа int, необходимо объявить ее следующим образом.int* ip;
А указатель типа float объявляется так, как показано ниже.float* fp;
Вообще говоря, если в операторе объявления после имени типа следует знак *, тоэто означает, что создается переменная типа указателя.
Тип данных, на которые будет указывать сам указатель, зависит от его соотносимоготипа. Поэтому в приведенных выше примерах переменная ip может служить для указания на значение типа int, а переменная fp — для указания на значение типа float.Следует, однако, иметь в виду, что указателю ничто не мешает указывать на что угодно.Именно поэтому указатели потенциально небезопасны.
Если у вас есть опыт программирования на С/С++, то вы должны ясно пониматьглавное отличие в объявлении указателей в C# и C/C++. При объявлении указателяв C/C++ знак * не разделяет список переменных в объявлении. Поэтому в следующейстроке кода:int* р, q;
объявляется указатель р типа int и переменная q типа int. Это равнозначно двумследующим объявлениям.int* р;int q;
А в C# знак * является разделительным, и поэтому в объявленииint* р, q;
создаются две переменные-указателя. Это равнозначно двум следующим объявлениям.int* р;int* q;
Это главное отличие следует иметь в виду при переносе кода C/C++ на С#.Операторы * и & в указателях
В указателях применяются два оператора: * и &. Оператор & является унарными возвращает адрес памяти своего операнда. (Напомним, что для унарного операторатребуется единственный операнд.) Например, в следующем фрагменте кода:int* ip;int num = 10;ip = #
в переменной ip сохраняется адрес памяти переменной num. Это адрес расположенияпеременной num в оперативной памяти компьютера. Он не имеет никакого отношения к значению переменной num. Поэтому в переменной ip содержится не значение10, являющееся исходным для переменной num, а конкретный адрес, по которому этапеременная хранится в оперативной памяти. Операцию & можно рассматривать каквозврат адреса той переменной, перед которой она указывается. Таким образом, приведенное выше присваивание словами можно описать так: "Переменная ip получаетадрес переменной num.
Второй оператор, *, является дополнением оператора &. Этот унарный оператор находит значение переменной, расположенной по адресу, на который указывает его операнд. Следовательно, этот оператор обращается к значению переменной, на которуюуказывает соответствующий указатель. Так, если переменная ip содержит адрес памятипеременной num, как показано в предыдущем примере, то в следующей строке кода:int val = *ip;