Рефлексия атрибутов с использованием раннего связывания
Ограничение использования атрибутов
Создание специальных атрибутов
Первым шагом в процессе создания специального атрибута является создание нового класса, унаследованного от System.Attribute. В описании атрибута (DescriptionAttribute ) поддерживается фрагмент строковых данных, предусматривающий возможность манипуляций над ним с помощью автоматического свойства (Description). Помимо того факта, что данный класс наследуется от System.Attribute, ничего особенного в нем больше нет.
По умолчанию действие специальных атрибутов может распространяться на практически любой аспект кода (методы, классы, свойства и т.д.). Следовательно, если бы потребовалось, можно было бы использовать VehicleDescription (помимо прочего) и для уточнения описания методов, свойств или полей. В одних случаях подобное поведение оказывается именно тем, что нужно, но в других, однако, может потребоваться создать вместо этого специальный атрибут, действие которого бы распространялось только на избранные элементы кода. Чтобы ограничить область действия специального атрибута, необходимо применить к его определению атрибут [AttributeUsage].
Вспомните, что атрибуты остаются бесполезными до тех пор, пока к их значениям не применяется рефлексия в каком-то другом компоненте программного обеспечения. После обнаружения атрибута в этом компоненте может предприниматься любое необходимое действие. Как и в любом приложении, обнаружение специального атрибута может быть реализовано с использованием либо раннего, либо позднего связывания.
Для применения раннего связывания определение интересующего атрибута (в данном случае VehicleDescriptionAttribute) должно присутствовать в клиентском приложении уже на этапе компиляции. С учетом того, что специальный атрибут определен в сборке At tribute dCarLibrary как общедоступный класс, использование раннего связывания будет наилучшим вариантом.
Создание расширяемого приложения
В первую очередь необходимо создать сборку с типами, которые должна обязательно использовать каждая оснастка, чтобы иметь возможность подключаться к расширяемому приложению Windows Forms. Для этого создадим проект типа Class Library (Библиотека классов), назовем его CommonSnappableTypes.
namespace CommonSnappableTypes
{
public interface IAppFunctionality
{
void Dolt () ;
}
[AttributeUsage(AttributeTargets.Class) ]
public sealed class CompanylnfoAttribute : System.Attribute
{
public string CompanyName { get; set; }
public string CompanyUrl { get; set; }
}
Далее потребуется создать тип, реализующий интерфейс IAppFunctionality. Чтобы не усложнять пример создания расширяемого приложения, давайте сделаем этот тип простым. Создадим новый проект типа Class Library на С# по имени CSharpSnapln и определим в нем тип класса по имени CSharpModule. При этом нужно не забыть добавить ссылку на сборку CommonSnappableTypes, чтобы этот класс мог использовать определенные в ней типы (а также на сборку System. Windows . Forms . dll для того, чтобы он мог отображать осмысленное сообщение). Ниже показан необходимый код.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using CommonSnappableTypes;
using System.Windows.Forms;
namespace CSharpSnapln
{
[Companylnfo(CompanyName = "My Company", CompanyUrl = "www.MyCompany.com")]
public class CSharpModule : IAppFunctionality
{
void IAppFunctionality.Dolt()
{
MessageBox. Show ("You have just used the C# snap in!");
}
}
}
Обратите внимание, что для обеспечения поддержки интерфейса IAppFunctionality был выбран вариант его реализации явным образом. Применять именно такой вариант вовсе не необязательно; главное понимать, что единственной частью системы, которая нуждается в непосредственном взаимодействии с данным типом интерфейса, является обслуживающее приложение Windows. Благодаря явной реализации этого интерфейса, метод Dolt () не становится доступным прямо из типа CSharpModule.