2013-06-13 4 views
7

Есть ли способ использования перехвата атрибутом в C# единицу и сохранить код регистрации объекта в файле XML (например, app.config)? Если да, можете ли вы предоставить мне код, как должна выглядеть такая регистрация? Я сделал много обходных решений, но не нашел рабочего решения для этой проблемы.Перехват единственного элемента C# по атрибуту

ответ

14

Я предполагаю, что вы имеете в виду использование настраиваемого атрибута, чтобы указать, какие методы перехватывать. Вы можете использовать инъекцию политики для достижения перехвата с использованием конфигурации XML.

Во-первых, давайте определим пользовательский атрибут:

[AttributeUsage(AttributeTargets.Method)] 
public class MyInterceptionAttribute : Attribute 
{ 
} 

Далее мы можем создать ICallHandler, чтобы сделать некоторые отсечной работы. Эта реализация будет просто сделать Console.WriteLine до и после метода:

public class MyLoggingCallHandler : ICallHandler 
{ 
    IMethodReturn ICallHandler.Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext) 
    { 
     Console.WriteLine("Invoking " + input.MethodBase.Name); 
     IMethodReturn result = getNext()(input, getNext); 
     Console.WriteLine("Done Invoke"); 
     return result; 
    } 

    int ICallHandler.Order { get; set; } 
} 

Далее давайте предположим, что мы имеем некоторый интерфейс и реализация:

public interface IMyClass 
{ 
    void Do(); 
    void DoAgain(); 
} 

public class MyClass : IMyClass 
{ 
    [MyInterception] 
    public void Do() 
    { 
     Console.WriteLine("Do!"); 
    } 

    public void DoAgain() 
    { 
     Console.WriteLine("Do Again!"); 
    } 
} 

Обратите внимание, что я применил пользовательский атрибут , MyInterception, только для метода Do, но не для метода DoAgain. Мы перехватим все вызовы метода Do.

Далее мы создаем конфигурацию, чтобы определить политику, настроить правило соответствия и зарегистрировать тип вместе с перехватчиком:

<?xml version="1.0"?> 
<configuration> 
    <configSections> 
    <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration"/> 
    </configSections> 
    <unity xmlns="http://schemas.microsoft.com/practices/2010/unity"> 
    <namespace name="UnityCallHandlerConfig" /> 
    <assembly name="UnityCallHandlerConfig" /> 
    <sectionExtension type="Microsoft.Practices.Unity.InterceptionExtension.Configuration.InterceptionConfigurationExtension, Microsoft.Practices.Unity.Interception.Configuration"/> 
    <container> 
     <extension type="Interception"/> 
     <interception> 
     <policy name="Policy"> 
      <matchingRule name="Match" type="Microsoft.Practices.Unity.InterceptionExtension.CustomAttributeMatchingRule, Microsoft.Practices.Unity.Interception"> 
      <constructor> 
       <param name="attributeType" value="UnityCallHandlerConfig.MyInterceptionAttribute, UnityCallHandlerConfig" typeConverter="AssemblyQualifiedTypeNameConverter" /> 
       <param name="inherited"> 
       <value value="false"/> 
       </param> 
      </constructor> 
      </matchingRule> 
      <callHandler name="MyLogging" type="MyLoggingCallHandler"> 
      <lifetime type="singleton"/> 
      </callHandler> 
     </policy> 
     </interception> 
     <register type="IMyClass" mapTo="MyClass"> 
     <interceptor type="InterfaceInterceptor"/> 
     <interceptionBehavior type="PolicyInjectionBehavior"/> 
     </register> 
    </container> 
    </unity> 

    <startup> 
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5"/> 
    </startup> 
</configuration> 

Мы также нужен конвертер типа для преобразования строкового представления пользовательского атрибута соответствующий тип:

public class AssemblyQualifiedTypeNameConverter : ConfigurationConverterBase 
{ 
    public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType) 
    { 
     if (value != null) 
     { 
      Type typeValue = value as Type; 
      if (typeValue == null) 
      { 
       throw new ArgumentException("Cannot convert type", typeof(Type).Name); 
      } 

      if (typeValue != null) return (typeValue).AssemblyQualifiedName; 
     } 
     return null; 
    } 

    public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value) 
    { 
     string stringValue = (string)value; 
     if (!string.IsNullOrEmpty(stringValue)) 
     { 
      Type result = Type.GetType(stringValue, false); 
      if (result == null) 
      { 
       throw new ArgumentException("Invalid type", "value"); 
      } 

      return result; 
     } 
     return null; 
    } 
} 

После того, как у нас есть все, что создали мы можем создать контейнер и загрузить конфигурацию:

var container = new UnityContainer().LoadConfiguration(); 

var myClass = container.Resolve<IMyClass>(); 
myClass.Do(); 
myClass.DoAgain(); 

Выходной сигнал будет:

Invoking Do 
Do! 
Done Invoke 
Do Again! 

, показывающий, что первый метод перехватывается в то время как второй нет.

+0

Большое спасибо за помощь! –

+2

@Tuzo, как выглядела конфигурация в коде C#? Вам все еще нужно «AssemblyQualifiedTypeNameConverter», если это сделано в коде? –

Смежные вопросы