-
Notifications
You must be signed in to change notification settings - Fork 18
Property interception
There are 2 types of property interceptors; the IPropertyGetterInterceptor and the IPropertySetterInterceptor.
The setter and getter interceptors can be combined into one attribute if it is required to intercept both getter and setter. An interface that combines both interfaces also exists: IPropertyInterceptor.
It is also possible to force the weaver to initialize the property interceptors on object construction. To enable this, the interceptor has to implement the IPropertyInterceptorInitialize interface.
A sample implementation of a getter and setter interceptor.
[InterceptorOptions(AlwaysCreateNewInstance = true)]
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = false)]
public class InterceptorGetAttribute : Attribute, IPropertyGetterInterceptor, IPropertySetterInterceptor
{
public void OnException(Exception e)
{
}
public void OnExit()
{
}
public void OnGet(PropertyInterceptionInfo propertyInterceptionInfo, object value)
{
if (value == null || value.ToString() == "Hello")
propertyInterceptionInfo.SetValue("New String");
}
public bool OnSet(PropertyInterceptionInfo propertyInterceptionInfo, object oldValue, object newValue)
{
if (ComparerUtils.Equals(oldValue, newValue))
return true;
return false;
}
}
Your code:
public class SampleClass
{
[PropertyInterceptor]
public string SampleProperty { get; private set; }
}
What gets compiled:
public class SampleClass
{
[NonSerialized]
private PropertyInterceptionInfo propertyinterceptioninfo;
[CompilerGenerated]
private string sampleProperty;
public string SampleProperty
{
get
{
var propertyInterceptorAttribute = new PropertyInterceptorAttribute();
if(this.propertyinterceptioninfo == null)
{
this.propertyinterceptioninfo = new PropertyInterceptionInfo(
methodof(get_SampleProperty),
methodof(set_SampleProperty),
"SampleProperty",
typeof(string),
this,
null,
new Action<object>(this.m_setteraction));
}
try
{
propertyInterceptorAttribute.OnGet(this.propertyinterceptioninfo, this.sampleProperty);
return this.sampleProperty;
}
catch (Exception e)
{
if(propertyInterceptorAttribute.OnException(e))
throw;
}
finally
{
propertyInterceptorAttribute.OnExit();
}
}
private set
{
PropertyInterceptorAttribute propertyInterceptorAttribute = new PropertyInterceptorAttribute();
if(this.propertyinterceptioninfo == null)
{
this.propertyinterceptioninfo = new PropertyInterceptionInfo(
methodof(get_SampleProperty),
methodof(set_SampleProperty),
"SampleProperty",
typeof(string),
this,
null,
new Action<object>(this.m_setteraction));
}
try
{
if (!propertyInterceptorAttribute.OnSet(this.propertyinterceptioninfo, this.sampleProperty, value))
{
this.sampleProperty = value;
}
}
catch (Exception e)
{
if(propertyInterceptorAttribute.OnException(e))
throw;
}
finally
{
propertyInterceptorAttribute.OnExit();
}
}
}
private void m_setteraction(object value)
{
this.sampleProperty = Convert.ToString(value);
}
}
Types that implements the IEnumerable<> interface will also have a specialized implementation in the setter action method.
For example in the case of the following:
[PropertyInterceptor]
public List<string> Property { get; set; }
This is whats gets compiled for the setter action:
private void <Property>m_setteraction(object value)
{
if (this.<Property>k__BackingField == null)
{
this.<Property>k__BackingField = new List<string>();
}
if (value == null)
{
this.<Property>k__BackingField.Clear();
}
else
{
var values = (value as IEnumerable).Cast<string>().ToArray();
for(int i=0; i < values.Length; i++)
this.<Property>k__BackingField.Add(values[i]);
}
}
Applying the property interceptor to an abstract property will result in all overriding properties implementing the interceptor.
public abstract class SampleClassBase
{
[PropertyInterceptor]
public abstract string SampleProperty { get; }
}
The weaver will copy the interceptor to all property implementation.
public class CoolClass : SampleClassBase
{
[PropertyInterceptor]
public override string SampleProperty { get; }
}