Skip to content

Instantly share code, notes, and snippets.

@alexandre-spieser
Last active February 11, 2018 21:22
Show Gist options
  • Save alexandre-spieser/160798e1f9e868f32de287547586ab88 to your computer and use it in GitHub Desktop.
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.
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