Created
February 10, 2013 23:28
-
-
Save hagbarddenstore/4751506 to your computer and use it in GitHub Desktop.
This file contains 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.Linq; | |
using System.Text; | |
namespace AggregateRootTesting | |
{ | |
using System.Diagnostics; | |
using System.Reflection; | |
class Program | |
{ | |
static Guid _id; | |
static void Main(string[] args) | |
{ | |
const int Runs = 10000; | |
_id = Guid.NewGuid(); | |
var domainEvents = new List<DomainEvent> | |
{ | |
new Created(_id, 1, "Hello, world!") | |
}; | |
for (var i = 2; domainEvents.Count < 101; i++) | |
{ | |
domainEvents.Add(new CommentedOn(_id, i, string.Format("A comment on this worthless post! {0}", i))); | |
} | |
// Warmup and assertions | |
var blogPostDynamic = new BlogPostDynamic(_id, domainEvents); | |
var blogPostStatic = new BlogPostStatic(_id, domainEvents); | |
var blogPostReflection = new BlogPostReflection(_id, domainEvents); | |
var blogPostCachedReflection = new BlogPostCachedReflection(_id, domainEvents); | |
Info("Asserting dynamic"); | |
Assert(blogPostDynamic); | |
Info("Asserting static"); | |
Assert(blogPostStatic); | |
Info("Asserting reflection"); | |
Assert(blogPostReflection); | |
Info("Asserting cached reflection"); | |
Assert(blogPostCachedReflection); | |
for (var j = 0; j < 10; j++) | |
{ | |
Info("Testing static"); | |
var stopwatchStatic = Stopwatch.StartNew(); | |
for (var i = 0; i < Runs; i++) | |
{ | |
var blogPost = new BlogPostStatic(_id, domainEvents); | |
} | |
stopwatchStatic.Stop(); | |
Info(string.Format("It took {0}ms to run static. {1}ms / call", stopwatchStatic.ElapsedMilliseconds, stopwatchStatic.ElapsedMilliseconds / (double)Runs)); | |
Info("Testing reflection"); | |
var stopwatchReflection = Stopwatch.StartNew(); | |
for (var i = 0; i < Runs; i++) | |
{ | |
var blogPost = new BlogPostReflection(_id, domainEvents); | |
} | |
stopwatchReflection.Stop(); | |
Info(string.Format("It took {0}ms to run reflection. {1}ms / call", stopwatchReflection.ElapsedMilliseconds, stopwatchReflection.ElapsedMilliseconds / (double)Runs)); | |
Info("Testing cached reflection"); | |
var stopwatchCachedReflection = Stopwatch.StartNew(); | |
for (var i = 0; i < Runs; i++) | |
{ | |
var blogPost = new BlogPostCachedReflection(_id, domainEvents); | |
} | |
stopwatchCachedReflection.Stop(); | |
Info(string.Format("It took {0}ms to run cached reflection. {1}ms / call", stopwatchCachedReflection.ElapsedMilliseconds, stopwatchCachedReflection.ElapsedMilliseconds / (double)Runs)); | |
} | |
Console.WriteLine("Press enter to exit..."); | |
Console.ReadLine(); | |
} | |
static void Assert(IBlogPost blogPost) | |
{ | |
if (blogPost.Id != _id) | |
{ | |
Error(string.Format("Invalid id. Expected: {0} Attempted: {1}", _id, blogPost.Id)); | |
} | |
if (blogPost.Version != 101) | |
{ | |
Error(string.Format("Invalid version. Expected: {0} Attempted: {1}", 101, blogPost.Version)); | |
} | |
if (blogPost.Comments.Count() != 100) | |
{ | |
Error(string.Format("Invalid number of comments. Expected: {0} Attempted: {1}", 100, blogPost.Comments.Count())); | |
} | |
} | |
static void Error(string message) | |
{ | |
var color = Console.ForegroundColor; | |
Console.ForegroundColor = ConsoleColor.Red; | |
Console.WriteLine(message); | |
Console.ForegroundColor = color; | |
} | |
static void Info(string message) | |
{ | |
var color = Console.ForegroundColor; | |
Console.ForegroundColor = ConsoleColor.White; | |
Console.WriteLine(message); | |
Console.ForegroundColor = color; | |
} | |
} | |
class DomainEvent | |
{ | |
public DomainEvent(Guid aggregateRootId, long version) | |
{ | |
AggregateRootId = aggregateRootId; | |
Version = version; | |
} | |
public Guid AggregateRootId { get; private set; } | |
public long Version { get; private set; } | |
} | |
abstract class AggregateRootBase | |
{ | |
protected AggregateRootBase(Guid aggregateRootId, IEnumerable<DomainEvent> domainEvents) | |
{ | |
Id = aggregateRootId; | |
Replay(domainEvents); | |
} | |
public Guid Id { get; private set; } | |
public long Version { get; private set; } | |
private void Replay(IEnumerable<DomainEvent> domainEvents) | |
{ | |
foreach (var domainEvent in domainEvents) | |
{ | |
Replay(domainEvent); | |
Version = domainEvent.Version; | |
} | |
} | |
protected abstract void Replay(DomainEvent domainEvent); | |
} | |
class Created : DomainEvent | |
{ | |
public Created(Guid aggregateRootId, long version, string title) | |
: base(aggregateRootId, version) | |
{ | |
Title = title; | |
} | |
public string Title { get; private set; } | |
} | |
class CommentedOn : DomainEvent | |
{ | |
public CommentedOn(Guid aggregateRootId, long version, string comment) | |
: base(aggregateRootId, version) | |
{ | |
Comment = comment; | |
} | |
public string Comment { get; private set; } | |
} | |
interface IBlogPost | |
{ | |
Guid Id { get; } | |
long Version { get; } | |
string Title { get; } | |
IEnumerable<string> Comments { get; } | |
} | |
class BlogPostDynamic : AggregateRootBase, IBlogPost | |
{ | |
private readonly ISet<string> _comments = new HashSet<string>(); | |
public BlogPostDynamic(Guid aggregateRootId, IEnumerable<DomainEvent> domainEvents) | |
: base(aggregateRootId, domainEvents) | |
{ | |
} | |
public string Title { get; private set; } | |
public IEnumerable<string> Comments | |
{ | |
get { return _comments; } | |
} | |
public void Apply(Created domainEvent) | |
{ | |
Title = domainEvent.Title; | |
} | |
public void Apply(CommentedOn domainEvent) | |
{ | |
_comments.Add(domainEvent.Comment); | |
} | |
protected override void Replay(DomainEvent domainEvent) | |
{ | |
dynamic self = this; | |
self.Apply(domainEvent); | |
} | |
} | |
class BlogPostStatic : AggregateRootBase, IBlogPost | |
{ | |
private readonly ISet<string> _comments = new HashSet<string>(); | |
public BlogPostStatic(Guid aggregateRootId, IEnumerable<DomainEvent> domainEvents) | |
: base(aggregateRootId, domainEvents) | |
{ | |
} | |
public string Title { get; private set; } | |
public IEnumerable<string> Comments | |
{ | |
get { return _comments; } | |
} | |
private void Apply(Created domainEvent) | |
{ | |
Title = domainEvent.Title; | |
} | |
private void Apply(CommentedOn domainEvent) | |
{ | |
_comments.Add(domainEvent.Comment); | |
} | |
protected override void Replay(DomainEvent domainEvent) | |
{ | |
var created = domainEvent as Created; | |
if (created != null) | |
{ | |
Apply(created); | |
} | |
var commentedOn = domainEvent as CommentedOn; | |
if (commentedOn != null) | |
{ | |
Apply(commentedOn); | |
} | |
} | |
} | |
class BlogPostReflection : AggregateRootBase, IBlogPost | |
{ | |
private readonly ISet<string> _comments = new HashSet<string>(); | |
public BlogPostReflection(Guid aggregateRootId, IEnumerable<DomainEvent> domainEvents) | |
: base(aggregateRootId, domainEvents) | |
{ | |
} | |
public string Title { get; private set; } | |
public IEnumerable<string> Comments | |
{ | |
get { return _comments; } | |
} | |
private void Apply(Created domainEvent) | |
{ | |
Title = domainEvent.Title; | |
} | |
private void Apply(CommentedOn domainEvent) | |
{ | |
_comments.Add(domainEvent.Comment); | |
} | |
protected override void Replay(DomainEvent domainEvent) | |
{ | |
var applyMethod = FindMethod(domainEvent.GetType()); | |
applyMethod.Invoke(this, new object[] { domainEvent }); | |
} | |
private MethodInfo FindMethod(Type domainEventType) | |
{ | |
MethodInfo methodInfo = null; | |
var classType = GetType(); | |
do | |
{ | |
methodInfo = FindMethod(classType, domainEventType); | |
if (methodInfo == null) | |
{ | |
classType = classType.BaseType; | |
} | |
} | |
while (methodInfo == null && classType != typeof(AggregateRootBase)); | |
return methodInfo; | |
} | |
private MethodInfo FindMethod(Type classType, Type domainEventType) | |
{ | |
const BindingFlags BindingFlags = BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public; | |
var methodInfo = classType.GetMethod("Apply", BindingFlags, null, new[] { domainEventType }, null); | |
return methodInfo; | |
} | |
} | |
class BlogPostCachedReflection : AggregateRootBase, IBlogPost | |
{ | |
private static readonly IDictionary<Type, IDictionary<Type, MethodInfo>> _applyMethods = new Dictionary<Type, IDictionary<Type, MethodInfo>>(); | |
private readonly ISet<string> _comments = new HashSet<string>(); | |
public BlogPostCachedReflection(Guid aggregateRootId, IEnumerable<DomainEvent> domainEvents) | |
: base(aggregateRootId, domainEvents) | |
{ | |
} | |
public string Title { get; private set; } | |
public IEnumerable<string> Comments | |
{ | |
get { return _comments; } | |
} | |
private void Apply(Created domainEvent) | |
{ | |
Title = domainEvent.Title; | |
} | |
private void Apply(CommentedOn domainEvent) | |
{ | |
_comments.Add(domainEvent.Comment); | |
} | |
protected override void Replay(DomainEvent domainEvent) | |
{ | |
var applyMethod = FindMethod(GetType(), domainEvent.GetType()); | |
applyMethod.Invoke(this, new object[] { domainEvent }); | |
} | |
private MethodInfo FindMethod(Type classType, Type domainEventType) | |
{ | |
if (_applyMethods.ContainsKey(classType) && _applyMethods[classType].ContainsKey(domainEventType)) | |
{ | |
return _applyMethods[classType][domainEventType]; | |
} | |
do | |
{ | |
const BindingFlags BindingFlags = BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public; | |
var methodInfo = classType.GetMethod("Apply", BindingFlags, null, new[] { domainEventType }, null); | |
if (methodInfo == null) | |
{ | |
classType = classType.BaseType; | |
} | |
else | |
{ | |
if (!_applyMethods.ContainsKey(classType)) | |
{ | |
_applyMethods.Add(classType, new Dictionary<Type, MethodInfo>()); | |
} | |
_applyMethods[classType].Add(domainEventType, methodInfo); | |
return methodInfo; | |
} | |
} | |
while (classType != typeof(AggregateRootBase)); | |
return null; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment