1629295407-c61bfe4caba98380ea3e7cdae6295416 (846200), страница 82
Текст из файла (страница 82)
В результате будет установлен уровень доступа protected internal,который можно применять только к членам класса. К члену, объявленному сиспользованием пары модификаторов protected internal, можно получить доступвнутри его компоновочного файла. Он также доступен для производных типов.Рассмотрим пример использования модификатора доступа internal.// Использование модификатора доступа internal.using System;class InternalTest {internal int x;}class InternalDemo {public static void Main() {InternalTest ob = new InternalTest();ob.x = 10; // Доступ возможен: x — в том же файле.}}Console.WriteLine("Значение ob.x: " + ob.x);Внутри класса InternalTest поле x объявлено с использованием модификаторадоступа internal.
Это означает, что оно доступно в программе, как показано в кодекласса InternalDemo, но недоступно вне ее.448Часть I. Язык C#Полныйсправочник поГлава 17Динамическаяидентификация типов,отражение и атрибутыЭта глава посвящена трем взаимосвязанным мощным средствам C#: динамическойидентификации типов, отражению и атрибутам. Динамическая идентификация типов— это механизм, который позволяет распознать тип данных во время выполненияпрограммы. Отражение представляет собой средство, с помощью которого можнополучить информацию о типе.
Используя эту информацию, во время выполненияпрограммы можно создавать объекты, а затем работать с ними. Это средство обладаетбольшой эффективностью, поскольку оно позволяет динамически расширять функции,выполняемые программой. Атрибут предназначен для описания элементов C#-программы.Например, можно определить атрибуты для классов, методов и полей.
Информацию обатрибутах можно запрашивать и получать во время выполнения программы. Для поддержкиатрибутов используются средства как динамической идентификации типов, так и отражениясоответствующей информации.Динамическая идентификация типовДинамическая идентификация типов (runtime type identification — RTTI) позволяетопределить тип объекта во время выполнения программы, что необходимо во многихситуациях.
Например, можно совершенно точно узнать, на объект какого типа вдействительности указывает ссылка на базовый класс. Еще одно применение RTTI —заранее проверить, удачно ли будет выполнена операция приведения типа, не допустиввозникновения исключения, связанного с некорректно заданной операцией приведениятипа.
Динамическая идентификация типов также является ключевым компонентом средстваотражения (информации о типе).В C# предусмотрено три ключевых слова, которые поддерживают динамическуюидентификацию типов: is, as и typeof. Рассмотрим назначение каждого из них вотдельности.Проверка типа с помощью ключевого слова isС помощью оператора is можно определить, имеет ли рассматриваемый объектзаданный тип. Общая форма его записи имеет следующий вид:выражение is типЗдесь тип элемента выражение сравнивается с элементом тип. Если тип элементавыражение совпадает (или совместим) с элементом тип, результат выполнения операциипринимается равным значению ИСТИНА.
В противном случае — значению ЛОЖЬ.Следовательно, если результат истинен, выражение можно привести к типу, заданномуэлементом тип.Рассмотрим пример использования оператора is.// Демонстрация выполнения оператора is.using System;class A {}class B : A {}class UseIs {public static void Main() {A a = new A();B b = new B();450Часть I. Язык C#}}if(a is A) Console.WriteLine("Объект а имеет тип А.");if(b is A)Console.WriteLine("Объект b совместим с типом А, " +"поскольку его тип выведен из типа А.");if(a is B)Console.WriteLine("Этот текст не будет отображен, " +"поскольку объект а не выведен из класса B.");if(b is B)Console.WriteLine("Объект b имеет тип B.");if(a is object) Console.WriteLine("a -- это объект.");Результаты выполнения этой программы таковы:Объект аОбъект bОбъект bа -- этоимеет тип А.совместим с типом А, поскольку его тип выведен из типа А.имеет тип B.объект.Несмотря на то что все сообщения в этой программе говорят сами за себя, некотрыеиз них все же требуют пояснений.
Обратите внимание на следующую инструкцию:if(b is А)Console.WriteLine("Объект b совместим с типом А, " +"поскольку его тип выведен из типа А.");В данном случае if-инструкция выполнилась успешно, поскольку переменная bявляется ссылкой типа в, который выведен из типа А. Следовательно, объект b совместим стипом А. Однако обратное утверждение не является справедливым. При выполнении строкикодаif(a is B)Console.WriteLine("Этот текст не будет отображен, " +"поскольку объект а не выведен из класса B.");if-инструкция успехом не увенчается, поскольку объект а имеет тип А, который невыведен из типа B. Следовательно, объект a и класс B несовместимы по типу.Использование оператора asИногда во время работы программы требуется выполнить операцию приведениятипов, не генерируя исключение в случае, если попытка окажется неудачной.
Для этогопредусмотрен оператор as, формат которого таков:выражение as типНетрудно догадаться, что используемый здесь элемент выражение участвует впопытке приведения его к типу, заданному элементом тип. В случае успешноговыполнения этой операции возвращается ссылка на тип. В противном случае возвращаетсянулевая ссылка.Оператор as в некоторых случаях предлагает удобную альтернативу оператору is.Рассмотрим, например, следующую программу, в которой оператор is позволяетпредотвратить неверное приведение типов:// Использование оператора is для предотвращения// неверной операции приведения типов.using System;class A {}class В : A {}Глава 17.
Динамическая идентификация типов, отражение и атрибуты451class CheckCast {public static void Main() {A a = new A();В b = new В();// Проверяем, можно ли объект а привести к типу В.if(a is В)// При положительном результате выполняем// операцию приведения типов.b = (В) a;else//В противном случае операция приведения// типов опускается.b = null;}}if(b==null)Console.WriteLine("Операция приведения типов b = (В) а НЕ РАЗРЕШЕНА.");elseConsole.WriteLine("Операция приведения типов b = (В) а разрешена.");Результаты выполнения этой программы таковы:Операция приведения b = (В) а НЕ РАЗРЕШЕНА.Как подтверждают эти результаты, поскольку тип объекта а не совместим с типом B,операция приведения объекта а к типу В недопустима, и ее выполнение предотвращается спомощью инструкции if.
Как видите, реализация такого подхода требует выполнения двухэтапов. Первый состоит в подтверждении обоснованности операции приведения типов, авторой — в самом ее выполнении. С помощью оператора as эти два. этапа можнообъединить в один, как показано в следующей программе.// Демонстрация использования оператора as.using System;class A {}class B : A {}class CheckCast {public static void Main() {A a = new A();B b = new B();b = a as B; // Выполняем операцию приведения типов,// если она возможна.if(b==null)Console.WriteLine("Операция приведения типов " +"b - (B) а НЕ РАЗРЕШЕНА.");elseConsole.WriteLine("Операция приведения типов b - (B) а разрешена.");}}Вот результаты выполнения этой программы:Операция приведения типов b = (В) а НЕ РАЗРЕШЕНА.452Часть I.
Язык C#В этой версии оператор as проверяет допустимость операции приведения типов, азатем, если она законна, выполняет ее, причем все это реализуется в одной инструкции.Использование оператора typeofНесмотря на полезность операторов as и is, они просто проверяют (причем каждыйпо-своему) совместимость двух типов. Программист же зачастую сталкивается снеобходимостью получить информацию о типе данных. Для таких случаев в C#предусмотрен оператор typeof.
Его назначение состоит в считывании объекта классаSystem.Type для заданного типа. Используя этот объект, можно определитьхарактеристики конкретного типа данных.Оператор typeof используется в следующем формате:typeof(тип)Здесь элемент тип означает тип, информацию о котором мы хотим получить. Объекттипа Туре, возвращаемый при выполнении оператора typeof, инкапсулируетинформацию, связанную с заданным типом.Получив Type-объект, можно обращаться к информации о заданном типе, используяразличные свойства, поля и методы, определенные в классе Туре. Класс Туре содержитмножество членов, но их обсуждение мы отложим до следующего раздела, посвященногоотражению информации о типе.
Однако, чтобы все же продемонстрировать одно извозможных применений класса Туре, рассмотрим программу, в которой используются триего свойства: FullName, IsClass и IsAbstract. Свойство FullName позволяетполучить полное имя типа. Свойство IsClass возвращает значение true, если типомобъекта является класс. Свойство IsAbstract возвращает значение true, еслирассматриваемый класс является абстрактным.// Демонстрация использования оператора typeof.using System;using System.IO;class UseTypeof {public static void Main() {Type t = typeof(StreamReader);Console.WriteLine(t.FullName);if(t.IsClass) Console.WriteLine("Это класс.");}}if(t.IsAbstract) Console.WriteLine("Это абстрактный класс");else Console.WriteLine("Это конкретный класс.");При выполнении этой программы получены такие результаты:System.IO.StreamReaderЭто класс.Это конкретный класс.Эта программа получает объект типа Туре с описанием типа StreamReader.
Затемона отображает полное имя этого типа, определяет, класс ли это и является ли онабстрактным.Глава 17. Динамическая идентификация типов, отражение и атрибуты453ОтражениеКак упоминалось в начале этой главы, отражение (reflection) — это средство C#,которое позволяет получить информацию о типе. Термин отражение произошел отхарактера процесса: объект класса Туре воспроизводит, или отражает, базовый тип,который он представляет. Для получения интересующей вас информации вы “задаетевопросы” объекту класса Туре, а он возвращает (отражает) для вас информацию,связанную с этим типом.
Отражение — мощный механизм, позволяющий узнатьхарактеристики типа, точное имя которого становится известным только во времявыполнения программы, и соответствующим образом использовать их.Многие классы, которые поддерживают средство отражения, являются частьюинтерфейса .NET Reflection API, который определен в пространстве именSystem.Reflection. Таким образом, в программы, которые используют средствоотражения, обычно включается следующая инструкция:using System.Reflection;Ядро подсистемы отображения: класс System.TуреКласс System.Type — “сердце” подсистемы отображения, поскольку онинкапсулирует тип. Он содержит множество свойств и методов, которые можноиспользовать для получения информации о типе во время выполнения программы. КлассТуре выведен из абстрактного класса System.Reflection.MemberInfо.В классе MemberInfo определены следующие абстрактные свойства, которыепредназначены только для чтения:Туре DeclanngTypeMemberTypes MemberTypestring NameType ReflectedTypeТип класса или интерфейса, в котором объявляетсяанализируемый членТип членаИмя типаТип отражаемого объектаОбратите внимание на то, что свойство MemberType имеет тип MemberTypes.Свойство MemberTypes представляет собой перечисление, которое определяет значения,соответствующие различным типам членов.
Среди прочих они включают следующие:MemberTypes.ConstructorMemberTypes.MethodMemberTypes.FieldMemberTypes.EventMemberTypes.PropertyСледовательно, тип члена можно определить, опросив свойство MemberType.Например, если свойство MemberType содержит значение MemberTypes.Method,значит, интересующий нас член является методом.Класс MemberInfo включает два абстрактных метода: GetCustomAttributes()и IsDefined(). Оба они связаны с атрибутами.К методам и свойствам, определенным в классе MemberInfo, класс Туре добавляетнемало “своих”. Ниже перечислены наиболее часто используемые методы, определенные вклассе Туре.454Часть I. Язык C#МетодНазначениеConstructorInfo[] GetConstructors()EventInfo[] GetEvents()FieldInfo[] GetFields()MemberInfo[] GetMembers()MethodInfo[] GetMethods()PropertyInfo[] GetProperties()Получает список конструкторов для заданного типаПолучает список событий для заданного типаПолучает список полей для заданного типаПолучает список членов для заданного типаПолучает список методов для заданного типаПолучает список свойств для заданного типаТеперь ознакомьтесь с наиболее часто используемыми свойствами, определенными вклассе Туре.СвойствоНазначениеAssembly AssemblyTypeAttributes AttributesType BaseTypestring FullNamebool IsAbstractbool IsArraybool IsClassbool IsEnumstring NamespaceПолучает компоновочный файл для заданного типаПолучает атрибуты для заданного типаПолучает непосредственный базовый тип для заданного типаПолучает полное имя заданного типаИстинно, если заданный тип является абстрактнымИстинно, если заданный тип является массивомИстинно, если заданный тип является классомИстинно, если заданный тип является перечислениемПолучает пространство имен для заданного типаИспользование отраженияИспользуя методы и свойства класса Туре, во время выполнения программы можнополучить подробную информацию о типе.