10_C#_отражение_атрибуты

advertisement
Отражение (reflection)
 Отражение – получение из метаданных информации о типах,
определенных в сборке.
 Классы, поддерживающие механизм отражения, находятся в
пространстве имен System.Reflection.
 Класс System.Type – абстрактный класс для хранения
информации о типе.
 Схема наследования для класса System.Type:
System.Object
System.Reflection.MemberInfo
System.Type
Сборка и метаданные
• Сборка - исполняемое под
управлением CLR приложение
или библиотека с типами и/или
ресурсами.
• Метаданные содержат
описание всех типов,
определенных в приложении.
Рисунок из MSDN
Developer Tools \ Visual Studio 2008 \ Visual Studio \
Visual C# \ Getting Started with Visual C# \
Introduction to the C# Language and .NET Framework
• Можно программно получить
всю информацию о сборке,
используя механизм отражения
(reflection).
Метаданные
 Метаданные – это бинарная информация, которая добавляется в PEфайл (portable executable file) при компиляции исходного кода в MSIL.
 При выполнении кода CLR загружает метаданные в память.
 Метаданные содержат полную информацию о сборке.
• Описание сборки.
• Имя, версия, региональные стандарты (culture), ключ издателя
(public key).
• Типы, определенные в сборке.
• Другие сборки, на которые ссылается данная сборка.
• Права (security permissions), необходимые для выполнения сборки.
• Описание каждого типа, определенного в приложении.
• Имя, видимость, базовый класс, реализованные интерфейсы.
• Члены класса (методы, свойства, поля, события, вложенные типы).
• Атрибуты – дополнительную декларативную информацию.
Метаданные -2
 Метаданные используются
• Сборщиком мусора
• При сериализации объекта
• VisualStudio для подсказок при написании
исходного кода
 Метаданные доступны через
• Методы классов, поддерживающих механизм
отражения (reflection)
• ILDASM
Класс System.Type
 В классе System.Type определено более 100 свойств и методов,
которые дают возможность получить полную информацию о типе.
 Объект типа System.Type, предоставляющий информацию о типе,
уникален. Ссылку на объект System.Type для конкретного типа можно
получить многими способами, но все ссылки на этот объект будут
равны.
Student st = new Student();
Type t1 = typeof(Student);
Type t2 = st.GetType();
Console.WriteLine(object.ReferenceEquals(t1, t2)); // true
Console.WriteLine("\ntypeof(Student) {0}", t1.FullName);
Некоторые свойства, определенные в классе
System.Type
public abstract class Type : MemberInfo, IReflect
{
public abstract Assembly Assembly {get;} // сборка, в которой определен
// тип
public TypeAttributes Attributes {get;}
// атрибуты, связанные с типом
public abstract Type BaseType {get;}
// ссылка на базовый тип
public abstract string FullName {get;}
public bool IsSerializable {get;}
public bool IsValueType {get;}
public bool IsClass {get;}
…
}
Некоторые методы, определенные в классе
System.Type
public FieldInfo[ ] GetFields(); // информация об открытых полях типа;
// есть перегруженная версия с возможностью настройки
// на поля с другим типом доступа;
public MethodInfo[ ] GetMethods();
public PropertyInfo[ ] GetProperties();
public abstract object[ ] GetCustomAttributes( bool inherit );
 Типы FieldInfo, MethodInfo, PropertyInfo определены в пространстве
имен System.Reflection и имеют свойства и методы для получения
более детальной информации.
Как получить значение поля?
 Метод класса FieldInfo
public abstract object GetValue( object obj );
дает возможность передать ссылку на инициализированный объект
типа и получить значение поля. Например,
Type tp = typeof(Student);
Student stest = new Student();
FieldInfo[] flds = tp.GetFields();
if (flds.Length == 0) Console.WriteLine("\nNo public fields");
else
{ foreach (FieldInfo item in flds)
{
Console.Write(item.Name);
Console.Write("
" + item.FieldType);
Console.Write("
" + item.IsPrivate);
object s = item.GetValue(stest);
Console.Write("
}
}
" + s.ToString());
Вызов метода по ссылке на объект System.Type
 Метод класса MethodInfo
public object Invoke( object obj, object[] parameters );
дает возможность передать ссылку на инициализированный объект и
значения параметров и выполнить метод. Например,
Type tp = typeof(Student);
Student stest = new Student();
MethodInfo[] mds = tp.GetMethods();
foreach (MethodInfo item in mds)
{
Console.Write(item.Name);
if (item.Name == "get_Group")
{
object[] parms = null;
object ret = item.Invoke(stest, parms);
Console.Write("
}
}
" + ret);
Атрибуты
 В C# атрибуты используются для передачи декларативной
информации от разработчика фрагментам кода. При компиляции эта
информация добавляется к метаданным.
Атрибуты
• предопределенные (из BCL)
• пользовательские (custom)
 В период выполнения атрибуты доступны с помощью механизма
отражения (reflection).
 В C# атрибут размещается перед элементом, к которому он
прикреплен.
 Следующие объявления эквивалентны
[FlagsAttribute][SerializableAttribute]
[Serializable][Flags]
[Flags,Serializable]
Пользовательские атрибуты
 Пользовательский атрибут определяется путем определения класса,
производного от System.Attribute.
 Атрибут может иметь позиционные и именованные параметры.
 Позиционные параметры
• являются обязательными и указываются при каждом
использовании атрибута;
• порождаются конструкторами с типом доступа public.
 Именованные параметры
• не являются обязательными;
• значение параметра указывается вместе с именем параметра;
• всегда располагаются за позиционными;
• порождаются открытыми нестатическими полями и свойствами
класса;
 Типами параметров атрибута могут быть только встроенные типы и
одномерные sz-массивы этих типов.
 Значениями параметров могут быть только константные выражения.
Пример определения нового атрибута
[AttributeUsage(AttributeTargets.Class)]
public class MyCommentAttribute : Attribute
{
string last_update;
string comment;
public
MyCommentAttribute(string last_update)
{
this.last_update = last_update; }
public string Comment
{
get { return comment;}
set { comment = value;}
}
}
Атрибут AttributeUsage
 Используется только при определении классов атрибутов и может
быть прикреплен только к классу, производному от System.Attribute.
 Параметры
Позиционный – комбинация значений перечисления AttributeTargets
( определяет элементы, с которыми можно связать атрибут);
Именованные
• bool AllowMultiple; – запрещает или разрешает
многократное прикрепление к одному элементу ( умолчание
false );
• bool Inherited; – наследуется производным классом, если
прикреплен к базовому ( умолчание true).
 Если при объявлении класса атрибута, атрибут AttributeUsage не
указан, значение позиционного параметра считается равным
AttributeTargets.All.
Перечисление AttributeTargets
[SerializableAttribute]
[FlagsAttribute]
[ComVisibleAttribute(true)]
public enum AttributeTargets
 Перечисление определяет элементы, с которыми можно связать
атрибут.
 Элементы перечисления:
All
Assembly
Class
Constructor
Delegate
Enum
Event
Field
GenericParameter
Interface
Method
Module
Parameter
Property
ReturnValue
Struct
 Значения перечисления можно комбинировать с помощью побитовой
операци OR.
Использование нового атрибута
 Объявляем класс и указываем атрибут
[MyComment(“27.10.08", Comment = "Class from Attributes_Demo")]
[Serializable]
public class Abc { …}
 Список атрибутов получаем при помощи метода GetCustomAttributes().
 Значение true для второго параметра указывает, что атрибут может быть
унаследован от базового класса.
MemberInfo info = typeof (Abc);
object [] ats1 =
info.GetCustomAttributes(typeof(MyCommentAttribute),true);
Атрибут FlagsAttribute
 Атрибут Flags может быть прикреплен только к перечислению.
[AttributeUsage(AttributeTargets.Enum)]
[Serializable]
public class FlagsAttribute : Attribute
 Атрибут указывает, что
• перечисление можно рассматривать как набор битовых
флагов;
• значения перечисления можно комбинировать с помощью
побитовой операци OR.
 Примеры:
[Flags]
[Serializable]
public enum FileAccess
[Flags]
[Serializable]
public enum AttributeTargets
Атрибут ConditionalAttribute - условная компиляция
 При помощи атрибута Conditional можно включать/выключать
вызовы метода на этапе компиляции
[AttributeUsage(AttributeTargets.Method)]
[Serializable]
public sealed class ConditionalAttribute : Attribute
 Параметр конструктора атрибута определяет символ (строку)
условной компиляции:
public ConditionalAttribute( string conditionString );
 Символ (строка) условной компиляции чувствителен к регистру.
DEBUG и Debug – разные символы.
 Атрибут Conditional используется в методах классов Debug и Trace.
 Visual Studio определяет символ TRACE для Release-компиляции.
 Visual Studio определяет символы TRACE и DEBUG для Debugкомпиляции.
Атрибут ConditionalAttribute - 2
 Вызов условного метода зависит от того, определен или нет символ
условной компиляции (строка атрибута) в точке вызова метода.
 Если символ не определен, то не вычисляются параметры метода и
вызов не включается в код.
 Ограничения на метод, к которому может быть прикреплен атрибут:
• метод класса или струтуры (но не интерфейса);
• возвращаемое значение должно быть void;
• метод не имеет модификатор override, но может иметь
модификатор virtual; переопределенные версии этого метода
(overrides) неявно получают атрибут Conditional;
• метод не может быть реализацией интерфейсного метода;
• нельзя использовать метод с атрибутом Conditional в delegatecreation-expression.
 Атрибут Conditional допускает многократное прикрепление (multiuse
attribute ).
 Вызов метода включается в код, если определен хотя бы один из
прикрепленных к методу символов условной компиляции.
Атрибут ConditionalAttribute - пример
 File Class1.cs
Метод F класса Abc определен
с атрибутом Conditional.
Символ FAbc не определен.
using System;
using System.Diagnostics;
namespace Conditional_Demo
{ class Class1 {
static void Main(string[] args)
{ Abc abc = new Abc();
abc.F();
Console.WriteLine (“1”);
Class2 cl2= new Class2();
cl2.F2();
}
}
class Abc
{ [Conditional("FAbc")]
public void F()
{Console.WriteLine("Abc.F"); }
}}
 File Class2.cs.
Символ FAbc определен.
#define FAbc
using System;
namespace Conditional_Demo
{ public class Class2 {
public void F2()
{ Abc abc = new Abc();
abc.F();
}
}}
 Вывод:
1
Abc.F
Download