Created
April 27, 2015 14:56
-
-
Save danbarua/8a9387957f8a0d884f41 to your computer and use it in GitHub Desktop.
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 System; | |
using System.Collections.Generic; | |
using System.Diagnostics; | |
using System.Linq; | |
using System.Reflection; | |
using ServiceStack.Net30.Collections.Concurrent; | |
/// <summary> | |
/// Helper class redirects events to private Apply(event) method | |
/// </summary> | |
public static class RedirectToApply | |
{ | |
/// <summary>The cache.</summary> | |
private static readonly IDictionary<Type, IDictionary<Type, MethodInfo>> Cache = new ConcurrentDictionary<Type, IDictionary<Type, MethodInfo>>(); | |
/// <summary>The internal preserve stack trace method.</summary> | |
private static readonly MethodInfo InternalPreserveStackTraceMethod = typeof(Exception).GetMethod( | |
"InternalPreserveStackTrace", BindingFlags.Instance | BindingFlags.NonPublic); | |
/// <summary>Invokes the Apply() method on the instance, throwing an exception if it does not exist.</summary> | |
/// <param name="instance">The instance.</param> | |
/// <param name="event">The event.</param> | |
/// <exception cref="InvalidOperationException">Thrown where the object does not have an Apply() method.</exception> | |
/// <exception cref="Exception">Thrown whent the Apply() method throws an exception.</exception> | |
[DebuggerNonUserCode] | |
public static void InvokeApply(object instance, object @event) | |
{ | |
MethodInfo info; | |
var instanceType = instance.GetType(); | |
IDictionary<Type, MethodInfo> lookup; | |
if (!Cache.TryGetValue(instanceType, out lookup)) | |
{ | |
lookup = | |
instanceType.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance) | |
.Where(m => m.Name == "Apply") | |
.Where(m => m.GetParameters().Length == 1) | |
.ToDictionary(m => m.GetParameters().First().ParameterType, m => m); | |
Cache[instanceType] = lookup; | |
} | |
var eventType = @event.GetType(); | |
if (!lookup.TryGetValue(eventType, out info)) | |
{ | |
var s = string.Format("Failed to locate {0}.Apply({1})", instanceType.Name, eventType.Name); | |
throw new InvalidOperationException(s); | |
} | |
try | |
{ | |
info.Invoke(instance, new[] { @event }); | |
} | |
catch (TargetInvocationException ex) | |
{ | |
if (null != InternalPreserveStackTraceMethod) | |
{ | |
InternalPreserveStackTraceMethod.Invoke(ex.InnerException, new object[0]); | |
} | |
throw ex.InnerException; | |
} | |
} | |
/// <summary>Optionally invokes the Apply(event) method on the instance where the method exists.</summary> | |
/// <param name="instance">The instance.</param> | |
/// <param name="event">The event.</param> | |
/// <exception cref="Exception">Thrown when the Apply() method throws an exception.</exception> [DebuggerNonUserCode] | |
public static void InvokeApplyOptional(object instance, object @event) | |
{ | |
MethodInfo info; | |
var instanceType = instance.GetType(); | |
IDictionary<Type, MethodInfo> lookup; | |
if (!Cache.TryGetValue(instanceType, out lookup)) | |
{ | |
lookup = | |
instanceType.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance) | |
.Where(m => m.Name == "Apply") | |
.Where(m => m.GetParameters().Length == 1) | |
.ToDictionary(m => m.GetParameters().First().ParameterType, m => m); | |
Cache[instanceType] = lookup; | |
} | |
var eventType = @event.GetType(); | |
if (!lookup.TryGetValue(eventType, out info)) | |
{ | |
// event is not needed for aggregate state | |
return; | |
} | |
try | |
{ | |
info.Invoke(instance, new[] { @event }); | |
} | |
catch (TargetInvocationException ex) | |
{ | |
if (null != InternalPreserveStackTraceMethod) | |
{ | |
InternalPreserveStackTraceMethod.Invoke(ex.InnerException, new object[0]); | |
} | |
throw ex.InnerException; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment