Search code examples
c#postsharp

Import postsharp aspect field from class by name dynamically


If I have a class:

class MyClass
{
  IMyInterface _mi;

  [MyAspectAttribute("_mi")]
  bool _myValue;

  // ...
}

Is there a way to create an aspect attribute MyAspectAttribute that intercepts getting and setting the value for (bool myValue) AND also imports the field that is specified in the attribute [MyAspectAttribute("_mi")] in this case _mi dynamically so I can use it in the aspect? (I want to call the interface before getting or setting the field in the aspect).

I know how to write the aspect I just don't know how to dynamically import the specified field (in this example _mi). All of the examples require that you know the exact field name to import (but I want the name passed to my aspect).

Thanks.


Solution

  • You can import the field dynamically by implementing IAdviceProvider.ProvideAdvices method and returning ImportLocationAdviceInstance for the field you want to import. The sample aspect below demonstrates this technique.

    [PSerializable]
    public class MyAspectAttribute : LocationLevelAspect, IAdviceProvider, IInstanceScopedAspect
    {
        private string _importedFieldName;
    
        public MyAspectAttribute(string importedFieldName)
        {
            _importedFieldName = importedFieldName;
        }
    
        public ILocationBinding ImportedField;
    
        public IEnumerable<AdviceInstance> ProvideAdvices(object targetElement)
        {
            var target = (LocationInfo) targetElement;
            var importedField = target.DeclaringType
                .GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
                .First(f => f.Name == this._importedFieldName);
    
            yield return new ImportLocationAdviceInstance(
                typeof(MyAspectAttribute).GetField("ImportedField"),
                new LocationInfo(importedField));
        }
    
        [OnLocationGetValueAdvice, SelfPointcut]
        public void OnGetValue(LocationInterceptionArgs args)
        {
            IMyInterface mi = (IMyInterface)this.ImportedField.GetValue(args.Instance);
            mi.SomeMethod();
    
            args.ProceedGetValue();
        }
    
        [OnLocationSetValueAdvice(Master = "OnGetValue"), SelfPointcut]
        public void OnSetValue(LocationInterceptionArgs args)
        {
            IMyInterface mi = (IMyInterface) this.ImportedField.GetValue(args.Instance);
            mi.SomeMethod();
    
            args.ProceedSetValue();
        }
    
        public object CreateInstance(AdviceArgs adviceArgs)
        {
            return this.MemberwiseClone();
        }
    
        public void RuntimeInitializeInstance()
        {
        }
    }