Last active
February 11, 2018 21:22
-
-
Save alexandre-spieser/160798e1f9e868f32de287547586ab88 to your computer and use it in GitHub Desktop.
Registering all the get and set events on all the virtual properties of a class.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using Castle.DynamicProxy; | |
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Reflection; | |
using Xunit; | |
namespace AlexPlayingWithDynamicProxy | |
{ | |
public enum EventType | |
{ | |
Unknown = 0, | |
Get = 1, | |
Set = 2 | |
} | |
public class PropertyEvent | |
{ | |
public EventType EventType { get; set; } | |
public object Value { get; set; } | |
public PropertyInfo PropertyInfo { get; set; } | |
} | |
public class TrackedObject | |
{ | |
public TrackedObject() | |
{ | |
} | |
private List<PropertyEvent> PropertyEvents { get; } = new List<PropertyEvent>(); | |
public void AddEvent(EventType eventType, string propertyName, object value) | |
{ | |
var propertyInfo = this.GetType().GetProperties().Where(e => e.Name == propertyName).FirstOrDefault(); | |
if (propertyInfo == null) | |
{ | |
return; | |
} | |
var eventsToAdd = new PropertyEvent | |
{ | |
EventType = eventType, | |
PropertyInfo = propertyInfo, | |
Value = value | |
}; | |
if (PropertyEvents.Any(e => e.Equals(eventsToAdd))) | |
{ | |
return; | |
} | |
PropertyEvents.Add(new PropertyEvent | |
{ | |
EventType = eventType, | |
PropertyInfo = propertyInfo, | |
Value = value | |
}); | |
} | |
public List<PropertyEvent> GetEvents() | |
{ | |
return PropertyEvents; | |
} | |
} | |
public class TrackedClass : TrackedObject | |
{ | |
public virtual string SomeContent { get; set; } | |
public virtual int SomeInt { get; set; } | |
} | |
public class GetterSetterInterceptorTests | |
{ | |
[Fact] | |
public void SuccessFullyRegisterGetAndSetEvents() | |
{ | |
ProxyGenerator generator = new ProxyGenerator(); | |
var tracked = generator.CreateClassProxy<TrackedClass>(new GetSetInterceptor()); | |
tracked.SomeContent = "some content"; | |
Assert.Single(tracked.GetEvents()); | |
var eventAfterSomeContentAssigned = tracked.GetEvents().Last(); | |
Assert.Equal(EventType.Set, eventAfterSomeContentAssigned.EventType); | |
Assert.Equal("some content", eventAfterSomeContentAssigned.Value); | |
Assert.Equal("SomeContent", eventAfterSomeContentAssigned.PropertyInfo.Name); | |
tracked.SomeInt = 1; | |
Assert.Equal(2, tracked.GetEvents().Count); | |
var eventAfterSomeIntAssigned = tracked.GetEvents().Last(); | |
Assert.Equal(EventType.Set, eventAfterSomeContentAssigned.EventType); | |
Assert.Equal(1, eventAfterSomeIntAssigned.Value); | |
Assert.Equal("SomeInt", eventAfterSomeIntAssigned.PropertyInfo.Name); | |
var x = tracked.SomeInt; | |
Assert.Equal(3, tracked.GetEvents().Count); | |
var eventAfterSomeIntAccessed = tracked.GetEvents().Last(); | |
Assert.Equal(EventType.Get, eventAfterSomeIntAccessed.EventType); | |
Assert.Equal(1, eventAfterSomeIntAccessed.Value); | |
Assert.Equal("SomeInt", eventAfterSomeIntAccessed.PropertyInfo.Name); | |
} | |
} | |
[Serializable] | |
public abstract class Interceptor : IInterceptor | |
{ | |
public void Intercept(IInvocation invocation) | |
{ | |
ExecuteBefore(invocation); | |
invocation.Proceed(); | |
ExecuteAfter(invocation); | |
} | |
protected abstract void ExecuteAfter(IInvocation invocation); | |
protected abstract void ExecuteBefore(IInvocation invocation); | |
} | |
public class GetSetInterceptor : Interceptor | |
{ | |
protected override void ExecuteBefore(IInvocation invocation) | |
{ | |
} | |
protected override void ExecuteAfter(IInvocation invocation) | |
{ | |
if(invocation.Method.Name.StartsWith("get_") || invocation.Method.Name.StartsWith("set_")) | |
{ | |
var target = invocation.InvocationTarget as TrackedObject; | |
if(target == null) | |
{ | |
return; | |
} | |
var methodInvoked = invocation.Method.Name.Split("_"); | |
switch (methodInvoked[0]) | |
{ | |
case "get": | |
target.AddEvent(EventType.Get, methodInvoked[1], invocation.ReturnValue); | |
break; | |
case "set": | |
target.AddEvent(EventType.Set, methodInvoked[1], invocation.Arguments[0]); | |
break; | |
} | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment