diff --git a/Hypodermic.Tests/CMakeLists.txt b/Hypodermic.Tests/CMakeLists.txt
index cd88a7d..41c2b10 100644
--- a/Hypodermic.Tests/CMakeLists.txt
+++ b/Hypodermic.Tests/CMakeLists.txt
@@ -21,6 +21,7 @@ set(HypodermicTests_sources
GithubTests.cpp
IsCompleteTests.cpp
MemoryTests.cpp
+ NamedTests.cpp
NestedContainerTests.cpp
PerformanceTests.cpp
PersistentInstanceRegistrationTests.cpp
@@ -28,6 +29,7 @@ set(HypodermicTests_sources
ProvidedInstanceFactoryRegistrationTests.cpp
ProvidedInstanceRegistrationTests.cpp
RegistrationTests.cpp
+ UseIfNoneTests.cpp
)
include_directories("..")
diff --git a/Hypodermic.Tests/Hypodermic.Tests.vcxproj b/Hypodermic.Tests/Hypodermic.Tests.vcxproj
index d30abef..6356676 100644
--- a/Hypodermic.Tests/Hypodermic.Tests.vcxproj
+++ b/Hypodermic.Tests/Hypodermic.Tests.vcxproj
@@ -197,6 +197,7 @@
NotUsing
+
diff --git a/Hypodermic.Tests/Hypodermic.Tests.vcxproj.filters b/Hypodermic.Tests/Hypodermic.Tests.vcxproj.filters
index a9d64cf..4e5e3eb 100644
--- a/Hypodermic.Tests/Hypodermic.Tests.vcxproj.filters
+++ b/Hypodermic.Tests/Hypodermic.Tests.vcxproj.filters
@@ -53,6 +53,9 @@
Tests
+
+ Tests
+
diff --git a/Hypodermic.Tests/NamedTests.cpp b/Hypodermic.Tests/NamedTests.cpp
new file mode 100644
index 0000000..3f23816
--- /dev/null
+++ b/Hypodermic.Tests/NamedTests.cpp
@@ -0,0 +1,94 @@
+#include "stdafx.h"
+
+#include "Hypodermic/ContainerBuilder.h"
+
+#include "TestingTypes.h"
+
+
+namespace Hypodermic
+{
+namespace Testing
+{
+
+ BOOST_AUTO_TEST_SUITE(NamedTests)
+
+ BOOST_AUTO_TEST_CASE(should_resolve_named_component)
+ {
+ // Arrange
+ ContainerBuilder builder;
+
+ // Act
+ builder.registerType< DefaultConstructible1 >().named< DefaultConstructibleBase >("default1");
+
+ auto container = builder.build();
+
+ // Assert
+ auto instance = container->resolveNamed< DefaultConstructibleBase >("default1");
+ BOOST_CHECK(instance != nullptr);
+ }
+
+ BOOST_AUTO_TEST_CASE(should_not_resolve_named_component_without_its_name)
+ {
+ // Arrange
+ ContainerBuilder builder;
+
+ // Act
+ builder.registerType< DefaultConstructible1 >().named< DefaultConstructibleBase >("default1");
+
+ auto container = builder.build();
+
+ // Assert
+ auto instance = container->resolve< DefaultConstructibleBase >();
+ BOOST_CHECK(instance == nullptr);
+ }
+
+ BOOST_AUTO_TEST_CASE(should_resolve_the_right_named_component)
+ {
+ // Arrange
+ ContainerBuilder builder;
+
+ // Act
+ builder.registerType< DefaultConstructible1 >().named< DefaultConstructibleBase >("default1");
+ builder.registerType< DefaultConstructible2 >().named< DefaultConstructibleBase >("default2");
+
+ auto container = builder.build();
+
+ // Assert
+ auto instance = container->resolveNamed< DefaultConstructibleBase >("default1");
+ BOOST_CHECK(instance != nullptr);
+ BOOST_CHECK(std::dynamic_pointer_cast< DefaultConstructible1 >(instance) == instance);
+ }
+
+ BOOST_AUTO_TEST_CASE(should_not_conflict_with_anonymous_registrations)
+ {
+ // Arrange
+ ContainerBuilder builder;
+
+ // Act
+ auto instance = std::make_shared< DefaultConstructible1 >();
+ builder.registerInstance(instance).as< DefaultConstructibleBase >();
+
+ builder.registerType< DefaultConstructible1 >().named< DefaultConstructibleBase >("default");
+
+ auto container = builder.build();
+
+ // Assert
+ auto resolvedInstance = container->resolve< DefaultConstructibleBase >();
+ auto namedInstance1 = container->resolveNamed< DefaultConstructibleBase >("default");
+ auto namedInstance2 = container->resolveNamed< DefaultConstructibleBase >("default");
+
+ BOOST_CHECK(resolvedInstance == instance);
+
+ BOOST_CHECK(namedInstance1 != nullptr);
+ BOOST_CHECK(namedInstance1 != instance);
+
+ BOOST_CHECK(namedInstance2 != nullptr);
+ BOOST_CHECK(namedInstance2 != instance);
+
+ BOOST_CHECK(namedInstance1 != namedInstance2);
+ }
+
+ BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace Testing
+} // namespace Hypodermic
\ No newline at end of file
diff --git a/Hypodermic/AutowireableConstructorRegistrationDescriptor.h b/Hypodermic/AutowireableConstructorRegistrationDescriptor.h
index f3a544a..691547c 100644
--- a/Hypodermic/AutowireableConstructorRegistrationDescriptor.h
+++ b/Hypodermic/AutowireableConstructorRegistrationDescriptor.h
@@ -5,6 +5,7 @@
#include "Hypodermic/ConstructorDescriptor.h"
#include "Hypodermic/InstanceFactory.h"
#include "Hypodermic/Log.h"
+#include "Hypodermic/Named.h"
#include "Hypodermic/OnActivated.h"
#include "Hypodermic/RegistrationBuilder.h"
#include "Hypodermic/RegistrationDescriptorBase.h"
@@ -20,6 +21,7 @@ namespace Hypodermic
class AutowireableConstructorRegistrationDescriptor : public RegistrationDescriptorBase< AutowireableConstructorRegistrationDescriptor< TDescriptorInfo >, TDescriptorInfo >,
public RegistrationDescriptorOperations::As< AutowireableConstructorRegistrationDescriptor< TDescriptorInfo >, TDescriptorInfo >,
public RegistrationDescriptorOperations::AsSelf< AutowireableConstructorRegistrationDescriptor< TDescriptorInfo >, TDescriptorInfo >,
+ public RegistrationDescriptorOperations::Named< AutowireableConstructorRegistrationDescriptor< TDescriptorInfo >, TDescriptorInfo >,
public RegistrationDescriptorOperations::OnActivated< AutowireableConstructorRegistrationDescriptor< TDescriptorInfo >, TDescriptorInfo >,
public RegistrationDescriptorOperations::SingleInstance< AutowireableConstructorRegistrationDescriptor< TDescriptorInfo >, TDescriptorInfo >,
public RegistrationDescriptorOperations::UseIfNone< AutowireableConstructorRegistrationDescriptor< TDescriptorInfo >, TDescriptorInfo >,
@@ -27,6 +29,7 @@ namespace Hypodermic
{
friend class RegistrationDescriptorOperations::As< AutowireableConstructorRegistrationDescriptor< TDescriptorInfo >, TDescriptorInfo >;
friend class RegistrationDescriptorOperations::AsSelf< AutowireableConstructorRegistrationDescriptor< TDescriptorInfo >, TDescriptorInfo >;
+ friend class RegistrationDescriptorOperations::Named< AutowireableConstructorRegistrationDescriptor< TDescriptorInfo >, TDescriptorInfo >;
friend class RegistrationDescriptorOperations::OnActivated< AutowireableConstructorRegistrationDescriptor< TDescriptorInfo >, TDescriptorInfo >;
friend class RegistrationDescriptorOperations::SingleInstance< AutowireableConstructorRegistrationDescriptor< TDescriptorInfo >, TDescriptorInfo >;
friend class RegistrationDescriptorOperations::UseIfNone< AutowireableConstructorRegistrationDescriptor< TDescriptorInfo >, TDescriptorInfo >;
diff --git a/Hypodermic/CMakeLists.txt b/Hypodermic/CMakeLists.txt
index 6545526..ca7d4dc 100644
--- a/Hypodermic/CMakeLists.txt
+++ b/Hypodermic/CMakeLists.txt
@@ -58,6 +58,8 @@ set(Hypodermic_headers
MetaInsert.h
MetaMap.h
MetaPair.h
+ Named.h
+ NamedTypeAlias.h
NestedRegistrationScope.h
NoopLoggerSink.h
OnActivated.h
@@ -89,6 +91,7 @@ set(Hypodermic_headers
TypeAliases.h
TypeAliasKey.h
TypeInfo.h
+ UseIfNone.h
With.h
)
diff --git a/Hypodermic/ComponentContext.h b/Hypodermic/ComponentContext.h
index 4e53724..595bf27 100644
--- a/Hypodermic/ComponentContext.h
+++ b/Hypodermic/ComponentContext.h
@@ -65,6 +65,20 @@ namespace Hypodermic
return resolveAll< T >(createKeyForType< T >());
}
+ ///
+ /// Resolve an instance of type T by both its type and a name
+ ///
+ /// The type to resolve (i.e. get an instance of T)
+ /// The name of the object to resolve
+ /// A shared pointer on an instance of type T
+ template
+ std::shared_ptr< T > resolveNamed(const std::string& name)
+ {
+ static_assert(Traits::IsComplete< T >::value, "T should be a complete type");
+
+ return resolve< T >(createKeyForNamedType< T >(name));
+ }
+
private:
template
std::shared_ptr< T > resolve(const TypeAliasKey& typeAliasKey)
diff --git a/Hypodermic/Container.h b/Hypodermic/Container.h
index 57b7738..b15bb22 100644
--- a/Hypodermic/Container.h
+++ b/Hypodermic/Container.h
@@ -75,6 +75,19 @@ namespace Hypodermic
return componentContext.resolveAll< T >();
}
+ ///
+ /// Resolve an instance of type T by both its type and a name
+ ///
+ /// The type to resolve (i.e. get an instance of T)
+ /// The name of the object to resolve
+ /// A shared pointer on an instance of type T
+ template
+ std::shared_ptr< T > resolveNamed(const std::string& name)
+ {
+ ComponentContext componentContext(shared_from_this(), m_registrationScope, m_runtimeRegistrationBuilder);
+ return componentContext.resolveNamed< T >(name);
+ }
+
private:
std::shared_ptr< IRegistrationScope > m_registrationScope;
std::shared_ptr< IRuntimeRegistrationBuilder > m_runtimeRegistrationBuilder;
diff --git a/Hypodermic/Hypodermic.vcxproj b/Hypodermic/Hypodermic.vcxproj
index b88d9d3..c0cdc19 100644
--- a/Hypodermic/Hypodermic.vcxproj
+++ b/Hypodermic/Hypodermic.vcxproj
@@ -168,6 +168,8 @@
+
+
diff --git a/Hypodermic/Hypodermic.vcxproj.filters b/Hypodermic/Hypodermic.vcxproj.filters
index 5667bf2..80f277f 100644
--- a/Hypodermic/Hypodermic.vcxproj.filters
+++ b/Hypodermic/Hypodermic.vcxproj.filters
@@ -293,5 +293,11 @@
Descriptors\Operations
+
+ Descriptors\Operations
+
+
+ TypeAlias
+
\ No newline at end of file
diff --git a/Hypodermic/Named.h b/Hypodermic/Named.h
new file mode 100644
index 0000000..db84299
--- /dev/null
+++ b/Hypodermic/Named.h
@@ -0,0 +1,69 @@
+#pragma once
+
+#include
+
+#include "Hypodermic/TypeAliasKey.h"
+
+
+namespace Hypodermic
+{
+namespace RegistrationDescriptorOperations
+{
+
+ template
+ <
+ class TDescriptor,
+ class TDescriptorInfo
+ >
+ class Named
+ {
+ private:
+ typedef typename TDescriptorInfo::InstanceType InstanceType;
+
+ template
+ struct EnforceBaseOf
+ {
+ static_assert(std::is_base_of< TBase, T >::value && !std::is_same< TBase, T >::value, "TBase should be a base of T");
+
+ static void act() {}
+ };
+
+ template
+ struct EnforceBaseNotAlreadyRegistered
+ {
+ static_assert(!TDescriptorInfo::template IsBaseRegistered< TBase >::value, "TBase is already registered for instance T");
+
+ static void act() {}
+ };
+
+ public:
+ template
+ typename TDelayedDescriptor::template UpdateDescriptor
+ <
+ typename TDescriptorInfo::template RegisterBase< TBase >::Type
+ >
+ ::Type& named(const std::string& name)
+ {
+ EnforceBaseOf< TBase, InstanceType >::act();
+ EnforceBaseNotAlreadyRegistered< TBase >::act();
+
+ auto descriptor = static_cast< TDescriptor* >(this);
+ descriptor->addTypeIfMissing(createKeyForNamedType< TBase >(name), [](const std::shared_ptr< void >& x)
+ {
+ auto instanceDynamicType = std::static_pointer_cast< InstanceType >(x);
+ auto instanceStaticType = std::static_pointer_cast< TBase >(instanceDynamicType);
+ return instanceStaticType;
+ });
+
+ auto updatedDescriptor = descriptor->template createUpdate< typename TDescriptorInfo::template RegisterBase< TBase >::Type >();
+ descriptor->registrationDescriptorUpdated()(updatedDescriptor);
+
+ return *updatedDescriptor;
+ }
+
+ protected:
+ virtual ~Named() {}
+ };
+
+} // namespace RegistrationDescriptorOperations
+} // namespace Hypodermic
\ No newline at end of file
diff --git a/Hypodermic/NamedTypeAlias.h b/Hypodermic/NamedTypeAlias.h
new file mode 100644
index 0000000..2129d0e
--- /dev/null
+++ b/Hypodermic/NamedTypeAlias.h
@@ -0,0 +1,51 @@
+#pragma once
+
+#include
+#include
+
+#include "Hypodermic/ITypeAlias.h"
+#include "Hypodermic/TypeInfo.h"
+
+
+namespace Hypodermic
+{
+
+ class NamedTypeAlias : public ITypeAlias
+ {
+ public:
+ explicit NamedTypeAlias(const TypeInfo& typeInfo, const std::string& name)
+ : m_typeInfo(typeInfo)
+ , m_name(name)
+ {
+ }
+
+ bool operator==(const ITypeAlias& rhs) const override
+ {
+ const ITypeAlias* self = this;
+ if (self == &rhs)
+ return true;
+
+ auto rhsTypeAlias = dynamic_cast< const NamedTypeAlias* >(&rhs);
+ if (rhsTypeAlias == nullptr)
+ return false;
+
+ return m_typeInfo == rhsTypeAlias->m_typeInfo && m_name == rhsTypeAlias->m_name;
+ }
+
+ std::size_t hashCode() const override
+ {
+ auto hashCode = std::hash< std::type_index >()(m_typeInfo.intrinsicTypeInfo());
+ return (hashCode * 397) ^ std::hash< std::string >()(m_name);
+ }
+
+ const TypeInfo& typeInfo() const override
+ {
+ return m_typeInfo;
+ }
+
+ private:
+ TypeInfo m_typeInfo;
+ std::string m_name;
+ };
+
+} // namespace Hypodermic
\ No newline at end of file
diff --git a/Hypodermic/ProvidedInstanceFactoryRegistrationDescriptor.h b/Hypodermic/ProvidedInstanceFactoryRegistrationDescriptor.h
index a78907a..2dc4034 100644
--- a/Hypodermic/ProvidedInstanceFactoryRegistrationDescriptor.h
+++ b/Hypodermic/ProvidedInstanceFactoryRegistrationDescriptor.h
@@ -4,6 +4,7 @@
#include "Hypodermic/AsSelf.h"
#include "Hypodermic/InstanceFactory.h"
#include "Hypodermic/Log.h"
+#include "Hypodermic/Named.h"
#include "Hypodermic/OnActivated.h"
#include "Hypodermic/RegistrationBuilder.h"
#include "Hypodermic/RegistrationDescriptorBase.h"
@@ -18,12 +19,14 @@ namespace Hypodermic
class ProvidedInstanceFactoryRegistrationDescriptor : public RegistrationDescriptorBase< ProvidedInstanceFactoryRegistrationDescriptor< TDescriptorInfo >, TDescriptorInfo >,
public RegistrationDescriptorOperations::As< ProvidedInstanceFactoryRegistrationDescriptor< TDescriptorInfo >, TDescriptorInfo >,
public RegistrationDescriptorOperations::AsSelf< ProvidedInstanceFactoryRegistrationDescriptor< TDescriptorInfo >, TDescriptorInfo >,
+ public RegistrationDescriptorOperations::Named< ProvidedInstanceFactoryRegistrationDescriptor< TDescriptorInfo >, TDescriptorInfo >,
public RegistrationDescriptorOperations::OnActivated< ProvidedInstanceFactoryRegistrationDescriptor< TDescriptorInfo >, TDescriptorInfo >,
public RegistrationDescriptorOperations::SingleInstance< ProvidedInstanceFactoryRegistrationDescriptor< TDescriptorInfo >, TDescriptorInfo >,
public RegistrationDescriptorOperations::UseIfNone< ProvidedInstanceFactoryRegistrationDescriptor< TDescriptorInfo >, TDescriptorInfo >
{
friend class RegistrationDescriptorOperations::As< ProvidedInstanceFactoryRegistrationDescriptor< TDescriptorInfo >, TDescriptorInfo >;
friend class RegistrationDescriptorOperations::AsSelf< ProvidedInstanceFactoryRegistrationDescriptor< TDescriptorInfo >, TDescriptorInfo >;
+ friend class RegistrationDescriptorOperations::Named< ProvidedInstanceFactoryRegistrationDescriptor< TDescriptorInfo >, TDescriptorInfo >;
friend class RegistrationDescriptorOperations::OnActivated< ProvidedInstanceFactoryRegistrationDescriptor< TDescriptorInfo >, TDescriptorInfo >;
friend class RegistrationDescriptorOperations::SingleInstance< ProvidedInstanceFactoryRegistrationDescriptor< TDescriptorInfo >, TDescriptorInfo >;
friend class RegistrationDescriptorOperations::UseIfNone< ProvidedInstanceFactoryRegistrationDescriptor< TDescriptorInfo >, TDescriptorInfo >;
diff --git a/Hypodermic/ProvidedInstanceRegistrationDescriptor.h b/Hypodermic/ProvidedInstanceRegistrationDescriptor.h
index 18e2b02..d0988e4 100644
--- a/Hypodermic/ProvidedInstanceRegistrationDescriptor.h
+++ b/Hypodermic/ProvidedInstanceRegistrationDescriptor.h
@@ -3,6 +3,7 @@
#include "Hypodermic/As.h"
#include "Hypodermic/AsSelf.h"
#include "Hypodermic/Log.h"
+#include "Hypodermic/Named.h"
#include "Hypodermic/RegistrationBuilder.h"
#include "Hypodermic/RegistrationDescriptorBase.h"
#include "Hypodermic/UseIfNone.h"
@@ -15,10 +16,12 @@ namespace Hypodermic
class ProvidedInstanceRegistrationDescriptor : public RegistrationDescriptorBase< ProvidedInstanceRegistrationDescriptor< TDescriptorInfo >, TDescriptorInfo >,
public RegistrationDescriptorOperations::As< ProvidedInstanceRegistrationDescriptor< TDescriptorInfo >, TDescriptorInfo >,
public RegistrationDescriptorOperations::AsSelf< ProvidedInstanceRegistrationDescriptor< TDescriptorInfo >, TDescriptorInfo >,
+ public RegistrationDescriptorOperations::Named< ProvidedInstanceRegistrationDescriptor< TDescriptorInfo >, TDescriptorInfo >,
public RegistrationDescriptorOperations::UseIfNone< ProvidedInstanceRegistrationDescriptor< TDescriptorInfo >, TDescriptorInfo >
{
friend class RegistrationDescriptorOperations::As< ProvidedInstanceRegistrationDescriptor< TDescriptorInfo >, TDescriptorInfo >;
friend class RegistrationDescriptorOperations::AsSelf< ProvidedInstanceRegistrationDescriptor< TDescriptorInfo >, TDescriptorInfo >;
+ friend class RegistrationDescriptorOperations::Named< ProvidedInstanceRegistrationDescriptor< TDescriptorInfo >, TDescriptorInfo >;
friend class RegistrationDescriptorOperations::UseIfNone< ProvidedInstanceRegistrationDescriptor< TDescriptorInfo >, TDescriptorInfo >;
public:
diff --git a/Hypodermic/TypeAlias.h b/Hypodermic/TypeAlias.h
index 93789cb..67625ea 100644
--- a/Hypodermic/TypeAlias.h
+++ b/Hypodermic/TypeAlias.h
@@ -12,7 +12,7 @@ namespace Hypodermic
class TypeAlias : public ITypeAlias
{
public:
- TypeAlias(const TypeInfo& typeInfo)
+ explicit TypeAlias(const TypeInfo& typeInfo)
: m_typeInfo(typeInfo)
{
}
diff --git a/Hypodermic/TypeAliasKey.h b/Hypodermic/TypeAliasKey.h
index c5a0a28..be1cec5 100644
--- a/Hypodermic/TypeAliasKey.h
+++ b/Hypodermic/TypeAliasKey.h
@@ -5,6 +5,7 @@
#include
#include "Hypodermic/ITypeAlias.h"
+#include "Hypodermic/NamedTypeAlias.h"
#include "Hypodermic/TypeAlias.h"
#include "Hypodermic/TypeInfo.h"
@@ -41,16 +42,27 @@ namespace Hypodermic
template
- inline TypeAliasKey createKeyForType()
+ TypeAliasKey createKeyForType()
{
return createKeyForType(Utils::getMetaTypeInfo< T >());
}
+ template
+ TypeAliasKey createKeyForNamedType(const std::string& name)
+ {
+ return createKeyForNamedType(Utils::getMetaTypeInfo< T >(), name);
+ }
+
inline TypeAliasKey createKeyForType(const TypeInfo& typeInfo)
{
return TypeAliasKey(std::make_shared< TypeAlias >(typeInfo));
}
+ inline TypeAliasKey createKeyForNamedType(const TypeInfo& typeInfo, const std::string& name)
+ {
+ return TypeAliasKey(std::make_shared< NamedTypeAlias >(typeInfo, name));
+ }
+
} // namespace Hypodermic
diff --git a/Hypodermic/TypeInfo.h b/Hypodermic/TypeInfo.h
index d20e0df..21603f4 100644
--- a/Hypodermic/TypeInfo.h
+++ b/Hypodermic/TypeInfo.h
@@ -74,7 +74,7 @@ namespace Utils
{
template
- inline const TypeInfo& getMetaTypeInfo()
+ const TypeInfo& getMetaTypeInfo()
{
static TypeInfo result(typeid(T));
return result;