Skip to content

Commit

Permalink
This fixes issue #29. Now collection change tracking implementations …
Browse files Browse the repository at this point in the history
…are addded using generic parameters instead of regular method parameters. Both old AddImplementation/ReplaceImplementation have been replaced with AddOrUpdateImplementation`3
  • Loading branch information
mfidemraizer committed Mar 20, 2017
1 parent b746ae6 commit 3e99468
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 58 deletions.
9 changes: 9 additions & 0 deletions TrackerDog.Test/ConfigurationTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using TrackerDog.CollectionHandling;
using TrackerDog.Configuration;

namespace TrackerDog.Test
Expand Down Expand Up @@ -226,5 +227,13 @@ public void CanConfigureWithNestedTypes()

Assert.IsNotNull(instance);
}

[TestMethod]
public void CanReplaceCollectionChangeTrackingImplementation()
{
IObjectChangeTrackingConfiguration config = ObjectChangeTracking.CreateConfiguration();

config.Collections.AddOrUpdateImplementation<ICollection<string>, List<string>, DefaultCollectionChangeInterceptor<string>>();
}
}
}
23 changes: 6 additions & 17 deletions TrackerDog/Configuration/ICollectionChangeTrackingConfiguration.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Collections;
using System.Collections.Generic;

namespace TrackerDog.Configuration
Expand All @@ -21,22 +22,10 @@ public interface ICollectionChangeTrackingConfiguration
/// <param name="some">A collection interface type</param>
/// <returns></returns>
KeyValuePair<Type, CollectionImplementation> GetImplementation(Type some);

/// <summary>
/// Adds a collection implementation
/// </summary>
/// <param name="interfaceType">Collection interface type</param>
/// <param name="implementationType">Implementation type to given collection interface type</param>
/// <param name="collectionChangeInterceptor">Collection change interceptor</param>
void AddImplementation(Type interfaceType, Type implementationType, Type collectionChangeInterceptor);


/// <summary>
/// Replaces an existing collection implementation and looks for it by given collection interface type.
/// </summary>
/// <param name="interfaceType">Collection interface type</param>
/// <param name="implementationType">Implementation type to given collection interface type</param>
/// <param name="collectionChangeInterceptor">Collection change interceptor</param>
void ReplaceImplementation(Type interfaceType, Type implementationType, Type collectionChangeInterceptor);

void AddOrUpdateImplementation<TInterface, TImplementation, TCollectionChangeInterceptor>()
where TInterface : IEnumerable
where TImplementation : class, TInterface
where TCollectionChangeInterceptor : class;
}
}
56 changes: 15 additions & 41 deletions TrackerDog/Configuration/TrackableCollectionConfiguration.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
Expand All @@ -19,11 +20,11 @@ internal sealed class TrackableCollectionConfiguration : ICollectionChangeTracki
/// </summary>
public TrackableCollectionConfiguration()
{
AddImplementation(typeof(ISet<>), typeof(HashSet<>), typeof(SetChangeInterceptor<>));
AddImplementation(typeof(IList<>), typeof(List<>), typeof(DefaultCollectionChangeInterceptor<>));
AddImplementation(typeof(IDictionary<,>), typeof(Dictionary<,>), typeof(DefaultCollectionChangeInterceptor<>));
AddImplementation(typeof(ICollection<>), typeof(List<>), typeof(DefaultCollectionChangeInterceptor<>));
AddImplementation(typeof(IEnumerable<>), typeof(List<>), typeof(DefaultCollectionChangeInterceptor<>));
AddOrUpdateImplementation<ISet<string>, HashSet<string>, SetChangeInterceptor<string>>();
AddOrUpdateImplementation<IList<string>, List<string>, DefaultCollectionChangeInterceptor<string>>();
AddOrUpdateImplementation<IDictionary<string, string>, Dictionary<string, string>, DefaultCollectionChangeInterceptor<string>>();
AddOrUpdateImplementation<ICollection<string>, List<string>, DefaultCollectionChangeInterceptor<string>>();
AddOrUpdateImplementation<IEnumerable<string>, List<string>, DefaultCollectionChangeInterceptor<string>>();
}

/// <summary>
Expand Down Expand Up @@ -101,47 +102,20 @@ public KeyValuePair<Type, CollectionImplementation> GetImplementation(Type some)
}
}

/// <summary>
/// Adds a new implementation to some collection interface. This method will not support replacing
/// an already added interface/implementation pair.
/// </summary>
/// <param name="interfaceType">The collection interface</param>
/// <param name="implementationType">The collection implementation</param>
/// <param name="collectionChangeInterceptor">An implementation to interface type which intercepts calls to the whole collection type to handle changes</param>
public void AddImplementation(Type interfaceType, Type implementationType, Type collectionChangeInterceptor)
public void AddOrUpdateImplementation<TInterface, TImplementation, TCollectionChangeInterceptor>()
where TInterface : IEnumerable
where TImplementation : class, TInterface
where TCollectionChangeInterceptor : class
{
Contract.Requires(() => interfaceType != null, "Cannot add an implementation of a null interface");
Contract.Requires(() => interfaceType.GetTypeInfo().IsInterface, "Given type must be an interface");
Contract.Requires(() => interfaceType.GetTypeInfo().IsGenericTypeDefinition, "Given collection interface must be provided as a generic type definition");
Contract.Requires(() => collectionChangeInterceptor.GetInterfaces().Any(i => collectionChangeInterceptor.GetInterfaces().Any(i2 => i2 == i)), "Provided change interceptor type must be assignable to collection implementation type");

lock (_syncLock)
{
Contract.Assert(() => !Implementations.ContainsKey(interfaceType), "Adding an implementation can be done once");

Implementations.Add(interfaceType, new CollectionImplementation(implementationType, collectionChangeInterceptor));
}
}
Type interfaceType = typeof(TInterface).GetTypeInfo().GetGenericTypeDefinition();
Type implementationType = typeof(TImplementation).GetTypeInfo().GetGenericTypeDefinition();
Type collectionChangeInterceptorType = typeof(TCollectionChangeInterceptor).GetTypeInfo().GetGenericTypeDefinition();

/// <summary>
/// Replaces an existing collection interface/implementation or adds it.
/// </summary>
/// <param name="interfaceType"></param>
/// <param name="implementationType"></param>
/// <param name="collectionChangeInterceptor">An implementation to interface type which intercepts calls to the whole collection type to handle changes</param>
public void ReplaceImplementation(Type interfaceType, Type implementationType, Type collectionChangeInterceptor)
{
Contract.Requires(() => interfaceType != null, "Cannot add an implementation of a null interface");
Contract.Requires(() => interfaceType.GetTypeInfo().IsInterface, "Given type must be an interface");
Contract.Requires(() => interfaceType.GetTypeInfo().IsGenericTypeDefinition, "Given collection interface must be provided as a generic type definition");
Contract.Requires(() => interfaceType.IsAssignableFrom(collectionChangeInterceptor), "Provided change interceptor type must be assignable to collection implementation type");
Contract.Requires(() => interfaceType.GetTypeInfo().IsInterface, $"Given type in generic parameter '{nameof(TInterface)}' must be an interface");

lock (_syncLock)
{
if (Implementations.ContainsKey(interfaceType))
Implementations[interfaceType] = new CollectionImplementation(implementationType, collectionChangeInterceptor);
else
AddImplementation(interfaceType, implementationType, collectionChangeInterceptor);
Implementations[interfaceType] = new CollectionImplementation(implementationType, collectionChangeInterceptorType);
}
}
}
Expand Down

0 comments on commit 3e99468

Please sign in to comment.