Рефлексия атрибутов с использованием раннего связывания

Ограничение использования атрибутов

Создание специальных атрибутов

Первым шагом в процессе создания специального атрибута является создание нового класса, унаследованного от 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.