Г. Шилдт - С# 3.0 Полное руководство. 2010 (1160798), страница 126
Текст из файла (страница 126)
Сначала в ией создается дерево выражений с помощью следующего оператора: Ехргевв1оп<тппс<ъпх, гпг, Ьоо1» ХвгасгогЕхр = (и, б) => (б != О) ? (и % б) == 0: га1ве В этом операторе конструируется представление лямбда-выражеиия в оперативной памяти. Как пояснялось выше, это представление доступно по ссылке, присваиваемой делегату 1зеассогехр. А в следующем операторе данные выражения преобразуются в исполняемый код: еопс<ъпс, Епс, ьоо1> 1веассог = 1вгассогехр.совр11е(); После выполнения этого оператора делегат 1эеассогехр может быть вызван, чтобы определить, является ли одно целое число множителем другого. Обратите также внимание иа то, что <Еопс<йпс, Епс, Ьоа1> обозначает тип делегата.
В этой форме делегата еппс указываются два параметра типа Епг и возвращаемый тип Ьоо1. В рассматриваемой здесь программе использована именно эта форма делегата гипс, совместимая с лямбда-выражеииями, поскольку для выражения требуются два параметра. Для других лямбда-выражеиий могут подойти иные формы делегата гипс в зависимости от количества требуемых параметров. Вообще говоря, конкретная форма делегата еппс должна удовлетворять требованиям лямбда-выражения. Методы расширения Как упоминалось выше, методы расширения предоставляют средства для расширения функций класса, пе прибегая к обычному механизму наследования.
Методы расширения создаются нечасто, поскольку механизм наследования, как правило, предлагает лучшее решение. Тем ие менее знать, как оии действуют, никогда не помешает. Ведь оии имеют существенное значение для 1.1ХЯ. Метод расширения является статическим и поэтому должен быть включен в состав статического, иеобобщеииого класса.
Тип первого параметра метода расширения определяет тип объектов, для которых этот метод может быть вызван. Кроме того, первый параметр может быть указан с модификатором сьъз. Объект, для которого вызывается метод расширения, автоматически передается его первому параметру. Ои ие передается явным образом в списке аргументов.
Следует, однако, иметь в виду, что метод расширения может по-прежиему вызываться для объекта аналогично методу экземпляра, несмотря иа то, что ои объявляется как статический. Ниже приведена общая форма метода расширения. всаг1с возрамаемьвт тип имя( СП1в тил вызывапа7его объекта оЬ, список параметров) Очевидно, что список параметров окажется пустым в отсутствие аргументов, за исключением аргумента, неявно передаваемого вызывающим объектом оЬ.
Не следует забывать, что первым параметром метода расширения является автоматически передавае- о54 Часть ). язык С» мый объект, длл которого вызывается этот метод. кьак правило, метод расширения становится открытым членом своего класса. В приведенном ниже примере программы создаются три простых метода расширения. // Создать и использовать ряд методов расширения. оя1по Зуягевп ягагас с1авя МуЕхгмегпя ( // Возвратить обратную величину числового значения типа бооЫе. риЫТс ягагас бооЫе Кес1ргоса1(СЫя боиЫе ч) ( гегогп 1.0 / чт ) // Изменить на обратный регистр букв в символьной // строке и возвратить результат.
рпЫТс зсасас ясгтпч кечСаяе(СЫз ясгтпо зсг) ( ясгапд сешр = ""; Гогеасп(спаг сЬ 1п ягг) ( 11(сьаг.тя'онег(сы ) сешр += сьаг.тооррег(сь) е1яе сешр ь= Спаг.ТоЬонег(сп)т ) гесигп сешрт ) // Возвратить абсолютное значение выражения и / с(. роЫТс згагтс с(ооЫе АЬявтч1беВу(СЫя с(оиЫе и, боиЫе б) ( гесигп мась.АЬя (и / сО; ) с1аяя Ехгоешо ( ягаСЬс чоьб Мвтп() ( бочЬ1е ча1 = В. От ягг1по ягг = "А1рпа Вега Оашша"т // Вызвать метод расширения КеЫр().
Сопяо1е.нгтсеъапе("Обратная величина (О) равна (1)", ча1, ча1.Кестргоса1()); // Вызвать метод расширения кечСаяе(). сопяо1е.хгасеьтпе(ясг +" после изменения регистра: " + ясг.кечсаяе()) // Использовать метод расширения АЬяоьчьиеВу()) Сопяо1е.нг1Сеъапе("Результат вызова " + "метода ча1.АЬяоачтбеВу(-2): ча1.АЬяО1чсбеву(-2))т ) ) Глава 19. 1)МО 655 Эта программа дает следующий результат: Обратная величина 8 равна 0.125 А1рьа Веса яаана после изменения регистра: аьРВА ьетА флмА Результат вызова метода ча1.АЬаоуч1беВу(-2): 4 В данном примере программы каждый метод расширения содержится в статическом классе муехемесьз. Как пояснялось выше, метод расширения должен быть объявлен в статическом классе.
Более того, этот класс должен находиться в области действия своих методов расширения, чтобы ими можно было пользоваться. (Имеиио поэтому в исходный текст программы следует включить пространство имен еузсет. В1пг(, так как зто дает возможность пользоваться методами расширения, связанными с 1ЛХО.) Объявленные методы расширения вызываются для объекта таким же образом, как и методы экземпляра. Главное отличие заключается в том, что вызывающий объект передается первому параметру метода расширения. Поэтому при выполнении выражения ча1 .
АЬ а 01ч1беву (-2 ) объект ча1 передается параметру и метода расширения АЬзпьчьбеВу (), а значение -2— параметру б. Любопытно, что методы расширения Весургоса1 () и АЬ801ч1с(еву () могут вполие законно вызываться и для литерала типа с(опЬ1е, как показано ниже, поскольку оии определены для этого типа данных. 8.0.кес1ргоса1() 8.0.АЬапьч1беВу(-1) Кроме того, метод расширения Вечсазе () может быть вызван следующим образом: "АЬСОе".Вечсаае() В данном случае возвращается строковый литерал с измененным иа обратный регистром букв. ГЛАВА Небезопасный код, указатели, обнуляемые типы и разные ключевые слова В этой главе рассматривается средство языка С№, которое обычно захватывает программистов врасплох.
Это небезопасный код. В таком коде зачастую используются указатели. Совместно с небезопасным кодом указатели позволяют разрабатывать иа С№ приложения, которые обычно связываются с языком С++, высокой производительностью и системным кодом. Более того, благодаря включению небезопасного кода и указателей в состав С№ в этом языке появились возможности, которые отсутствуют в 1ача. В этой главе рассматриваются также обиуляемые типы, определения частичных классов и методов, буферы фиксированного размера. И в заключение этой главы представлен ряд ключевых слов, ие упоминавшихся в предыдущих главах. Небезопасный код В С№ разрешается писать так называемый небезопасный код. В этом странном иа первый взгляд утверждении иет иа самом деле ничего необычного. Небезопасным считается ие плохо написанный код, а такой код, который ие может быть выполнен под полным управлением в общеязыковой исполияющей среде (С1 й).
Как пояснялось в главе 1, результатом программирования иа С№ обычно является управляемый код. Тем ие меиее этот язык программирования допускает написание кода, который ие выполняется под полным управлением в среде СЕВ. Такой неуправляемый код ие подчиняется тем же самым средствам управления и ограничениям, что и управляемый код, и называется ои небезопасным потому, что нельзя никак проверить, что ои ие выполняет какое-нибудь опасное действие. Следовательно, термин небезопасный совсем ие означает, что коду присущи какие-то изъяны.
Это просто означает, что код может выполнять действия, которые ие подлежат контролю в управляемой среде. 658 Часть Я Язык С№ Если небезопасный код может вызвать осложнения, то зачем вообще создавать такой код? Дело в том, что управляемый код не позволяет использовать указатели. Если у вас имеется некоторый опыт программирования на С или С++, то вам должно быть известно, что указапкели предстанляют собой переменные, предназначенные для хранения адресов других объектов, т.е. они в какой-то степени похожи на ссылки в С№. Главное отличие указателя заключается в том, что он может указывать на любую область памяти, тогда как ссылка всегда указывает на объект своего типа. Но поскольку указатель способен указывать практически на любую область памяти, то сущесэвует большая вероятность его неправильного использования.
Кроме того, используя указатели, легко допустить программные ошибки. Именно поэтому указатели не поддерживаются при создании управляемого кода в С№. Но поскольку указатели полезны и необходимы для некоторых видов программирования (например, утилит системного уровня), в С№ разремкается создавать и использовать их. Но при этом все операции с указателями должны быть помечены как небезопасные, поскольку они выполняются вне управляемой среды. В языке С№ указатели объявляются и используются таким же образом, как и в С/С++. Если вы знаете, как пользоваться ими в С/С-ь-ь, то вам нетрудно будет сделать это и в С№.
Но не забывайте, что главное назначение С№ — создание управляемого кода. А способность этого языка программирования поддерживать неуправляемый код следует использовать для решения лишь особого рода задач. Это скорее исключение, чем правило для программирования на С№. По существу, для компилирования неуправляемого кода следует использовать параметр компилятора /ипзаге. Указатели состанляют основу небезопасного кода, поэтому мы начнем его рассмотрение именно с них. Основы применения указателей Указатель представляет собой переменную, хранящую адрес какого-нибудь другого объекта, например другой переменной.
Так, если в переменной х хранится адрес пере-. менной у, то говорят, что переменная х указывает на переменную у. Когда указатель указывает на переменную, то значение этой переменной может быть получено или изменено по указателю. Такие операции с указателями называют непрямой адресацией. Обывление указателя Переменные-указатели должны быть объявлены как таковые. Ниже приведена общая форма объявления переменной-указателя. тип* нмя переменной; где тип обозначает соотносимый шип, который не должен быть ссылочным. Это означает, что в С№ нельзя объявить указатель на объект определенного класса.
Соотносимый тип указателя иногда еще называют базовым. Обратите внимание на положение знака * в объявлении указателя. Он должен следовать после наименования типа. А имя переменной обозначает конкретное имя указателя-переменной. Обратимся к конкретному примеру. Для того чтобы сделать переменную Гр указателем на значение типа хпг, необходимо объявить ее следующим образом: ъпк* ьрт А указатель типа г1оас объявляется так, как показано ниже. гтоас* грт Глава 20. Небезопасный код, указатели, обнуиввыыв типы и разные ключевые слова 669 Вообще говоря, если в операторе объявления после имени типа следует знак *, то это означает, что создастся переменная типа указателя. Тип данных, на которые будет указывать сам указатель, зависит от его соотносимого типа.