From 3e787da81d72146af496bc68191ba7b971a3ce8b Mon Sep 17 00:00:00 2001 From: Einar Ingebrigtsen Date: Sat, 9 May 2015 20:40:54 +0200 Subject: [PATCH] Refactoring TypeDiscoverer a bit to accommodate new needs + changing signatures Basically we are going to need to be able to find types from any enumerable of types. TypeDiscoverer had a bunch of this functionality we wanted but coupled together with how it wants to do things. Extracting out the finding of types part into its own ITypeFinder enables us to reuse the finding bits. Worth mentioning is that all signatures returning arrays of Type are now returning IEnumerable instead. This affected some implementations! --- .../Bifrost.Silverlight.csproj | 6 + Source/Bifrost.Specs/Bifrost.Specs.csproj | 8 +- .../given/a_type_discoverer.cs | 33 +++++- ...inding_type_by_name_that_does_not_exist.cs | 10 +- .../when_finding_type_by_name_that_exists.cs | 2 +- ...ing_types_with_multiple_implementations.cs | 13 +- ...implementations_but_asking_for_a_single.cs | 15 --- ...ding_types_with_only_one_implementation.cs | 6 +- .../Execution/for_TypeFinder/Stubs.cs | 27 +++++ .../for_TypeFinder/given/a_type_finder.cs | 25 ++++ ...inding_type_by_name_that_does_not_exist.cs | 16 +++ .../when_finding_type_by_name_that_exists.cs | 17 +++ ...ing_types_with_multiple_implementations.cs | 19 +++ ...implementations_but_asking_for_a_single.cs | 16 +++ ...ding_types_with_only_one_implementation.cs | 17 +++ .../Bifrost.Web/Services/JsonInterceptor.cs | 3 +- Source/Bifrost/Bifrost.csproj | 4 +- .../Configuration/Defaults/DefaultBindings.cs | 1 + .../ExecutionContextDetailsPopulator.cs | 5 +- ...erAssembly.cs => ICanSpecifyAssemblies.cs} | 15 +-- Source/Bifrost/Execution/ITypeDiscoverer.cs | 4 +- Source/Bifrost/Execution/ITypeFinder.cs | 87 ++++++++++++++ Source/Bifrost/Execution/TypeDiscoverer.cs | 112 +++--------------- Source/Bifrost/Execution/TypeFinder.cs | 99 ++++++++++++++++ Source/Bifrost/Execution/TypeImporter.cs | 46 ++++--- .../Execution/UnableToResolveTypeByName.cs | 2 +- Source/Bifrost/Read/ReadModelFilters.cs | 5 +- 27 files changed, 452 insertions(+), 161 deletions(-) delete mode 100644 Source/Bifrost.Specs/Execution/for_TypeDiscoverer/when_finding_types_with_multiple_implementations_but_asking_for_a_single.cs create mode 100644 Source/Bifrost.Specs/Execution/for_TypeFinder/Stubs.cs create mode 100644 Source/Bifrost.Specs/Execution/for_TypeFinder/given/a_type_finder.cs create mode 100644 Source/Bifrost.Specs/Execution/for_TypeFinder/when_finding_type_by_name_that_does_not_exist.cs create mode 100644 Source/Bifrost.Specs/Execution/for_TypeFinder/when_finding_type_by_name_that_exists.cs create mode 100644 Source/Bifrost.Specs/Execution/for_TypeFinder/when_finding_types_with_multiple_implementations.cs create mode 100644 Source/Bifrost.Specs/Execution/for_TypeFinder/when_finding_types_with_multiple_implementations_but_asking_for_a_single.cs create mode 100644 Source/Bifrost.Specs/Execution/for_TypeFinder/when_finding_types_with_only_one_implementation.cs rename Source/Bifrost/Execution/{ICanFilterAssembly.cs => ICanSpecifyAssemblies.cs} (68%) create mode 100644 Source/Bifrost/Execution/ITypeFinder.cs create mode 100644 Source/Bifrost/Execution/TypeFinder.cs diff --git a/Source/Bifrost.Silverlight/Bifrost.Silverlight.csproj b/Source/Bifrost.Silverlight/Bifrost.Silverlight.csproj index 699fb0d66..c7ba63d9d 100644 --- a/Source/Bifrost.Silverlight/Bifrost.Silverlight.csproj +++ b/Source/Bifrost.Silverlight/Bifrost.Silverlight.csproj @@ -626,6 +626,9 @@ Execution\ITypeDiscoverer.cs + + Execution\ITypeFinder.cs + Execution\ITypeImporter.cs @@ -644,6 +647,9 @@ Execution\TypeDiscoverer.cs + + Execution\TypeFinder.cs + Execution\TypeImporter.cs diff --git a/Source/Bifrost.Specs/Bifrost.Specs.csproj b/Source/Bifrost.Specs/Bifrost.Specs.csproj index 982d86bd6..ee3b4e6a2 100644 --- a/Source/Bifrost.Specs/Bifrost.Specs.csproj +++ b/Source/Bifrost.Specs/Bifrost.Specs.csproj @@ -331,6 +331,13 @@ + + + + + + + @@ -722,7 +729,6 @@ - diff --git a/Source/Bifrost.Specs/Execution/for_TypeDiscoverer/given/a_type_discoverer.cs b/Source/Bifrost.Specs/Execution/for_TypeDiscoverer/given/a_type_discoverer.cs index cb15b9bd8..001cad33f 100644 --- a/Source/Bifrost.Specs/Execution/for_TypeDiscoverer/given/a_type_discoverer.cs +++ b/Source/Bifrost.Specs/Execution/for_TypeDiscoverer/given/a_type_discoverer.cs @@ -1,4 +1,7 @@ -using System.Reflection; +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Runtime.InteropServices; using Bifrost.Execution; using Machine.Specifications; using Moq; @@ -7,14 +10,32 @@ namespace Bifrost.Specs.Execution.for_TypeDiscoverer.given { public class a_type_discoverer { - protected static TypeDiscoverer TypeDiscoverer; + protected static TypeDiscoverer type_discoverer; + protected static Mock<_Assembly> assembly_mock; + protected static Type[] types; + + protected static Mock assemblies_mock; + protected static Mock type_finder_mock; Establish context = () => { - var assembliesMock = new Mock(); - assembliesMock.Setup(x => x.GetAll()).Returns(new[] - {typeof (a_type_discoverer).Assembly}); - TypeDiscoverer = new TypeDiscoverer(assembliesMock.Object); + types = new[] { + typeof(ISingle), + typeof(Single), + typeof(IMultiple), + typeof(FirstMultiple), + typeof(SecondMultiple) + }; + + assembly_mock = new Mock<_Assembly>(); + assembly_mock.Setup(a => a.GetTypes()).Returns(types); + assembly_mock.Setup(a => a.FullName).Returns("A.Full.Name"); + + assemblies_mock = new Mock(); + assemblies_mock.Setup(x => x.GetAll()).Returns(new[] { assembly_mock.Object }); + + type_finder_mock = new Mock(); + type_discoverer = new TypeDiscoverer(assemblies_mock.Object, type_finder_mock.Object); }; } } diff --git a/Source/Bifrost.Specs/Execution/for_TypeDiscoverer/when_finding_type_by_name_that_does_not_exist.cs b/Source/Bifrost.Specs/Execution/for_TypeDiscoverer/when_finding_type_by_name_that_does_not_exist.cs index 7624f9af2..8dac029ee 100644 --- a/Source/Bifrost.Specs/Execution/for_TypeDiscoverer/when_finding_type_by_name_that_does_not_exist.cs +++ b/Source/Bifrost.Specs/Execution/for_TypeDiscoverer/when_finding_type_by_name_that_does_not_exist.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using Bifrost.Execution; using Machine.Specifications; @@ -7,9 +8,12 @@ namespace Bifrost.Specs.Execution.for_TypeDiscoverer [Subject(typeof(TypeDiscoverer))] public class when_finding_type_by_name_that_does_not_exist : given.a_type_discoverer { - static Type typeFound; - Because of = () => typeFound = TypeDiscoverer.FindTypeByFullName(typeof(Single).FullName + "Blah"); + static Type type_found; - It should_be_null = () => typeFound.ShouldBeNull(); + Establish context = () => type_finder_mock.Setup(t => t.FindTypeByFullName(Moq.It.IsAny>(), Moq.It.IsAny())).Returns((Type)null); + + Because of = () => type_found = type_discoverer.FindTypeByFullName(typeof(Single).FullName + "Blah"); + + It should_be_null = () => type_found.ShouldBeNull(); } } \ No newline at end of file diff --git a/Source/Bifrost.Specs/Execution/for_TypeDiscoverer/when_finding_type_by_name_that_exists.cs b/Source/Bifrost.Specs/Execution/for_TypeDiscoverer/when_finding_type_by_name_that_exists.cs index 947ce47dd..a94fefaaa 100644 --- a/Source/Bifrost.Specs/Execution/for_TypeDiscoverer/when_finding_type_by_name_that_exists.cs +++ b/Source/Bifrost.Specs/Execution/for_TypeDiscoverer/when_finding_type_by_name_that_exists.cs @@ -8,7 +8,7 @@ namespace Bifrost.Specs.Execution.for_TypeDiscoverer public class when_finding_type_by_name_that_exists : given.a_type_discoverer { static Type typeFound; - Because of = () => typeFound = TypeDiscoverer.FindTypeByFullName(typeof(Single).FullName); + Because of = () => typeFound = type_discoverer.FindTypeByFullName(typeof(Single).FullName); It should_not_return_null = () => typeFound.ShouldNotBeNull(); It should_return_the_correct_type = () => typeFound.ShouldEqual(typeof(Single)); diff --git a/Source/Bifrost.Specs/Execution/for_TypeDiscoverer/when_finding_types_with_multiple_implementations.cs b/Source/Bifrost.Specs/Execution/for_TypeDiscoverer/when_finding_types_with_multiple_implementations.cs index dc21d463b..fb7ea6a7d 100644 --- a/Source/Bifrost.Specs/Execution/for_TypeDiscoverer/when_finding_types_with_multiple_implementations.cs +++ b/Source/Bifrost.Specs/Execution/for_TypeDiscoverer/when_finding_types_with_multiple_implementations.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using Bifrost.Execution; using Machine.Specifications; @@ -7,11 +8,13 @@ namespace Bifrost.Specs.Execution.for_TypeDiscoverer [Subject(typeof(TypeDiscoverer))] public class when_finding_types_with_multiple_implementations : given.a_type_discoverer { - static Type[] typesFound; - Because we_find_multiple = () => typesFound = TypeDiscoverer.FindMultiple(); + static IEnumerable types_found; - It should_not_return_null = () => typesFound.ShouldNotBeNull(); - It should_return_2_types = () => typesFound.Length.ShouldEqual(2); - It should_contain_the_expected_types = () => typesFound.ShouldContain(typeof (FirstMultiple), typeof (SecondMultiple)); + Establish context = () => type_finder_mock.Setup(t => t.FindMultiple(Moq.It.IsAny>())).Returns(new[] { typeof(FirstMultiple), typeof(SecondMultiple) }); + + Because of = () => types_found = type_discoverer.FindMultiple(); + + It should_not_return_null = () => types_found.ShouldNotBeNull(); + It should_contain_the_types_found_by_the_finder = () => types_found.ShouldContain(typeof (FirstMultiple), typeof (SecondMultiple)); } } \ No newline at end of file diff --git a/Source/Bifrost.Specs/Execution/for_TypeDiscoverer/when_finding_types_with_multiple_implementations_but_asking_for_a_single.cs b/Source/Bifrost.Specs/Execution/for_TypeDiscoverer/when_finding_types_with_multiple_implementations_but_asking_for_a_single.cs deleted file mode 100644 index 68f48ccde..000000000 --- a/Source/Bifrost.Specs/Execution/for_TypeDiscoverer/when_finding_types_with_multiple_implementations_but_asking_for_a_single.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; -using Bifrost.Execution; -using Machine.Specifications; - -namespace Bifrost.Specs.Execution.for_TypeDiscoverer -{ - [Subject(typeof(TypeDiscoverer))] - public class when_finding_types_with_multiple_implementations_but_asking_for_a_single : given.a_type_discoverer - { - static Exception Exception; - Because we_ask_for_a_single = () => Exception = Catch.Exception(() => TypeDiscoverer.FindSingle()); - - It should_throw_an_ArgumentException = () => Exception.ShouldBeOfExactType(); - } -} \ No newline at end of file diff --git a/Source/Bifrost.Specs/Execution/for_TypeDiscoverer/when_finding_types_with_only_one_implementation.cs b/Source/Bifrost.Specs/Execution/for_TypeDiscoverer/when_finding_types_with_only_one_implementation.cs index 3e294213a..f7d87e64d 100644 --- a/Source/Bifrost.Specs/Execution/for_TypeDiscoverer/when_finding_types_with_only_one_implementation.cs +++ b/Source/Bifrost.Specs/Execution/for_TypeDiscoverer/when_finding_types_with_only_one_implementation.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using Bifrost.Execution; using Machine.Specifications; @@ -8,7 +9,10 @@ namespace Bifrost.Specs.Execution.for_TypeDiscoverer public class when_finding_types_with_only_one_implementation : given.a_type_discoverer { static Type typeFound; - Because we_find_single = () => typeFound = TypeDiscoverer.FindSingle(); + + Establish context = () => type_finder_mock.Setup(t => t.FindSingle(Moq.It.IsAny>())).Returns(typeof(Single)); + + Because we_find_single = () => typeFound = type_discoverer.FindSingle(); It should_not_return_null = () => typeFound.ShouldNotBeNull(); It should_return_correct_implementation_when = () => typeFound.ShouldEqual(typeof (Single)); diff --git a/Source/Bifrost.Specs/Execution/for_TypeFinder/Stubs.cs b/Source/Bifrost.Specs/Execution/for_TypeFinder/Stubs.cs new file mode 100644 index 000000000..7dbac15f4 --- /dev/null +++ b/Source/Bifrost.Specs/Execution/for_TypeFinder/Stubs.cs @@ -0,0 +1,27 @@ +namespace Bifrost.Specs.Execution.for_TypeFinder +{ + public interface ISingle + { + + } + + public class Single : ISingle + { + + } + + public interface IMultiple + { + + } + + public class FirstMultiple : IMultiple + { + + } + + public class SecondMultiple : IMultiple + { + + } +} diff --git a/Source/Bifrost.Specs/Execution/for_TypeFinder/given/a_type_finder.cs b/Source/Bifrost.Specs/Execution/for_TypeFinder/given/a_type_finder.cs new file mode 100644 index 000000000..7b7a100c7 --- /dev/null +++ b/Source/Bifrost.Specs/Execution/for_TypeFinder/given/a_type_finder.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using Bifrost.Execution; +using Machine.Specifications; + +namespace Bifrost.Specs.Execution.for_TypeFinder.given +{ + public class a_type_finder + { + protected static TypeFinder type_finder; + protected static IEnumerable types; + + Establish context = () => + { + types = new[] { + typeof(ISingle), + typeof(Single), + typeof(IMultiple), + typeof(FirstMultiple), + typeof(SecondMultiple) + }; + type_finder = new TypeFinder(); + }; + } +} diff --git a/Source/Bifrost.Specs/Execution/for_TypeFinder/when_finding_type_by_name_that_does_not_exist.cs b/Source/Bifrost.Specs/Execution/for_TypeFinder/when_finding_type_by_name_that_does_not_exist.cs new file mode 100644 index 000000000..3ec64ffd6 --- /dev/null +++ b/Source/Bifrost.Specs/Execution/for_TypeFinder/when_finding_type_by_name_that_does_not_exist.cs @@ -0,0 +1,16 @@ +using System; +using Bifrost.Execution; +using Machine.Specifications; + +namespace Bifrost.Specs.Execution.for_TypeFinder +{ + [Subject(typeof(TypeFinder))] + public class when_finding_type_by_name_that_does_not_exist : given.a_type_finder + { + static Exception exception; + + Because of = () => exception = Catch.Exception(() => type_finder.FindTypeByFullName(types, typeof(Single).FullName + "Blah")); + + It should_be_throw_unable_to_resolve_type_by_name = () => exception.ShouldBeOfExactType(); + } +} \ No newline at end of file diff --git a/Source/Bifrost.Specs/Execution/for_TypeFinder/when_finding_type_by_name_that_exists.cs b/Source/Bifrost.Specs/Execution/for_TypeFinder/when_finding_type_by_name_that_exists.cs new file mode 100644 index 000000000..ab9a0620f --- /dev/null +++ b/Source/Bifrost.Specs/Execution/for_TypeFinder/when_finding_type_by_name_that_exists.cs @@ -0,0 +1,17 @@ +using System; +using Bifrost.Execution; +using Machine.Specifications; + +namespace Bifrost.Specs.Execution.for_TypeFinder +{ + [Subject(typeof(TypeFinder))] + public class when_finding_type_by_name_that_exists : given.a_type_finder + { + static Type type_found; + + Because of = () => type_found = type_finder.FindTypeByFullName(types, typeof(Single).FullName); + + It should_not_return_null = () => type_found.ShouldNotBeNull(); + It should_return_the_correct_type = () => type_found.ShouldEqual(typeof(Single)); + } +} \ No newline at end of file diff --git a/Source/Bifrost.Specs/Execution/for_TypeFinder/when_finding_types_with_multiple_implementations.cs b/Source/Bifrost.Specs/Execution/for_TypeFinder/when_finding_types_with_multiple_implementations.cs new file mode 100644 index 000000000..5e65707dc --- /dev/null +++ b/Source/Bifrost.Specs/Execution/for_TypeFinder/when_finding_types_with_multiple_implementations.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Bifrost.Execution; +using Machine.Specifications; + +namespace Bifrost.Specs.Execution.for_TypeFinder +{ + [Subject(typeof(TypeFinder))] + public class when_finding_types_with_multiple_implementations : given.a_type_finder + { + static IEnumerable types_found; + + Because of = () => types_found = type_finder.FindMultiple(types); + + It should_not_return_null = () => types_found.ShouldNotBeNull(); + It should_contain_the_expected_types = () => types_found.ShouldContain(typeof (FirstMultiple), typeof (SecondMultiple)); + } +} \ No newline at end of file diff --git a/Source/Bifrost.Specs/Execution/for_TypeFinder/when_finding_types_with_multiple_implementations_but_asking_for_a_single.cs b/Source/Bifrost.Specs/Execution/for_TypeFinder/when_finding_types_with_multiple_implementations_but_asking_for_a_single.cs new file mode 100644 index 000000000..75928a8b8 --- /dev/null +++ b/Source/Bifrost.Specs/Execution/for_TypeFinder/when_finding_types_with_multiple_implementations_but_asking_for_a_single.cs @@ -0,0 +1,16 @@ +using System; +using Bifrost.Execution; +using Machine.Specifications; + +namespace Bifrost.Specs.Execution.for_TypeFinder +{ + [Subject(typeof(TypeFinder))] + public class when_finding_types_with_multiple_implementations_but_asking_for_a_single : given.a_type_finder + { + static Exception exception; + + Because of = () => exception = Catch.Exception(() => type_finder.FindSingle(types)); + + It should_throw_an_ArgumentException = () => exception.ShouldBeOfExactType(); + } +} \ No newline at end of file diff --git a/Source/Bifrost.Specs/Execution/for_TypeFinder/when_finding_types_with_only_one_implementation.cs b/Source/Bifrost.Specs/Execution/for_TypeFinder/when_finding_types_with_only_one_implementation.cs new file mode 100644 index 000000000..6fa01f4c0 --- /dev/null +++ b/Source/Bifrost.Specs/Execution/for_TypeFinder/when_finding_types_with_only_one_implementation.cs @@ -0,0 +1,17 @@ +using System; +using Bifrost.Execution; +using Machine.Specifications; + +namespace Bifrost.Specs.Execution.for_TypeFinder +{ + [Subject(typeof(TypeFinder))] + public class when_finding_types_with_only_one_implementation : given.a_type_finder + { + static Type type_found; + + Because of = () => type_found = type_finder.FindSingle(types); + + It should_not_return_null = () => type_found.ShouldNotBeNull(); + It should_return_correct_implementation_when = () => type_found.ShouldEqual(typeof (Single)); + } +} \ No newline at end of file diff --git a/Source/Bifrost.Web/Services/JsonInterceptor.cs b/Source/Bifrost.Web/Services/JsonInterceptor.cs index 1d92757e2..f4c183721 100644 --- a/Source/Bifrost.Web/Services/JsonInterceptor.cs +++ b/Source/Bifrost.Web/Services/JsonInterceptor.cs @@ -3,13 +3,14 @@ using Newtonsoft.Json.Linq; using System; using System.Linq; +using System.Collections.Generic; namespace Bifrost.Web.Services { [Singleton] public class JsonInterceptor : IJsonInterceptor { - private readonly Type[] _valueInterceptors; + private readonly IEnumerable _valueInterceptors; private readonly IContainer _container; public JsonInterceptor(ITypeDiscoverer typeDiscoverer, IContainer container) diff --git a/Source/Bifrost/Bifrost.csproj b/Source/Bifrost/Bifrost.csproj index 6cc721ee5..ddfd14094 100644 --- a/Source/Bifrost/Bifrost.csproj +++ b/Source/Bifrost/Bifrost.csproj @@ -159,12 +159,14 @@ - + + + diff --git a/Source/Bifrost/Configuration/Defaults/DefaultBindings.cs b/Source/Bifrost/Configuration/Defaults/DefaultBindings.cs index b5b699c27..183584bc0 100644 --- a/Source/Bifrost/Configuration/Defaults/DefaultBindings.cs +++ b/Source/Bifrost/Configuration/Defaults/DefaultBindings.cs @@ -51,6 +51,7 @@ public void Initialize(IContainer container) container.Bind(_assemblyProvider); container.Bind(typeof(global::Bifrost.Execution.Assemblies), BindingLifecycle.Singleton); container.Bind(typeof(TypeDiscoverer), BindingLifecycle.Singleton); + container.Bind(typeof(TypeFinder), BindingLifecycle.Singleton); } #pragma warning restore 1591 // Xml Comments } diff --git a/Source/Bifrost/Execution/ExecutionContextDetailsPopulator.cs b/Source/Bifrost/Execution/ExecutionContextDetailsPopulator.cs index 704d8de67..14d0428ab 100644 --- a/Source/Bifrost/Execution/ExecutionContextDetailsPopulator.cs +++ b/Source/Bifrost/Execution/ExecutionContextDetailsPopulator.cs @@ -16,8 +16,9 @@ // limitations under the License. // #endregion - using System; +using System.Collections.Generic; + namespace Bifrost.Execution { /// @@ -27,7 +28,7 @@ public class ExecutionContextDetailsPopulator : IExecutionContextDetailsPopulato { ITypeDiscoverer _typeDiscoverer; IContainer _container; - Type[] _populatorTypes; + IEnumerable _populatorTypes; /// /// Initializes an instance of diff --git a/Source/Bifrost/Execution/ICanFilterAssembly.cs b/Source/Bifrost/Execution/ICanSpecifyAssemblies.cs similarity index 68% rename from Source/Bifrost/Execution/ICanFilterAssembly.cs rename to Source/Bifrost/Execution/ICanSpecifyAssemblies.cs index d5cc6b7d7..d1ae68f63 100644 --- a/Source/Bifrost/Execution/ICanFilterAssembly.cs +++ b/Source/Bifrost/Execution/ICanSpecifyAssemblies.cs @@ -16,13 +16,12 @@ // limitations under the License. // #endregion -using System.Reflection; -using System.Runtime.InteropServices; +using Bifrost.Configuration.Assemblies; namespace Bifrost.Execution { /// - /// Defines something that tell wether or not to filter away an assembly. + /// Specifies what assemblies to include /// /// /// Typically used by implementations of to @@ -30,14 +29,12 @@ namespace Bifrost.Execution /// which relies on knowing about assemblies /// to be able to discover types. /// - public interface ICanFilterAssembly + public interface ICanSpecifyAssemblies { /// - /// Method that gets called participating in the chain to decide wether or - /// not an assembly should be included + /// Method that gets called for specifying which assemblies to include or not /// - /// to check - /// True if it should be included, false if not - bool ShouldInclude(_Assembly assembly); + /// object to specfiy on + void Specify(AssembliesConfiguration configuration); } } diff --git a/Source/Bifrost/Execution/ITypeDiscoverer.cs b/Source/Bifrost/Execution/ITypeDiscoverer.cs index 2b3d8f485..48ec63cde 100644 --- a/Source/Bifrost/Execution/ITypeDiscoverer.cs +++ b/Source/Bifrost/Execution/ITypeDiscoverer.cs @@ -53,7 +53,7 @@ public interface ITypeDiscoverer /// If the base type is an interface, it will look for any types implementing the interface. /// If it is a class, it will find anyone inheriting from that class /// - Type[] FindMultiple(); + IEnumerable FindMultiple(); /// /// Find a single implementation of a basetype @@ -76,7 +76,7 @@ public interface ITypeDiscoverer /// If the base type is an interface, it will look for any types implementing the interface. /// If it is a class, it will find anyone inheriting from that class /// - Type[] FindMultiple(Type type); + IEnumerable FindMultiple(Type type); /// /// Find a single type using the full name, without assembly diff --git a/Source/Bifrost/Execution/ITypeFinder.cs b/Source/Bifrost/Execution/ITypeFinder.cs new file mode 100644 index 000000000..dbfafbdaf --- /dev/null +++ b/Source/Bifrost/Execution/ITypeFinder.cs @@ -0,0 +1,87 @@ +#region License +// +// Copyright (c) 2008-2015, Dolittle (http://www.dolittle.com) +// +// Licensed under the MIT License (http://opensource.org/licenses/MIT) +// +// You may not use this file except in compliance with the License. +// You may obtain a copy of the license at +// +// http://github.com/dolittle/Bifrost/blob/master/MIT-LICENSE.txt +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#endregion +using System; +using System.Collections.Generic; + +namespace Bifrost.Execution +{ + /// + /// Defines a system that is capable of finding types based on base types + /// + public interface ITypeFinder + { + /// + /// Find a single implementation of a basetype + /// + /// Types to find from + /// Basetype to find for + /// Type found + /// + /// If the base type is an interface, it will look for any types implementing the interface. + /// If it is a class, it will find anyone inheriting from that class + /// + /// If there is more than one instance found + Type FindSingle(IEnumerable types); + + /// + /// Find multiple implementations of a basetype + /// + /// Types to find from + /// Basetype to find for + /// All types implementing or inheriting from the given basetype + /// + /// If the base type is an interface, it will look for any types implementing the interface. + /// If it is a class, it will find anyone inheriting from that class + /// + IEnumerable FindMultiple(IEnumerable types); + + /// + /// Find a single implementation of a basetype + /// + /// Types to find from + /// Basetype to find for + /// Type found + /// + /// If the base type is an interface, it will look for any types implementing the interface. + /// If it is a class, it will find anyone inheriting from that class + /// + /// If there is more than one instance found + Type FindSingle(IEnumerable types, Type type); + + /// + /// Find multiple implementations of a basetype + /// + /// Types to find from + /// Basetype to find for + /// All types implementing or inheriting from the given basetype + /// + /// If the base type is an interface, it will look for any types implementing the interface. + /// If it is a class, it will find anyone inheriting from that class + /// + IEnumerable FindMultiple(IEnumerable types, Type type); + + /// + /// Find a single type using the full name, without assembly + /// + /// Types to find from + /// full name of the type to find + /// The type is found, null otherwise + Type FindTypeByFullName(IEnumerable types, string fullName); + } +} diff --git a/Source/Bifrost/Execution/TypeDiscoverer.cs b/Source/Bifrost/Execution/TypeDiscoverer.cs index bb6dbde19..511d33533 100644 --- a/Source/Bifrost/Execution/TypeDiscoverer.cs +++ b/Source/Bifrost/Execution/TypeDiscoverer.cs @@ -42,15 +42,14 @@ public class TypeDiscoverer : ITypeDiscoverer static List NamespaceStartingWithExclusions = new List(); IAssemblies _assemblies; + ITypeFinder _typeFinder; #if(SILVERLIGHT || WINDOWS_PHONE) - Dictionary> _types; + List _types; #else - ConcurrentDictionary> _types; + ConcurrentBag _types; #endif - IDictionary _implementingTypes; - /// /// Exclude discovering of types in a specific namespace /// @@ -63,17 +62,18 @@ public static void ExcludeNamespaceStartingWith(string name) /// /// Initializes a new instance of TypeDiscoverer /// - public TypeDiscoverer(IAssemblies assemblies) + /// for getting assemblies + /// for finding types from all collected types + public TypeDiscoverer(IAssemblies assemblies, ITypeFinder typeFinder) { _assemblies = assemblies; + _typeFinder = typeFinder; #if(SILVERLIGHT) - _types = new Dictionary>(); + _types = new List(); #else - _types = new ConcurrentDictionary>(); + _types = new ConcurrentBag(); #endif - - _implementingTypes = new Dictionary(); CollectTypes(); } @@ -81,90 +81,41 @@ public TypeDiscoverer(IAssemblies assemblies) #pragma warning disable 1591 // Xml Comments public IEnumerable GetAll() { - return _types.Values.SelectMany(x => x.Values.ToList()); + return _types; } public Type FindSingle() { - var type = FindSingle(typeof(T)); - return type; + return _typeFinder.FindSingle(_types); } - public Type[] FindMultiple() + public IEnumerable FindMultiple() { - var types = FindMultiple(typeof(T)); - return types; + return _typeFinder.FindMultiple(_types); } public Type FindSingle(Type type) { - var typesFound = Find(type); - - if (typesFound.Length > 1) - throw new MultipleTypesFoundException(string.Format("More than one type found for '{0}'", type.FullName)); - return typesFound.SingleOrDefault(); + return _typeFinder.FindSingle(_types, type); } - public Type[] FindMultiple(Type type) + public IEnumerable FindMultiple(Type type) { - var typesFound = Find(type); - return typesFound; + return _typeFinder.FindMultiple(_types, type); } public Type FindTypeByFullName(string fullName) { - if (!_types.ContainsKey(fullName)) return null; - - var match = _types[fullName].Values; - - if (match.Count > 1) - { - throw new UnableToResolveTypeByName(fullName); - } - - return match.First(); + return _typeFinder.FindTypeByFullName(_types, fullName); } #pragma warning restore 1591 // Xml Comments -#if(SILVERLIGHT || WINDOWS_PHONE) - - void AddTypes(IEnumerable types) - { - foreach (var type in types) - { - if (_types.ContainsKey(type.FullName)) - { - var entry = _types[type.Assembly.FullName]; - entry[type.Assembly.FullName] = type; - } - else - { - _types.Add(type.FullName, new Dictionary {{type.Assembly.FullName, type}}); - } - } - } - -#else - void AddTypes(IEnumerable types) { - foreach (var type in types) - { - if (!_types.TryAdd(type.FullName, new Dictionary { { type.Assembly.FullName, type } })) - { - var entry = _types[type.FullName]; - - lock (entry) - { - entry[type.Assembly.FullName] = type; - } - } - - } + types.ForEach(_types.Add); } -#endif #if(WINDOWS_PHONE) void CollectTypes() @@ -245,32 +196,5 @@ static bool NameStartsWithAnExcludedNamespace(string name) { return NamespaceStartingWithExclusions.Any(name.StartsWith); } - - Type[] Find(Type type) - { - Type[] typesFound; - - Func isAssignableFrom = (t1, t2) => t2.IsAssignableFrom(t1); - if (type.IsInterface) isAssignableFrom = (t1, t2) => t1.HasInterface(t2); - - if (!_implementingTypes.TryGetValue(type, out typesFound)) - { - var query = from t in _types.Values.SelectMany(a => a.Values) - where - isAssignableFrom(t,type) && -#if(NETFX_CORE) - !t.GetTypeInfo().IsInterface && - !t.GetTypeInfo().IsAbstract -#else - !t.IsInterface && - !t.IsAbstract -#endif - select t; - typesFound = query.ToArray(); - _implementingTypes[type] = typesFound; - } - - return typesFound; - } } } diff --git a/Source/Bifrost/Execution/TypeFinder.cs b/Source/Bifrost/Execution/TypeFinder.cs new file mode 100644 index 000000000..418a702ad --- /dev/null +++ b/Source/Bifrost/Execution/TypeFinder.cs @@ -0,0 +1,99 @@ +#region License +// +// Copyright (c) 2008-2015, Dolittle (http://www.dolittle.com) +// +// Licensed under the MIT License (http://opensource.org/licenses/MIT) +// +// You may not use this file except in compliance with the License. +// You may obtain a copy of the license at +// +// http://github.com/dolittle/Bifrost/blob/master/MIT-LICENSE.txt +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#endregion +using System; +using System.Collections.Generic; +using System.Linq; +#if(SILVERLIGHT) +using System.Windows; +#endif +using Bifrost.Extensions; + +namespace Bifrost.Execution +{ + /// + /// Represents an implementation of + /// + public class TypeFinder : ITypeFinder + { +#pragma warning disable 1591 // Xml Comments + public Type FindSingle(IEnumerable types) + { + var type = FindSingle(types, typeof(T)); + return type; + } + + public IEnumerable FindMultiple(IEnumerable types) + { + var typesFound = FindMultiple(types, typeof(T)); + return typesFound; + } + + public Type FindSingle(IEnumerable types, Type type) + { + var typesFound = Find(types, type); + ThrowIfMultipleTypesFound(type, typesFound); + return typesFound.SingleOrDefault(); + } + + public IEnumerable FindMultiple(IEnumerable types, Type type) + { + var typesFound = Find(types, type); + return typesFound; + } + + public Type FindTypeByFullName(IEnumerable types, string fullName) + { + var typeFound = types.Where(t => t.FullName == fullName).SingleOrDefault(); + ThrowIfTypeNotFound(fullName, typeFound); + return typeFound; + } +#pragma warning restore 1591 // Xml Comments + Type[] Find(IEnumerable types, Type type) + { + Func isAssignableFrom = (t1, t2) => t2.IsAssignableFrom(t1); + if (type.IsInterface) isAssignableFrom = (t1, t2) => t1.HasInterface(t2); + + var query = types.Where( + t=>isAssignableFrom(t,type) && +#if(NETFX_CORE) + !t.GetTypeInfo().IsInterface && + !t.GetTypeInfo().IsAbstract + +#else + !t.IsInterface && + !t.IsAbstract +#endif + ); + + var typesFound = query.ToArray(); + return typesFound; + } + + void ThrowIfMultipleTypesFound(Type type, Type[] typesFound) + { + if (typesFound.Length > 1) + throw new MultipleTypesFoundException(string.Format("More than one type found for '{0}'", type.FullName)); + } + + void ThrowIfTypeNotFound(string fullName, Type typeFound) + { + if (typeFound == null) throw new UnableToResolveTypeByName(fullName); + } + } +} diff --git a/Source/Bifrost/Execution/TypeImporter.cs b/Source/Bifrost/Execution/TypeImporter.cs index 54750a6a8..3021e960c 100644 --- a/Source/Bifrost/Execution/TypeImporter.cs +++ b/Source/Bifrost/Execution/TypeImporter.cs @@ -17,6 +17,8 @@ // #endregion using System; +using System.Collections.Generic; +using System.Linq; namespace Bifrost.Execution { @@ -46,26 +48,19 @@ public T[] ImportMany() try { var types = _typeDiscoverer.FindMultiple(); - if( types == null ) - { - throw new ArgumentException( - string.Format("Can't import type {0}, it was not discovered", typeof(T))); - } - var instances = new T[types.Length]; - for (var instanceIndex = 0; instanceIndex < types.Length; instanceIndex++) - { - instances[instanceIndex] = (T) _container.Get(types[instanceIndex]); - } - + ThrowIfTypeCanNotBeImported(typeof(T), types); + var instances = types.Select(t => (T)_container.Get(t)).ToArray(); return instances; } catch (ArgumentException innerException) { - throw new ArgumentException( - string.Format("Can't import type {0}, see inner exception for details", typeof(T)), innerException); + ThrowUnableToImportType(typeof(T),innerException); } + return new T[0]; } + + public T Import() { try @@ -78,16 +73,33 @@ public T Import() } else { - throw new ArgumentException( - string.Format("Can't import type {0}, it was not discovered", typeof(T))); + ThrowCanNotBeImported(typeof(T)); } } catch (ArgumentException innerException) { - throw new ArgumentException( - string.Format("Can't import type {0}, see inner exception for details", typeof(T)), innerException); + ThrowUnableToImportType(typeof(T), innerException); } + return default(T); } #pragma warning restore 1591 // Xml Comments + + void ThrowUnableToImportType(Type type, ArgumentException innerException) + { + throw new ArgumentException( + string.Format("Can't import type {0}, see inner exception for details", type), innerException); + } + + void ThrowIfTypeCanNotBeImported(Type type, IEnumerable types) + { + if (types == null) ThrowCanNotBeImported(type); + } + + void ThrowCanNotBeImported(Type type) + { + throw new ArgumentException( + string.Format("Can't import type {0}, it was not discovered", type)); + } + } } \ No newline at end of file diff --git a/Source/Bifrost/Execution/UnableToResolveTypeByName.cs b/Source/Bifrost/Execution/UnableToResolveTypeByName.cs index 01d598ecb..edf819eab 100644 --- a/Source/Bifrost/Execution/UnableToResolveTypeByName.cs +++ b/Source/Bifrost/Execution/UnableToResolveTypeByName.cs @@ -29,7 +29,7 @@ public class UnableToResolveTypeByName : ArgumentException /// Initializes an instance of /// /// - public UnableToResolveTypeByName(string typeName) : base(string.Format("Unable to resolve '{0}'. More than one type found with the current name'", typeName)) + public UnableToResolveTypeByName(string typeName) : base(string.Format("Unable to resolve '{0}'.", typeName)) { } diff --git a/Source/Bifrost/Read/ReadModelFilters.cs b/Source/Bifrost/Read/ReadModelFilters.cs index 4bd9e2bd3..ff4faf502 100644 --- a/Source/Bifrost/Read/ReadModelFilters.cs +++ b/Source/Bifrost/Read/ReadModelFilters.cs @@ -18,6 +18,7 @@ #endregion using System; using System.Collections.Generic; +using System.Linq; using Bifrost.Execution; namespace Bifrost.Read @@ -28,7 +29,7 @@ namespace Bifrost.Read public class ReadModelFilters : IReadModelFilters { IContainer _container; - Type[] _filterTypes; + IEnumerable _filterTypes; /// /// Initializes an instance of @@ -45,7 +46,7 @@ public ReadModelFilters(ITypeDiscoverer typeDiscoverer, IContainer container) #pragma warning disable 1591 public IEnumerable Filter(IEnumerable readModels) { - if (_filterTypes.Length == 0) return readModels; + if (_filterTypes.Count() == 0) return readModels; foreach (var filterType in _filterTypes) {