Releasing v5.6.0
This commit is contained in:
Родитель
7b1f3108da
Коммит
961d68a925
|
@ -141,4 +141,3 @@ _NCrunch*
|
||||||
project.lock.json
|
project.lock.json
|
||||||
testresults.xml
|
testresults.xml
|
||||||
testresults.xml
|
testresults.xml
|
||||||
BenchmarkDotNet.Artifacts
|
|
||||||
|
|
|
@ -17,8 +17,15 @@ build:
|
||||||
parallel: true
|
parallel: true
|
||||||
verbosity: minimal
|
verbosity: minimal
|
||||||
|
|
||||||
|
after_build:
|
||||||
|
- choco install opencover.portable
|
||||||
|
- choco install codecov
|
||||||
|
|
||||||
test_script:
|
test_script:
|
||||||
- cmd: dotnet test --framework net47 --verbosity q
|
- OpenCover.Console.exe -register:user -target:"C:\Program Files\dotnet\dotnet.exe" -targetargs:"test --framework net47 --verbosity q"
|
||||||
|
|
||||||
|
after_test:
|
||||||
|
- codecov -f "results.xml"
|
||||||
|
|
||||||
artifacts:
|
artifacts:
|
||||||
- path: '**\Unity.*.nupkg'
|
- path: '**\Unity.*.nupkg'
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
<Project>
|
<Project>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Version>5.5.8</Version>
|
<Version>5.6.0</Version>
|
||||||
<PackageReleaseNotes>This package is distributed as .NET Standard 1.0, .NET 4.0, 4.5, 4.7 package.</PackageReleaseNotes>
|
<PackageReleaseNotes>This package is distributed as .NET Standard 1.0, .NET 4.0, 4.5, 4.7 package.</PackageReleaseNotes>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<UnityAbstractionsVersion>3.1.*</UnityAbstractionsVersion>
|
<UnityAbstractionsVersion>3.2.*</UnityAbstractionsVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
12
package.sln
12
package.sln
|
@ -7,7 +7,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Unity.Container", "src\Unit
|
||||||
EndProject
|
EndProject
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{13CA431F-C840-429D-A83D-BFDEDCCA0F6F}"
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{13CA431F-C840-429D-A83D-BFDEDCCA0F6F}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Unity.Tests", "tests\Unity.Tests\Unity.Tests.csproj", "{29D42A07-017E-4E9C-A87D-0ABBCAE53798}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Unity.Tests", "tests\Unity.Tests\Unity.Tests.csproj", "{25E09D23-F407-4A61-8446-E5FBD6F689B8}"
|
||||||
EndProject
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
@ -19,16 +19,16 @@ Global
|
||||||
{EE1F752C-1FAB-41AD-AD63-857D0E62AB6B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{EE1F752C-1FAB-41AD-AD63-857D0E62AB6B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{EE1F752C-1FAB-41AD-AD63-857D0E62AB6B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{EE1F752C-1FAB-41AD-AD63-857D0E62AB6B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{EE1F752C-1FAB-41AD-AD63-857D0E62AB6B}.Release|Any CPU.Build.0 = Release|Any CPU
|
{EE1F752C-1FAB-41AD-AD63-857D0E62AB6B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
{29D42A07-017E-4E9C-A87D-0ABBCAE53798}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
{25E09D23-F407-4A61-8446-E5FBD6F689B8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{29D42A07-017E-4E9C-A87D-0ABBCAE53798}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{25E09D23-F407-4A61-8446-E5FBD6F689B8}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{29D42A07-017E-4E9C-A87D-0ABBCAE53798}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{25E09D23-F407-4A61-8446-E5FBD6F689B8}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{29D42A07-017E-4E9C-A87D-0ABBCAE53798}.Release|Any CPU.Build.0 = Release|Any CPU
|
{25E09D23-F407-4A61-8446-E5FBD6F689B8}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(NestedProjects) = preSolution
|
GlobalSection(NestedProjects) = preSolution
|
||||||
{29D42A07-017E-4E9C-A87D-0ABBCAE53798} = {13CA431F-C840-429D-A83D-BFDEDCCA0F6F}
|
{25E09D23-F407-4A61-8446-E5FBD6F689B8} = {13CA431F-C840-429D-A83D-BFDEDCCA0F6F}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
SolutionGuid = {7D864CD1-AEA6-4EDF-B8F8-071CE7F88251}
|
SolutionGuid = {7D864CD1-AEA6-4EDF-B8F8-071CE7F88251}
|
||||||
|
|
|
@ -1,9 +1,5 @@
|
||||||
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
|
using System;
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Unity.Builder;
|
|
||||||
using Unity.Container;
|
|
||||||
using Unity.Exceptions;
|
using Unity.Exceptions;
|
||||||
using Unity.Lifetime;
|
using Unity.Lifetime;
|
||||||
using Unity.Policy;
|
using Unity.Policy;
|
||||||
|
@ -11,21 +7,49 @@ using Unity.Resolution;
|
||||||
using Unity.Strategy;
|
using Unity.Strategy;
|
||||||
using Unity.Utility;
|
using Unity.Utility;
|
||||||
|
|
||||||
namespace Unity.ObjectBuilder
|
namespace Unity.Builder
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents the context in which a build-up or tear-down operation runs.
|
/// Represents the context in which a build-up or tear-down operation runs.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class BuilderContext : IBuilderContext
|
public class BuilderContext : IBuilderContext
|
||||||
{
|
{
|
||||||
|
#region Fields
|
||||||
|
|
||||||
private readonly IStrategyChain _chain;
|
private readonly IStrategyChain _chain;
|
||||||
private CompositeResolverOverride _resolverOverrides;
|
private CompositeResolverOverride _resolverOverrides;
|
||||||
private bool _ownsOverrides;
|
private bool _ownsOverrides;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
public BuilderContext(IUnityContainer container, ILifetimeContainer lifetime, IStrategyChain chain,
|
||||||
|
IPolicyList persistentPolicies, IPolicyList policies, INamedType buildKey, object existing, params ResolverOverride[] resolverOverrides)
|
||||||
|
{
|
||||||
|
_chain = chain;
|
||||||
|
Container = container;
|
||||||
|
Lifetime = lifetime;
|
||||||
|
Existing = existing;
|
||||||
|
|
||||||
|
OriginalBuildKey = buildKey;
|
||||||
|
BuildKey = OriginalBuildKey;
|
||||||
|
|
||||||
|
Policies = policies;
|
||||||
|
PersistentPolicies = persistentPolicies;
|
||||||
|
|
||||||
|
_ownsOverrides = true;
|
||||||
|
_resolverOverrides = new CompositeResolverOverride();
|
||||||
|
if (null != resolverOverrides && 0 != resolverOverrides.Length)
|
||||||
|
_resolverOverrides.AddRange(resolverOverrides);
|
||||||
|
}
|
||||||
|
|
||||||
public BuilderContext(IBuilderContext original, IStrategyChain chain, object existing)
|
public BuilderContext(IBuilderContext original, IStrategyChain chain, object existing)
|
||||||
{
|
{
|
||||||
Container = original.Container;
|
|
||||||
_chain = chain;
|
_chain = chain;
|
||||||
|
Container = original.Container;
|
||||||
|
ParentContext = original;
|
||||||
Lifetime = original.Lifetime;
|
Lifetime = original.Lifetime;
|
||||||
OriginalBuildKey = original.OriginalBuildKey;
|
OriginalBuildKey = original.OriginalBuildKey;
|
||||||
BuildKey = original.BuildKey;
|
BuildKey = original.BuildKey;
|
||||||
|
@ -36,89 +60,27 @@ namespace Unity.ObjectBuilder
|
||||||
_ownsOverrides = true;
|
_ownsOverrides = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initialize a new instance of the <see cref="BuilderContext"/> class with a <see cref="IStrategyChain"/>,
|
|
||||||
/// <see cref="ILifetimeContainer"/>, <see cref="IPolicyList"/> and the
|
|
||||||
/// build key used to start this build operation.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="container"></param>
|
|
||||||
/// <param name="chain">The <see cref="IStrategyChain"/> to use for this context.</param>
|
|
||||||
/// <param name="lifetime">The <see cref="ILifetimeContainer"/> to use for this context.</param>
|
|
||||||
/// <param name="policies">The <see cref="IPolicyList"/> to use for this context.</param>
|
|
||||||
/// <param name="originalBuildKey">Build key to start building.</param>
|
|
||||||
/// <param name="existing">The existing object to build up.</param>
|
|
||||||
public BuilderContext(IUnityContainer container, IStrategyChain chain,
|
|
||||||
ILifetimeContainer lifetime,
|
|
||||||
IPolicyList policies,
|
|
||||||
INamedType originalBuildKey,
|
|
||||||
object existing)
|
|
||||||
{
|
|
||||||
Container = container ?? throw new ArgumentNullException(nameof(container));
|
|
||||||
_chain = chain;
|
|
||||||
Lifetime = lifetime;
|
|
||||||
OriginalBuildKey = originalBuildKey;
|
|
||||||
BuildKey = originalBuildKey;
|
|
||||||
PersistentPolicies = policies;
|
|
||||||
Policies = new PolicyList(PersistentPolicies);
|
|
||||||
Existing = existing;
|
|
||||||
_resolverOverrides = new CompositeResolverOverride();
|
|
||||||
_ownsOverrides = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
protected BuilderContext(IBuilderContext original, Type type, string name)
|
||||||
/// Create a new <see cref="BuilderContext"/> using the explicitly provided
|
|
||||||
/// values.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="container"></param>
|
|
||||||
/// <param name="chain">The <see cref="IStrategyChain"/> to use for this context.</param>
|
|
||||||
/// <param name="lifetime">The <see cref="ILifetimeContainer"/> to use for this context.</param>
|
|
||||||
/// <param name="persistentPolicies">The set of persistent policies to use for this context.</param>
|
|
||||||
/// <param name="transientPolicies">The set of transient policies to use for this context. It is
|
|
||||||
/// the caller's responsibility to ensure that the transient and persistent policies are properly
|
|
||||||
/// combined.</param>
|
|
||||||
/// <param name="buildKey">Build key for this context.</param>
|
|
||||||
/// <param name="existing">Existing object to build up.</param>
|
|
||||||
public BuilderContext(IUnityContainer container, IStrategyChain chain, ILifetimeContainer lifetime, IPolicyList persistentPolicies, IPolicyList transientPolicies, INamedType buildKey, object existing)
|
|
||||||
{
|
{
|
||||||
Container = container ?? throw new ArgumentNullException(nameof(container));
|
var parent = (BuilderContext) original;
|
||||||
_chain = chain;
|
|
||||||
Lifetime = lifetime;
|
|
||||||
PersistentPolicies = persistentPolicies;
|
|
||||||
Policies = transientPolicies;
|
|
||||||
OriginalBuildKey = buildKey;
|
|
||||||
BuildKey = buildKey;
|
|
||||||
Existing = existing;
|
|
||||||
_resolverOverrides = new CompositeResolverOverride();
|
|
||||||
_ownsOverrides = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
_chain = parent._chain;
|
||||||
/// Create a new <see cref="BuilderContext"/> using the explicitly provided
|
ParentContext = original;
|
||||||
/// values.
|
Container = original.Container;
|
||||||
/// </summary>
|
Lifetime = parent.Lifetime;
|
||||||
/// <param name="container"></param>
|
|
||||||
/// <param name="chain">The <see cref="IStrategyChain"/> to use for this context.</param>
|
|
||||||
/// <param name="lifetime">The <see cref="ILifetimeContainer"/> to use for this context.</param>
|
|
||||||
/// <param name="persistentPolicies">The set of persistent policies to use for this context.</param>
|
|
||||||
/// <param name="transientPolicies">The set of transient policies to use for this context. It is
|
|
||||||
/// the caller's responsibility to ensure that the transient and persistent policies are properly
|
|
||||||
/// combined.</param>
|
|
||||||
/// <param name="buildKey">Build key for this context.</param>
|
|
||||||
/// <param name="resolverOverrides">The resolver overrides.</param>
|
|
||||||
protected BuilderContext(IUnityContainer container, IStrategyChain chain, ILifetimeContainer lifetime, IPolicyList persistentPolicies, IPolicyList transientPolicies, INamedType buildKey, CompositeResolverOverride resolverOverrides)
|
|
||||||
{
|
|
||||||
Container = container ?? throw new ArgumentNullException(nameof(container));
|
|
||||||
_chain = chain;
|
|
||||||
Lifetime = lifetime;
|
|
||||||
PersistentPolicies = persistentPolicies;
|
|
||||||
Policies = transientPolicies;
|
|
||||||
OriginalBuildKey = buildKey;
|
|
||||||
BuildKey = buildKey;
|
|
||||||
Existing = null;
|
Existing = null;
|
||||||
_resolverOverrides = resolverOverrides;
|
_resolverOverrides = parent._resolverOverrides;
|
||||||
_ownsOverrides = false;
|
_ownsOverrides = false;
|
||||||
|
Policies = parent.Policies;
|
||||||
|
PersistentPolicies = parent.PersistentPolicies;
|
||||||
|
OriginalBuildKey = new NamedTypeBuildKey(type, name);
|
||||||
|
BuildKey = OriginalBuildKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
#region IBuilderContext
|
#region IBuilderContext
|
||||||
|
|
||||||
public IUnityContainer Container { get; }
|
public IUnityContainer Container { get; }
|
||||||
|
@ -221,8 +183,7 @@ namespace Unity.ObjectBuilder
|
||||||
_ownsOverrides = true;
|
_ownsOverrides = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (null != newOverrides)
|
_resolverOverrides.AddRange(newOverrides);
|
||||||
_resolverOverrides.AddRange(newOverrides);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -236,6 +197,8 @@ namespace Unity.ObjectBuilder
|
||||||
return _resolverOverrides.GetResolver(this, dependencyType);
|
return _resolverOverrides.GetResolver(this, dependencyType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A method to do a new buildup operation on an existing context.
|
/// A method to do a new buildup operation on an existing context.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -247,20 +210,14 @@ namespace Unity.ObjectBuilder
|
||||||
/// <returns>Resolved object</returns>
|
/// <returns>Resolved object</returns>
|
||||||
public object NewBuildUp(Type type, string name, Action<IBuilderContext> childCustomizationBlock = null)
|
public object NewBuildUp(Type type, string name, Action<IBuilderContext> childCustomizationBlock = null)
|
||||||
{
|
{
|
||||||
ChildContext =
|
ChildContext = new BuilderContext(this, type, name);
|
||||||
new BuilderContext(Container, _chain, Lifetime, PersistentPolicies,
|
|
||||||
Policies, new NamedTypeBuildKey(type, name), _resolverOverrides)
|
|
||||||
{ ParentContext = this};
|
|
||||||
|
|
||||||
childCustomizationBlock?.Invoke(ChildContext);
|
childCustomizationBlock?.Invoke(ChildContext);
|
||||||
|
var result = ChildContext.Strategies.ExecuteBuildUp(ChildContext);
|
||||||
object result = ChildContext.Strategies.ExecuteBuildUp(ChildContext);
|
|
||||||
|
|
||||||
ChildContext = null;
|
ChildContext = null;
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,62 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Unity.Builder
|
||||||
|
{
|
||||||
|
public class NamedTypeBase : INamedType
|
||||||
|
{
|
||||||
|
#region Fields
|
||||||
|
|
||||||
|
private readonly int _hash;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
protected NamedTypeBase(Type type, string name)
|
||||||
|
{
|
||||||
|
Type = type;
|
||||||
|
Name = name;
|
||||||
|
_hash = (Type?.GetHashCode() ?? 0 + 37) ^ (Name?.GetHashCode() ?? 0 + 17);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region INamedType
|
||||||
|
|
||||||
|
public Type Type { get; }
|
||||||
|
|
||||||
|
public string Name { get; }
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Object
|
||||||
|
|
||||||
|
public override bool Equals(object obj)
|
||||||
|
{
|
||||||
|
return obj is INamedType namedType &&
|
||||||
|
Type == namedType.Type &&
|
||||||
|
Name == namedType.Name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
return _hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region NamedTypeBuildKey
|
||||||
|
|
||||||
|
public static implicit operator NamedTypeBuildKey(NamedTypeBase namedType)
|
||||||
|
{
|
||||||
|
return new NamedTypeBuildKey(namedType.Type, namedType.Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
using Unity.Lifetime;
|
||||||
|
|
||||||
|
namespace Unity.Container.Lifetime
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Internal container lifetime manager.
|
||||||
|
/// This manager distinguishes internal registration from user mode registration.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Works like the ExternallyControlledLifetimeManager, but uses
|
||||||
|
/// regular instead of weak references
|
||||||
|
/// </remarks>
|
||||||
|
internal class ContainerLifetimeManager : LifetimeManager
|
||||||
|
{
|
||||||
|
public override object GetValue(ILifetimeContainer container = null)
|
||||||
|
{
|
||||||
|
return container.Container;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override LifetimeManager OnCreateLifetimeManager()
|
||||||
|
{
|
||||||
|
return new ContainerLifetimeManager();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,6 +3,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using Unity.Lifetime;
|
using Unity.Lifetime;
|
||||||
|
|
||||||
namespace Unity.Container.Lifetime
|
namespace Unity.Container.Lifetime
|
||||||
|
@ -19,6 +20,18 @@ namespace Unity.Container.Lifetime
|
||||||
{
|
{
|
||||||
private readonly List<object> _items = new List<object>();
|
private readonly List<object> _items = new List<object>();
|
||||||
|
|
||||||
|
public LifetimeContainer(IUnityContainer parent = null)
|
||||||
|
{
|
||||||
|
Container = parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The IUnityContainer this container is associated with.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The <see cref="IUnityContainer"/> object.</value>
|
||||||
|
public IUnityContainer Container { get; }
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the number of references in the lifetime container
|
/// Gets the number of references in the lifetime container
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -87,15 +100,9 @@ namespace Unity.Container.Lifetime
|
||||||
{
|
{
|
||||||
lock (_items)
|
lock (_items)
|
||||||
{
|
{
|
||||||
var itemsCopy = new List<object>(_items);
|
foreach (var disposable in _items.OfType<IDisposable>().Reverse())
|
||||||
itemsCopy.Reverse();
|
|
||||||
|
|
||||||
foreach (object o in itemsCopy)
|
|
||||||
{
|
{
|
||||||
if (o is IDisposable d)
|
disposable.Dispose();
|
||||||
{
|
|
||||||
d.Dispose();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_items.Clear();
|
_items.Clear();
|
||||||
|
|
|
@ -1,66 +0,0 @@
|
||||||
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Reflection;
|
|
||||||
using Unity.Builder;
|
|
||||||
using Unity.Lifetime;
|
|
||||||
using Unity.Policy;
|
|
||||||
using Unity.Registration;
|
|
||||||
|
|
||||||
namespace Unity.Container.Registration
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Class that returns information about the types registered in a container.
|
|
||||||
/// </summary>
|
|
||||||
public class ContainerRegistration : IContainerRegistration
|
|
||||||
{
|
|
||||||
private readonly NamedTypeBuildKey buildKey;
|
|
||||||
private static readonly TransientLifetimeManager Transient = new TransientLifetimeManager();
|
|
||||||
|
|
||||||
internal ContainerRegistration(Type registeredType, string name, IPolicyList policies)
|
|
||||||
{
|
|
||||||
this.buildKey = new NamedTypeBuildKey(registeredType, name);
|
|
||||||
MappedToType = GetMappedType(policies);
|
|
||||||
LifetimeManager = GetLifetimeManager(policies) ?? Transient;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The type that was passed to the <see cref="IUnityContainer.RegisterType"/> method
|
|
||||||
/// as the "from" type, or the only type if type mapping wasn't done.
|
|
||||||
/// </summary>
|
|
||||||
public Type RegisteredType { get { return this.buildKey.Type; } }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The type that this registration is mapped to. If no type mapping was done, the
|
|
||||||
/// <see cref="RegisteredType"/> property and this one will have the same value.
|
|
||||||
/// </summary>
|
|
||||||
public Type MappedToType { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Name the type was registered under. Null for default registration.
|
|
||||||
/// </summary>
|
|
||||||
public string Name { get { return this.buildKey.Name; } }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The lifetime manager for this registration.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// This property will be null if this registration is for an open generic.</remarks>
|
|
||||||
public LifetimeManager LifetimeManager { get; private set; }
|
|
||||||
|
|
||||||
private Type GetMappedType(IPolicyList policies)
|
|
||||||
{
|
|
||||||
var mappingPolicy = policies.Get<IBuildKeyMappingPolicy>(this.buildKey);
|
|
||||||
if (mappingPolicy != null)
|
|
||||||
{
|
|
||||||
return mappingPolicy.Map(this.buildKey, null).Type;
|
|
||||||
}
|
|
||||||
return this.buildKey.Type;
|
|
||||||
}
|
|
||||||
|
|
||||||
private LifetimeManager GetLifetimeManager(IPolicyList policies)
|
|
||||||
{
|
|
||||||
return (LifetimeManager)policies.Get<ILifetimePolicy>(buildKey);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,79 +0,0 @@
|
||||||
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace Unity.Container.Registration
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// A helper class to manage the names that get registered in the container
|
|
||||||
/// </summary>
|
|
||||||
internal class NamedTypesRegistry
|
|
||||||
{
|
|
||||||
private readonly Dictionary<Type, List<string>> registeredKeys;
|
|
||||||
private readonly NamedTypesRegistry parent;
|
|
||||||
|
|
||||||
public NamedTypesRegistry()
|
|
||||||
: this(null)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public NamedTypesRegistry(NamedTypesRegistry parent)
|
|
||||||
{
|
|
||||||
this.parent = parent;
|
|
||||||
registeredKeys = new Dictionary<Type, List<string>>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RegisterType(Type t, string name)
|
|
||||||
{
|
|
||||||
if (!registeredKeys.ContainsKey(t))
|
|
||||||
{
|
|
||||||
registeredKeys[t] = new List<string>();
|
|
||||||
}
|
|
||||||
|
|
||||||
RemoveMatchingKeys(t, name);
|
|
||||||
registeredKeys[t].Add(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerable<string> GetKeys(Type t)
|
|
||||||
{
|
|
||||||
var keys = Enumerable.Empty<string>();
|
|
||||||
|
|
||||||
if (parent != null)
|
|
||||||
{
|
|
||||||
keys = keys.Concat(parent.GetKeys(t));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (registeredKeys.ContainsKey(t))
|
|
||||||
{
|
|
||||||
keys = keys.Concat(registeredKeys[t]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return keys;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerable<Type> RegisteredTypes
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return registeredKeys.Keys;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Clear()
|
|
||||||
{
|
|
||||||
registeredKeys.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
// We need to do this the long way - Silverlight doesn't support List<T>.RemoveAll(Predicate)
|
|
||||||
private void RemoveMatchingKeys(Type t, string name)
|
|
||||||
{
|
|
||||||
var uniqueNames = from registeredName in registeredKeys[t]
|
|
||||||
where registeredName != name
|
|
||||||
select registeredName;
|
|
||||||
|
|
||||||
registeredKeys[t] = uniqueNames.ToList();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -34,18 +34,19 @@ namespace Unity.Container
|
||||||
public void BuildUp(IBuilderContext builderContext)
|
public void BuildUp(IBuilderContext builderContext)
|
||||||
{
|
{
|
||||||
var context = builderContext ?? throw new ArgumentNullException(nameof(builderContext));
|
var context = builderContext ?? throw new ArgumentNullException(nameof(builderContext));
|
||||||
var i = 0;
|
var i = -1;
|
||||||
|
var values = new object[_strategies.Length]; // TODO: Store in struct
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
while (!context.BuildComplete && i < _strategies.Length)
|
while (!context.BuildComplete && ++i < _strategies.Length)
|
||||||
{
|
{
|
||||||
_strategies[i++].PreBuildUp(context);
|
values[i] = _strategies[i].PreBuildUp(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
while (--i >= 0)
|
while (--i >= 0)
|
||||||
{
|
{
|
||||||
_strategies[i].PostBuildUp(context);
|
_strategies[i].PostBuildUp(context, values[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception)
|
catch (Exception)
|
||||||
|
|
|
@ -14,7 +14,7 @@ using Unity.Container.Lifetime;
|
||||||
using Unity.Lifetime;
|
using Unity.Lifetime;
|
||||||
using Unity.Policy;
|
using Unity.Policy;
|
||||||
|
|
||||||
namespace Unity.ObjectBuilder.BuildPlan.DynamicMethod
|
namespace Unity.ObjectBuilder.BuildPlan.DynamicMethod.Creation
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A <see cref="BuilderStrategy"/> that emits IL to call constructors
|
/// A <see cref="BuilderStrategy"/> that emits IL to call constructors
|
||||||
|
@ -93,7 +93,10 @@ namespace Unity.ObjectBuilder.BuildPlan.DynamicMethod
|
||||||
}
|
}
|
||||||
|
|
||||||
IConstructorSelectorPolicy selector =
|
IConstructorSelectorPolicy selector =
|
||||||
context.Policies.Get<IConstructorSelectorPolicy>(context.OriginalBuildKey, out var resolverPolicyDestination);
|
context.Policies.GetPolicy<IConstructorSelectorPolicy>(context.OriginalBuildKey, out var resolverPolicyDestination);
|
||||||
|
|
||||||
|
|
||||||
|
context.Policies.Get<IConstructorSelectorPolicy>(null, null, out resolverPolicyDestination);
|
||||||
|
|
||||||
SelectedConstructor selectedConstructor = selector.SelectConstructor(context, resolverPolicyDestination);
|
SelectedConstructor selectedConstructor = selector.SelectConstructor(context, resolverPolicyDestination);
|
||||||
|
|
||||||
|
@ -122,7 +125,9 @@ namespace Unity.ObjectBuilder.BuildPlan.DynamicMethod
|
||||||
{
|
{
|
||||||
if (selectedConstructor.Constructor.GetParameters().Any(p => p.ParameterType.GetTypeInfo() == target))
|
if (selectedConstructor.Constructor.GetParameters().Any(p => p.ParameterType.GetTypeInfo() == target))
|
||||||
{
|
{
|
||||||
var policy = context.Policies.Get<ILifetimePolicy>(context.BuildKey, out var _);
|
var policy = (ILifetimePolicy)context.Policies.Get(context.BuildKey.Type,
|
||||||
|
context.BuildKey.Name,
|
||||||
|
typeof(ILifetimePolicy), out var _);
|
||||||
if (null == policy?.GetValue())
|
if (null == policy?.GetValue())
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -199,13 +204,17 @@ namespace Unity.ObjectBuilder.BuildPlan.DynamicMethod
|
||||||
/// if the current object is such.
|
/// if the current object is such.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="context">Current build context.</param>
|
/// <param name="context">Current build context.</param>
|
||||||
private static void SetPerBuildSingleton(IBuilderContext context)
|
public static void SetPerBuildSingleton(IBuilderContext context)
|
||||||
{
|
{
|
||||||
var lifetime = (context ?? throw new ArgumentNullException(nameof(context))).Policies.Get<ILifetimePolicy>(context.OriginalBuildKey);
|
var lifetime = (context ?? throw new ArgumentNullException(nameof(context)))
|
||||||
|
.Policies.GetOrDefault(typeof(ILifetimePolicy), context.OriginalBuildKey, out _);
|
||||||
|
|
||||||
if (lifetime is PerResolveLifetimeManager)
|
if (lifetime is PerResolveLifetimeManager)
|
||||||
{
|
{
|
||||||
var perBuildLifetime = new InternalPerResolveLifetimeManager(context.Existing);
|
var perBuildLifetime = new InternalPerResolveLifetimeManager(context.Existing);
|
||||||
context.Policies.Set<ILifetimePolicy>(perBuildLifetime, context.OriginalBuildKey);
|
context.Policies.Set(context.OriginalBuildKey.Type,
|
||||||
|
context.OriginalBuildKey.Name,
|
||||||
|
typeof(ILifetimePolicy), perBuildLifetime);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,6 @@ namespace Unity.ObjectBuilder.BuildPlan.DynamicMethod
|
||||||
typeof(IBuilderContext).GetTypeInfo()
|
typeof(IBuilderContext).GetTypeInfo()
|
||||||
.DeclaredMembers
|
.DeclaredMembers
|
||||||
.First(m => m.Name == nameof(IBuilderContext.Existing));
|
.First(m => m.Name == nameof(IBuilderContext.Existing));
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -35,12 +35,10 @@ namespace Unity.ObjectBuilder.BuildPlan.DynamicMethod
|
||||||
/// <returns>The created build plan.</returns>
|
/// <returns>The created build plan.</returns>
|
||||||
public IBuildPlanPolicy CreatePlan(IBuilderContext context, INamedType buildKey)
|
public IBuildPlanPolicy CreatePlan(IBuilderContext context, INamedType buildKey)
|
||||||
{
|
{
|
||||||
DynamicBuildPlanGenerationContext generatorContext =
|
var generatorContext =
|
||||||
new DynamicBuildPlanGenerationContext((buildKey ?? throw new ArgumentNullException(nameof(buildKey))).Type);
|
new DynamicBuildPlanGenerationContext((buildKey ?? throw new ArgumentNullException(nameof(buildKey))).Type);
|
||||||
|
|
||||||
IBuilderContext planContext = new BuilderContext(context ?? throw new ArgumentNullException(nameof(context)),
|
IBuilderContext planContext = new BuilderContext(context ?? throw new ArgumentNullException(nameof(context)), new StrategyChain(_strategies), generatorContext);
|
||||||
((StagedStrategyChain<BuilderStage>)_strategies).MakeStrategyChain(),
|
|
||||||
generatorContext);
|
|
||||||
|
|
||||||
planContext.Strategies.ExecuteBuildUp(planContext);
|
planContext.Strategies.ExecuteBuildUp(planContext);
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ using Unity.Builder.Strategy;
|
||||||
using Unity.Exceptions;
|
using Unity.Exceptions;
|
||||||
using Unity.Policy;
|
using Unity.Policy;
|
||||||
|
|
||||||
namespace Unity.ObjectBuilder.BuildPlan.DynamicMethod
|
namespace Unity.ObjectBuilder.BuildPlan.DynamicMethod.Method
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A <see cref="BuilderStrategy"/> that generates IL to call
|
/// A <see cref="BuilderStrategy"/> that generates IL to call
|
||||||
|
@ -46,7 +46,7 @@ namespace Unity.ObjectBuilder.BuildPlan.DynamicMethod
|
||||||
{
|
{
|
||||||
var dynamicBuildContext = (DynamicBuildPlanGenerationContext)(context ?? throw new ArgumentNullException(nameof(context))).Existing;
|
var dynamicBuildContext = (DynamicBuildPlanGenerationContext)(context ?? throw new ArgumentNullException(nameof(context))).Existing;
|
||||||
|
|
||||||
var selector = context.Policies.Get<IMethodSelectorPolicy>(context.OriginalBuildKey, out var resolverPolicyDestination);
|
var selector = context.Policies.GetPolicy<IMethodSelectorPolicy>(context.OriginalBuildKey, out var resolverPolicyDestination);
|
||||||
|
|
||||||
bool shouldClearOperation = false;
|
bool shouldClearOperation = false;
|
||||||
|
|
|
@ -9,7 +9,7 @@ using Unity.Builder.Operation;
|
||||||
using Unity.Builder.Strategy;
|
using Unity.Builder.Strategy;
|
||||||
using Unity.Policy;
|
using Unity.Policy;
|
||||||
|
|
||||||
namespace Unity.ObjectBuilder.BuildPlan.DynamicMethod
|
namespace Unity.ObjectBuilder.BuildPlan.DynamicMethod.Property
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A <see cref="BuilderStrategy"/> that generates IL to resolve properties
|
/// A <see cref="BuilderStrategy"/> that generates IL to resolve properties
|
||||||
|
@ -39,7 +39,7 @@ namespace Unity.ObjectBuilder.BuildPlan.DynamicMethod
|
||||||
{
|
{
|
||||||
var dynamicBuildContext = (DynamicBuildPlanGenerationContext)(context ?? throw new ArgumentNullException(nameof(context))).Existing;
|
var dynamicBuildContext = (DynamicBuildPlanGenerationContext)(context ?? throw new ArgumentNullException(nameof(context))).Existing;
|
||||||
|
|
||||||
var selector = context.Policies.Get<IPropertySelectorPolicy>(context.OriginalBuildKey, out var resolverPolicyDestination);
|
var selector = context.Policies.GetPolicy<IPropertySelectorPolicy>( context.OriginalBuildKey, out var resolverPolicyDestination);
|
||||||
|
|
||||||
bool shouldClearOperation = false;
|
bool shouldClearOperation = false;
|
||||||
|
|
|
@ -1,70 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Globalization;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Reflection;
|
|
||||||
using Unity.Builder;
|
|
||||||
using Unity.ObjectBuilder.BuildPlan.DynamicMethod;
|
|
||||||
using Unity.Policy;
|
|
||||||
|
|
||||||
namespace Unity.ObjectBuilder.BuildPlan
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// An <see cref="IEnumerable{T}"/> implementation
|
|
||||||
/// that constructs a build plan for creating <see cref="IBuildPlanCreatorPolicy"/> objects.
|
|
||||||
/// </summary>
|
|
||||||
public class EnumerableDynamicMethodBuildPlanCreatorPolicy : IBuildPlanCreatorPolicy
|
|
||||||
{
|
|
||||||
private static readonly MethodInfo ResolveMethod =
|
|
||||||
typeof(EnumerableDynamicMethodBuildPlanCreatorPolicy).GetTypeInfo()
|
|
||||||
.GetDeclaredMethod(nameof(BuildResolveEnumerable));
|
|
||||||
|
|
||||||
private static readonly MethodInfo CastMethod = typeof(System.Linq.Enumerable).GetTypeInfo()
|
|
||||||
.DeclaredMethods
|
|
||||||
.First(m => Equals(m.Name, "Cast"));
|
|
||||||
|
|
||||||
|
|
||||||
public IBuildPlanPolicy CreatePlan(IBuilderContext context, INamedType buildKey)
|
|
||||||
{
|
|
||||||
var itemType = (context ?? throw new ArgumentNullException(nameof(context))).BuildKey
|
|
||||||
.Type
|
|
||||||
.GetTypeInfo()
|
|
||||||
.GenericTypeArguments
|
|
||||||
.First();
|
|
||||||
var buildMethod = ResolveMethod.MakeGenericMethod(itemType)
|
|
||||||
.CreateDelegate(typeof(DynamicBuildPlanMethod));
|
|
||||||
|
|
||||||
return new DynamicMethodBuildPlan((DynamicBuildPlanMethod)buildMethod);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void BuildResolveEnumerable<T>(IBuilderContext context)
|
|
||||||
{
|
|
||||||
if (null == context.Existing)
|
|
||||||
{
|
|
||||||
var itemType = typeof(T);
|
|
||||||
var itemTypeInfo = itemType.GetTypeInfo();
|
|
||||||
var container = context.Container ?? context.NewBuildUp<IUnityContainer>();
|
|
||||||
|
|
||||||
if (itemTypeInfo.IsGenericTypeDefinition)
|
|
||||||
{
|
|
||||||
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture,
|
|
||||||
Constants.MustHaveOpenGenericType,
|
|
||||||
itemType.GetTypeInfo().Name));
|
|
||||||
}
|
|
||||||
|
|
||||||
var generic = new Lazy<Type>(() => itemType.GetGenericTypeDefinition());
|
|
||||||
IEnumerable<object> enumerable = container.Registrations
|
|
||||||
.Where(r => r.RegisteredType == itemType || (itemTypeInfo.IsGenericType &&
|
|
||||||
r.RegisteredType.GetTypeInfo().IsGenericTypeDefinition &&
|
|
||||||
r.RegisteredType == generic.Value))
|
|
||||||
.Select(r => context.NewBuildUp(new NamedTypeBuildKey(itemType, r.Name)))
|
|
||||||
.ToArray();
|
|
||||||
context.Existing = CastMethod.MakeGenericMethod(itemType).Invoke(null, new object[] { enumerable });
|
|
||||||
context.BuildComplete = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
context.SetPerBuildSingleton();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -28,9 +28,10 @@ namespace Unity.ObjectBuilder.BuildPlan.Selection
|
||||||
protected override IResolverPolicy CreateResolver(ParameterInfo parameter)
|
protected override IResolverPolicy CreateResolver(ParameterInfo parameter)
|
||||||
{
|
{
|
||||||
// Resolve all DependencyAttributes on this parameter, if any
|
// Resolve all DependencyAttributes on this parameter, if any
|
||||||
var attrs = (parameter ?? throw new ArgumentNullException(nameof(parameter))).GetCustomAttributes(false).OfType<DependencyResolutionAttribute>().ToList();
|
var attrs = (parameter ?? throw new ArgumentNullException(nameof(parameter))).GetCustomAttributes(false)
|
||||||
|
.OfType<DependencyResolutionAttribute>()
|
||||||
if (attrs.Count > 0)
|
.ToArray();
|
||||||
|
if (attrs.Length > 0)
|
||||||
{
|
{
|
||||||
// Since this attribute is defined with MultipleUse = false, the compiler will
|
// Since this attribute is defined with MultipleUse = false, the compiler will
|
||||||
// enforce at most one. So we don't need to check for more.
|
// enforce at most one. So we don't need to check for more.
|
||||||
|
|
|
@ -1,72 +0,0 @@
|
||||||
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Globalization;
|
|
||||||
using System.Reflection;
|
|
||||||
using Unity.Builder;
|
|
||||||
using Unity.Policy;
|
|
||||||
|
|
||||||
namespace Unity.ObjectBuilder.Policies
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// An implementation of <see cref="IBuildKeyMappingPolicy"/> that can map
|
|
||||||
/// generic types.
|
|
||||||
/// </summary>
|
|
||||||
public class GenericTypeBuildKeyMappingPolicy : IBuildKeyMappingPolicy
|
|
||||||
{
|
|
||||||
private readonly NamedTypeBuildKey _destinationKey;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Create a new <see cref="GenericTypeBuildKeyMappingPolicy"/> instance
|
|
||||||
/// that will map generic types.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="destinationKey">Build key to map to. This must be or contain an open generic type.</param>
|
|
||||||
public GenericTypeBuildKeyMappingPolicy(NamedTypeBuildKey destinationKey)
|
|
||||||
{
|
|
||||||
if (!(destinationKey ?? throw new ArgumentNullException(nameof(destinationKey))).Type.GetTypeInfo().IsGenericTypeDefinition)
|
|
||||||
{
|
|
||||||
throw new ArgumentException(
|
|
||||||
string.Format(CultureInfo.CurrentCulture,
|
|
||||||
Constants.MustHaveOpenGenericType,
|
|
||||||
destinationKey.Type.GetTypeInfo().Name));
|
|
||||||
}
|
|
||||||
_destinationKey = destinationKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Maps the build key.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="buildKey">The build key to map.</param>
|
|
||||||
/// <param name="context">Current build context. Used for contextual information
|
|
||||||
/// if writing a more sophisticated mapping.</param>
|
|
||||||
/// <returns>The new build key.</returns>
|
|
||||||
public INamedType Map(INamedType buildKey, IBuilderContext context)
|
|
||||||
{
|
|
||||||
var originalTypeInfo = (buildKey ?? throw new ArgumentNullException(nameof(buildKey))).Type.GetTypeInfo();
|
|
||||||
if (originalTypeInfo.IsGenericTypeDefinition)
|
|
||||||
{
|
|
||||||
// No need to perform a mapping - the source type is an open generic
|
|
||||||
return _destinationKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
GuardSameNumberOfGenericArguments(originalTypeInfo);
|
|
||||||
Type[] genericArguments = originalTypeInfo.GenericTypeArguments;
|
|
||||||
Type resultType = _destinationKey.Type.MakeGenericType(genericArguments);
|
|
||||||
return new NamedTypeBuildKey(resultType, _destinationKey.Name);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void GuardSameNumberOfGenericArguments(TypeInfo sourceTypeInfo)
|
|
||||||
{
|
|
||||||
if (sourceTypeInfo.GenericTypeArguments.Length != DestinationType.GetTypeInfo().GenericTypeParameters.Length)
|
|
||||||
{
|
|
||||||
throw new ArgumentException(
|
|
||||||
string.Format(CultureInfo.CurrentCulture,
|
|
||||||
Constants.MustHaveSameNumberOfGenericArguments,
|
|
||||||
sourceTypeInfo.Name, DestinationType.Name),
|
|
||||||
nameof(sourceTypeInfo));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Type DestinationType => _destinationKey.Type;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,22 +0,0 @@
|
||||||
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using Unity.Builder;
|
|
||||||
using Unity.Policy;
|
|
||||||
|
|
||||||
namespace Unity.ObjectBuilder.Policies
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Provides access to the names registered for a container.
|
|
||||||
/// </summary>
|
|
||||||
public interface IRegisteredNamesPolicy : IBuilderPolicy
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the names registered for a type.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="type">The type.</param>
|
|
||||||
/// <returns>The names registered for <paramref name="type"/>.</returns>
|
|
||||||
IEnumerable<string> GetRegisteredNames(Type type);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,24 +0,0 @@
|
||||||
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using Unity.Container.Registration;
|
|
||||||
|
|
||||||
namespace Unity.ObjectBuilder.Policies
|
|
||||||
{
|
|
||||||
internal class RegisteredNamesPolicy : IRegisteredNamesPolicy
|
|
||||||
{
|
|
||||||
private readonly NamedTypesRegistry _registry;
|
|
||||||
|
|
||||||
public RegisteredNamesPolicy(NamedTypesRegistry registry)
|
|
||||||
{
|
|
||||||
_registry = registry;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerable<string> GetRegisteredNames(Type type)
|
|
||||||
{
|
|
||||||
return _registry.GetKeys(type).Where(s => !string.IsNullOrEmpty(s));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,63 +0,0 @@
|
||||||
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Reflection;
|
|
||||||
using Unity.Builder;
|
|
||||||
using Unity.Builder.Strategy;
|
|
||||||
using Unity.ObjectBuilder.Policies;
|
|
||||||
using Unity.Policy;
|
|
||||||
|
|
||||||
namespace Unity.ObjectBuilder.Strategies
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// This strategy implements the logic that will call container.ResolveAll
|
|
||||||
/// when an array parameter is detected.
|
|
||||||
/// </summary>
|
|
||||||
public class ArrayResolutionStrategy : BuilderStrategy
|
|
||||||
{
|
|
||||||
private delegate object ArrayResolver(IBuilderContext context);
|
|
||||||
|
|
||||||
private static readonly MethodInfo GenericResolveArrayMethod = typeof(ArrayResolutionStrategy)
|
|
||||||
.GetTypeInfo().GetDeclaredMethod(nameof(ResolveArray));
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Do the PreBuildUp stage of construction. This is where the actual work is performed.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context">Current build context.</param>
|
|
||||||
public override object PreBuildUp(IBuilderContext context)
|
|
||||||
{
|
|
||||||
Type typeToBuild = context.BuildKey.Type;
|
|
||||||
if (typeToBuild.IsArray && typeToBuild.GetArrayRank() == 1)
|
|
||||||
{
|
|
||||||
Type elementType = typeToBuild.GetElementType();
|
|
||||||
|
|
||||||
MethodInfo resolverMethod = GenericResolveArrayMethod.MakeGenericMethod(elementType);
|
|
||||||
|
|
||||||
ArrayResolver resolver = (ArrayResolver)resolverMethod.CreateDelegate(typeof(ArrayResolver));
|
|
||||||
|
|
||||||
context.Existing = resolver(context);
|
|
||||||
context.BuildComplete = true;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static object ResolveArray<T>(IBuilderContext context)
|
|
||||||
{
|
|
||||||
var registeredNamesPolicy = context.Policies.Get<IRegisteredNamesPolicy>(null);
|
|
||||||
if (registeredNamesPolicy != null)
|
|
||||||
{
|
|
||||||
var registeredNames = registeredNamesPolicy.GetRegisteredNames(typeof(T));
|
|
||||||
if (typeof(T).GetTypeInfo().IsGenericType)
|
|
||||||
{
|
|
||||||
registeredNames = registeredNames.Concat(registeredNamesPolicy.GetRegisteredNames(typeof(T).GetGenericTypeDefinition()));
|
|
||||||
}
|
|
||||||
registeredNames = registeredNames.Distinct();
|
|
||||||
|
|
||||||
return registeredNames.Select(context.NewBuildUp<T>).ToArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
return new T[0];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,60 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Reflection;
|
|
||||||
using Unity.Builder;
|
|
||||||
using Unity.Builder.Strategy;
|
|
||||||
using Unity.Injection;
|
|
||||||
using Unity.Lifetime;
|
|
||||||
using Unity.ObjectBuilder.Policies;
|
|
||||||
using Unity.Policy;
|
|
||||||
using Unity.Registration;
|
|
||||||
using Unity.Strategy;
|
|
||||||
|
|
||||||
namespace Unity.ObjectBuilder.Strategies
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Represents a strategy for mapping build keys in the build up operation.
|
|
||||||
/// </summary>
|
|
||||||
public class BuildKeyMappingStrategy : BuilderStrategy, IRegisterTypeStrategy
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Called during the chain of responsibility for a build operation. Looks for the <see cref="IBuildKeyMappingPolicy"/>
|
|
||||||
/// and if found maps the build key for the current operation.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context">The context for the operation.</param>
|
|
||||||
public override object PreBuildUp(IBuilderContext context)
|
|
||||||
{
|
|
||||||
var policy = context.Policies.Get<IBuildKeyMappingPolicy>(context.BuildKey, out _);
|
|
||||||
if (null == policy) return null;
|
|
||||||
|
|
||||||
context.BuildKey = policy.Map(context.BuildKey, context);
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RegisterType(IContainerContext context, Type typeFrom, Type typeTo, string name,
|
|
||||||
LifetimeManager lifetimeManager, params InjectionMember[] injectionMembers)
|
|
||||||
{
|
|
||||||
if (null == typeFrom || typeFrom == typeTo)
|
|
||||||
{
|
|
||||||
context.Policies.Clear(typeTo, name, typeof(IBuildKeyMappingPolicy));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeFrom.GetTypeInfo().IsGenericTypeDefinition && typeTo.GetTypeInfo().IsGenericTypeDefinition)
|
|
||||||
{
|
|
||||||
context.Policies.Set<IBuildKeyMappingPolicy>(new GenericTypeBuildKeyMappingPolicy(new NamedTypeBuildKey(typeTo, name)),
|
|
||||||
new NamedTypeBuildKey(typeFrom, name));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
context.Policies.Set(typeFrom, name, typeof(IBuildKeyMappingPolicy),
|
|
||||||
new BuildKeyMappingPolicy(new NamedTypeBuildKey(typeTo, name)));
|
|
||||||
}
|
|
||||||
|
|
||||||
var members = null == injectionMembers ? new InjectionMember[0] : injectionMembers;
|
|
||||||
if (!members.Where(m => m is InjectionConstructor || m is InjectionMethod || m is InjectionProperty).Any() && !(lifetimeManager is IRequireBuildUpPolicy))
|
|
||||||
context.Policies.Set(typeFrom, name, typeof(IBuildPlanPolicy), new ResolveBuildUpPolicy());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,40 +0,0 @@
|
||||||
using System;
|
|
||||||
using Unity.Builder;
|
|
||||||
using Unity.Builder.Strategy;
|
|
||||||
using Unity.Lifetime;
|
|
||||||
using Unity.ObjectBuilder.Policies;
|
|
||||||
using Unity.Policy;
|
|
||||||
using Unity.Registration;
|
|
||||||
using Unity.Strategy;
|
|
||||||
|
|
||||||
namespace Unity.ObjectBuilder.Strategies
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// A <see cref="BuilderStrategy"/> that will look for a build plan
|
|
||||||
/// in the current context. If it exists, it invokes it, otherwise
|
|
||||||
/// it creates one and stores it for later, and invokes it.
|
|
||||||
/// </summary>
|
|
||||||
public class BuildPlanStrategy : BuilderStrategy
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Called during the chain of responsibility for a build operation.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context">The context for the operation.</param>
|
|
||||||
public override object PreBuildUp(IBuilderContext context)
|
|
||||||
{
|
|
||||||
var plan = context.Policies.Get<IBuildPlanPolicy>(context.OriginalBuildKey, out var buildPlanLocation);
|
|
||||||
if (plan == null || plan is OverriddenBuildPlanMarkerPolicy)
|
|
||||||
{
|
|
||||||
var planCreator = context.Policies.Get<IBuildPlanCreatorPolicy>(context.BuildKey, out var creatorLocation);
|
|
||||||
if (planCreator != null)
|
|
||||||
{
|
|
||||||
plan = planCreator.CreatePlan(context, context.BuildKey);
|
|
||||||
(buildPlanLocation ?? creatorLocation).Set(plan, context.OriginalBuildKey);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
plan?.BuildUp(context);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,160 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Reflection;
|
|
||||||
using Unity.Builder;
|
|
||||||
using Unity.Builder.Strategy;
|
|
||||||
using Unity.Exceptions;
|
|
||||||
using Unity.Extension;
|
|
||||||
using Unity.Lifetime;
|
|
||||||
using Unity.Policy;
|
|
||||||
using Unity.Registration;
|
|
||||||
using Unity.Strategy;
|
|
||||||
|
|
||||||
namespace Unity.ObjectBuilder.Strategies
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// An <see cref="IBuilderStrategy"/> implementation that uses
|
|
||||||
/// a <see cref="ILifetimePolicy"/> to figure out if an object
|
|
||||||
/// has already been created and to update or remove that
|
|
||||||
/// object from some backing store.
|
|
||||||
/// </summary>
|
|
||||||
public class LifetimeStrategy : BuilderStrategy, IRegisterTypeStrategy
|
|
||||||
{
|
|
||||||
#region Fields
|
|
||||||
|
|
||||||
private readonly object _genericLifetimeManagerLock = new object();
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region BuilderStrategy
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Called during the chain of responsibility for a build operation. The
|
|
||||||
/// PreBuildUp method is called when the chain is being executed in the
|
|
||||||
/// forward direction.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context">Context of the build operation.</param>
|
|
||||||
public override object PreBuildUp(IBuilderContext context)
|
|
||||||
{
|
|
||||||
if (context.Existing != null) return null;
|
|
||||||
|
|
||||||
var lifetimePolicy = GetLifetimePolicy(context, out var _);
|
|
||||||
if (lifetimePolicy is IRequiresRecovery recovery)
|
|
||||||
{
|
|
||||||
context.RecoveryStack.Add(recovery);
|
|
||||||
}
|
|
||||||
|
|
||||||
var existing = lifetimePolicy?.GetValue(context.Lifetime);
|
|
||||||
if (existing != null)
|
|
||||||
{
|
|
||||||
context.Existing = existing;
|
|
||||||
context.BuildComplete = true;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Called during the chain of responsibility for a build operation. The
|
|
||||||
/// PostBuildUp method is called when the chain has finished the PreBuildUp
|
|
||||||
/// phase and executes in reverse order from the PreBuildUp calls.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context">Context of the build operation.</param>
|
|
||||||
public override void PostBuildUp(IBuilderContext context, object pre = null)
|
|
||||||
{
|
|
||||||
// If we got to this method, then we know the lifetime policy didn't
|
|
||||||
// find the object. So we go ahead and store it.
|
|
||||||
ILifetimePolicy lifetimePolicy = GetLifetimePolicy(context, out IPolicyList _);
|
|
||||||
lifetimePolicy.SetValue(context.Existing, context.Lifetime);
|
|
||||||
}
|
|
||||||
|
|
||||||
private ILifetimePolicy GetLifetimePolicy(IBuilderContext context, out IPolicyList source)
|
|
||||||
{
|
|
||||||
ILifetimePolicy policy = context.Policies.GetNoDefault<ILifetimePolicy>(context.OriginalBuildKey, false, out source);
|
|
||||||
if (policy == null && context.OriginalBuildKey.Type.GetTypeInfo().IsGenericType)
|
|
||||||
{
|
|
||||||
policy = GetLifetimePolicyForGenericType(context, out source);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (policy == null)
|
|
||||||
{
|
|
||||||
policy = TransientLifetimeManager.Instance;
|
|
||||||
context.PersistentPolicies.Set(policy, context.OriginalBuildKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
return policy;
|
|
||||||
}
|
|
||||||
|
|
||||||
private ILifetimePolicy GetLifetimePolicyForGenericType(IBuilderContext context, out IPolicyList factorySource)
|
|
||||||
{
|
|
||||||
var typeToBuild = context.OriginalBuildKey.Type;
|
|
||||||
object openGenericBuildKey = new NamedTypeBuildKey(typeToBuild.GetGenericTypeDefinition(),
|
|
||||||
context.OriginalBuildKey.Name);
|
|
||||||
|
|
||||||
var factoryPolicy = context.Policies
|
|
||||||
.Get<ILifetimeFactoryPolicy>(openGenericBuildKey, out factorySource);
|
|
||||||
|
|
||||||
if (factoryPolicy != null)
|
|
||||||
{
|
|
||||||
// creating the lifetime policy can result in arbitrary code execution
|
|
||||||
// in particular it will likely result in a Resolve call, which could result in locking
|
|
||||||
// to avoid deadlocks the new lifetime policy is created outside the lock
|
|
||||||
// multiple instances might be created, but only one instance will be used
|
|
||||||
ILifetimePolicy newLifetime = factoryPolicy.CreateLifetimePolicy();
|
|
||||||
|
|
||||||
lock (_genericLifetimeManagerLock)
|
|
||||||
{
|
|
||||||
// check whether the policy for closed-generic has been added since first checked
|
|
||||||
var lifetime = factorySource.GetNoDefault<ILifetimePolicy>(context.BuildKey);
|
|
||||||
if (lifetime == null)
|
|
||||||
{
|
|
||||||
factorySource.Set(newLifetime, context.BuildKey);
|
|
||||||
lifetime = newLifetime;
|
|
||||||
}
|
|
||||||
|
|
||||||
return lifetime;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region IRegisterTypeStrategy
|
|
||||||
|
|
||||||
public void RegisterType(IContainerContext context, Type typeFrom, Type typeTo, string name,
|
|
||||||
LifetimeManager lifetimeManager, params InjectionMember[] injectionMembers)
|
|
||||||
{
|
|
||||||
var lifetimeType = typeFrom ?? typeTo;
|
|
||||||
|
|
||||||
if (null == lifetimeManager)
|
|
||||||
{
|
|
||||||
context.Policies.Clear(lifetimeType, name, typeof(ILifetimePolicy));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lifetimeManager.InUse)
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException(Constants.LifetimeManagerInUse);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lifetimeType.GetTypeInfo().IsGenericTypeDefinition)
|
|
||||||
{
|
|
||||||
LifetimeManagerFactory factory = new LifetimeManagerFactory((ExtensionContext)context, lifetimeManager);
|
|
||||||
context.Policies.Set<ILifetimeFactoryPolicy>(factory, new NamedTypeBuildKey(lifetimeType, name));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
lifetimeManager.InUse = true;
|
|
||||||
context.Policies.Set<ILifetimePolicy>(lifetimeManager, new NamedTypeBuildKey(lifetimeType, name));
|
|
||||||
if (lifetimeManager is IDisposable)
|
|
||||||
{
|
|
||||||
context.Lifetime.Add(lifetimeManager);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -4,15 +4,15 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using Unity.Builder;
|
using Unity.Builder;
|
||||||
using Unity.Policy;
|
using Unity.ObjectBuilder.BuildPlan.DynamicMethod.Creation;
|
||||||
|
|
||||||
namespace Unity.ObjectBuilder.BuildPlan
|
namespace Unity.Policy.BuildPlanCreator
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Build plan for <see cref="Func{TResult}"/> that will return a Func that will resolve the requested type
|
/// Build plan for <see cref="Func{TResult}"/> that will return a Func that will resolve the requested type
|
||||||
/// through this container later.
|
/// through this container later.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal class DeferredResolveBuildPlanPolicy : IBuildPlanPolicy
|
internal class DeferredResolveCreatorPolicy : IBuildPlanPolicy
|
||||||
{
|
{
|
||||||
public void BuildUp(IBuilderContext context)
|
public void BuildUp(IBuilderContext context)
|
||||||
{
|
{
|
||||||
|
@ -34,7 +34,7 @@ namespace Unity.ObjectBuilder.BuildPlan
|
||||||
|
|
||||||
context.Existing = resolveMethod;
|
context.Existing = resolveMethod;
|
||||||
|
|
||||||
context.SetPerBuildSingleton();
|
DynamicMethodConstructorStrategy.SetPerBuildSingleton(context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
using System;
|
||||||
|
using System.Reflection;
|
||||||
|
using Unity.Builder;
|
||||||
|
using Unity.ObjectBuilder.BuildPlan.DynamicMethod;
|
||||||
|
|
||||||
|
namespace Unity.Policy.BuildPlanCreator
|
||||||
|
{
|
||||||
|
public class DelegateBasedBuildPlanCreatorPolicy : IBuildPlanCreatorPolicy
|
||||||
|
{
|
||||||
|
#region Fields
|
||||||
|
|
||||||
|
private readonly MethodInfo _resolveMethod;
|
||||||
|
private readonly Func<IBuilderContext, Type> _getTypeFunc;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
public DelegateBasedBuildPlanCreatorPolicy(MethodInfo resolveMethod, Func<IBuilderContext, Type> getTypeFunc)
|
||||||
|
{
|
||||||
|
_resolveMethod = resolveMethod;
|
||||||
|
_getTypeFunc = getTypeFunc;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region IBuildPlanCreatorPolicy
|
||||||
|
|
||||||
|
public IBuildPlanPolicy CreatePlan(IBuilderContext context, INamedType buildKey)
|
||||||
|
{
|
||||||
|
var buildMethod = _resolveMethod.MakeGenericMethod(_getTypeFunc(context))
|
||||||
|
.CreateDelegate(typeof(DynamicBuildPlanMethod));
|
||||||
|
|
||||||
|
return new DynamicMethodBuildPlan((DynamicBuildPlanMethod)buildMethod);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,22 +5,21 @@ using System.Collections.Generic;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using Unity.Builder;
|
using Unity.Builder;
|
||||||
using Unity.ObjectBuilder.BuildPlan.DynamicMethod;
|
using Unity.ObjectBuilder.BuildPlan.DynamicMethod;
|
||||||
using Unity.Policy;
|
|
||||||
|
|
||||||
namespace Unity.ObjectBuilder.BuildPlan
|
namespace Unity.Policy.BuildPlanCreator
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// An <see cref="IBuildPlanCreatorPolicy"/> implementation
|
/// An <see cref="IBuildPlanCreatorPolicy"/> implementation
|
||||||
/// that constructs a build plan for creating <see cref="Lazy{T}"/> objects.
|
/// that constructs a build plan for creating <see cref="Lazy{T}"/> objects.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class LazyDynamicMethodBuildPlanCreatorPolicy : IBuildPlanCreatorPolicy
|
public class GenericLazyBuildPlanCreatorPolicy : IBuildPlanCreatorPolicy
|
||||||
{
|
{
|
||||||
private static readonly MethodInfo BuildResolveLazyMethod;
|
private static readonly MethodInfo BuildResolveLazyMethod;
|
||||||
private static readonly MethodInfo BuildResolveAllLazyMethod;
|
private static readonly MethodInfo BuildResolveAllLazyMethod;
|
||||||
|
|
||||||
static LazyDynamicMethodBuildPlanCreatorPolicy()
|
static GenericLazyBuildPlanCreatorPolicy()
|
||||||
{
|
{
|
||||||
var info = typeof(LazyDynamicMethodBuildPlanCreatorPolicy).GetTypeInfo();
|
var info = typeof(GenericLazyBuildPlanCreatorPolicy).GetTypeInfo();
|
||||||
|
|
||||||
BuildResolveLazyMethod =
|
BuildResolveLazyMethod =
|
||||||
info.GetDeclaredMethod(nameof(BuildResolveLazy));
|
info.GetDeclaredMethod(nameof(BuildResolveLazy));
|
|
@ -1,26 +1,35 @@
|
||||||
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
|
using System;
|
||||||
|
|
||||||
using Unity.Builder;
|
using Unity.Builder;
|
||||||
using Unity.Policy;
|
|
||||||
|
|
||||||
namespace Unity.ObjectBuilder.Policies
|
namespace Unity.Policy.Mapping
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a builder policy for mapping build keys.
|
/// Represents a builder policy for mapping build keys.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class BuildKeyMappingPolicy : IBuildKeyMappingPolicy
|
public class BuildKeyMappingPolicy : NamedTypeBase, IBuildKeyMappingPolicy
|
||||||
{
|
{
|
||||||
private readonly NamedTypeBuildKey _newBuildKey;
|
#region Constructors
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initialize a new instance of the <see cref="BuildKeyMappingPolicy"/> with the new build key.
|
/// Initialize a new instance of the <see cref="BuildKeyMappingPolicy"/> with the new build key.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="newBuildKey">The new build key.</param>
|
/// <param name="newBuildKey">The new build key.</param>
|
||||||
public BuildKeyMappingPolicy(NamedTypeBuildKey newBuildKey)
|
public BuildKeyMappingPolicy(INamedType newBuildKey)
|
||||||
|
: base(newBuildKey.Type, newBuildKey.Name)
|
||||||
{
|
{
|
||||||
_newBuildKey = newBuildKey;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public BuildKeyMappingPolicy(Type type, string name)
|
||||||
|
: base(type, name)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region IBuildKeyMappingPolicy
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Maps the build key.
|
/// Maps the build key.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -30,7 +39,9 @@ namespace Unity.ObjectBuilder.Policies
|
||||||
/// <returns>The new build key.</returns>
|
/// <returns>The new build key.</returns>
|
||||||
public INamedType Map(INamedType buildKey, IBuilderContext context)
|
public INamedType Map(INamedType buildKey, IBuilderContext context)
|
||||||
{
|
{
|
||||||
return _newBuildKey;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,73 @@
|
||||||
|
using System;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Reflection;
|
||||||
|
using Unity.Builder;
|
||||||
|
|
||||||
|
namespace Unity.Policy.Mapping
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// An implementation of <see cref="IBuildKeyMappingPolicy"/> that can map
|
||||||
|
/// generic types.
|
||||||
|
/// </summary>
|
||||||
|
public class GenericTypeBuildKeyMappingPolicy : NamedTypeBase, IBuildKeyMappingPolicy
|
||||||
|
{
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create a new <see cref="GenericTypeBuildKeyMappingPolicy"/> instance
|
||||||
|
/// that will map generic types.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="type">Type mapped to</param>
|
||||||
|
/// <param name="name">Name</param>
|
||||||
|
public GenericTypeBuildKeyMappingPolicy(Type type, string name)
|
||||||
|
: base(type, name)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create a new <see cref="GenericTypeBuildKeyMappingPolicy"/> instance
|
||||||
|
/// that will map generic types.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="destinationKey">Build key to map to. This must be or contain an open generic type.</param>
|
||||||
|
public GenericTypeBuildKeyMappingPolicy(INamedType destinationKey)
|
||||||
|
: base(destinationKey.Type, destinationKey.Name)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region IBuildKeyMappingPolicy
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Maps the build key.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="buildKey">The build key to map.</param>
|
||||||
|
/// <param name="context">Current build context. Used for contextual information
|
||||||
|
/// if writing a more sophisticated mapping.</param>
|
||||||
|
/// <returns>The new build key.</returns>
|
||||||
|
public INamedType Map(INamedType buildKey, IBuilderContext context)
|
||||||
|
{
|
||||||
|
var targetTypeInfo = buildKey.Type.GetTypeInfo();
|
||||||
|
if (targetTypeInfo.IsGenericTypeDefinition)
|
||||||
|
{
|
||||||
|
// No need to perform a mapping - the source type is an open generic
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (targetTypeInfo.GenericTypeArguments.Length != Type.GetTypeInfo().GenericTypeParameters.Length)
|
||||||
|
{
|
||||||
|
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture,
|
||||||
|
Constants.MustHaveSameNumberOfGenericArguments,
|
||||||
|
buildKey.Type.Name, Type.Name),
|
||||||
|
nameof(buildKey.Type));
|
||||||
|
}
|
||||||
|
|
||||||
|
Type[] genericArguments = targetTypeInfo.GenericTypeArguments;
|
||||||
|
Type resultType = Type.MakeGenericType(genericArguments);
|
||||||
|
return new NamedTypeBuildKey(resultType, Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,161 @@
|
||||||
|
using System;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Reflection;
|
||||||
|
using Unity.Builder;
|
||||||
|
using Unity.Lifetime;
|
||||||
|
using Unity.Policy;
|
||||||
|
using Unity.Storage;
|
||||||
|
|
||||||
|
namespace Unity.Registration
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// This class holds instance registration
|
||||||
|
/// </summary>
|
||||||
|
public class InstanceRegistration : NamedTypeBase,
|
||||||
|
IContainerRegistration,
|
||||||
|
IBuildPlanCreatorPolicy,
|
||||||
|
IBuildPlanPolicy,
|
||||||
|
IPolicySet,
|
||||||
|
IDisposable
|
||||||
|
{
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Instance registration with the container.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks> <para>
|
||||||
|
/// Instance registration is much like setting a type as a singleton, except that instead
|
||||||
|
/// of the container creating the instance the first time it is requested, the user
|
||||||
|
/// creates the instance ahead of type and adds that instance to the container.
|
||||||
|
/// </para></remarks>
|
||||||
|
/// <param name="registrationType">Type of instance to register (may be an implemented interface instead of the full type).</param>
|
||||||
|
/// <param name="instance">Object to be returned.</param>
|
||||||
|
/// <param name="registrationName">Name for registration.</param>
|
||||||
|
/// <param name="lifetimeManager">
|
||||||
|
/// <para>If null or <see cref="ContainerControlledLifetimeManager"/>, the container will take over the lifetime of the instance,
|
||||||
|
/// calling Dispose on it (if it's <see cref="IDisposable"/>) when the container is Disposed.</para>
|
||||||
|
/// <para>
|
||||||
|
/// If <see cref="ExternallyControlledLifetimeManager"/>, container will not maintain a strong reference to <paramref name="instance"/>.
|
||||||
|
/// User is responsible for disposing instance, and for keeping the instance typeFrom being garbage collected.</para></param>
|
||||||
|
/// <returns>The <see cref="UnityContainer"/> object that this method was called on (this in C#, Me in Visual Basic).</returns>
|
||||||
|
public InstanceRegistration(Type registrationType, string registrationName, object instance, LifetimeManager lifetimeManager)
|
||||||
|
: base(registrationType ?? (instance ?? throw new ArgumentNullException(nameof(instance))).GetType(),
|
||||||
|
string.IsNullOrEmpty(registrationName) ? null : registrationName)
|
||||||
|
{
|
||||||
|
// Validate input
|
||||||
|
if (null != registrationType) InstanceIsAssignable(registrationType, instance, nameof(instance));
|
||||||
|
|
||||||
|
LifetimeManager = lifetimeManager;
|
||||||
|
MappedToType = registrationType ?? instance.GetType();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region IPolicySet
|
||||||
|
|
||||||
|
public IBuilderPolicy Get(Type policyInterface)
|
||||||
|
{
|
||||||
|
if (typeof(ILifetimePolicy) == policyInterface)
|
||||||
|
return LifetimeManager;
|
||||||
|
|
||||||
|
if (typeof(IBuildPlanPolicy) == policyInterface ||
|
||||||
|
typeof(IBuildPlanCreatorPolicy) == policyInterface)
|
||||||
|
return this;
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Set(Type policyInterface, IBuilderPolicy policy)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Clear(Type policyInterface)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ClearAll()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region IContainerRegistration
|
||||||
|
|
||||||
|
public Type RegisteredType => Type;
|
||||||
|
|
||||||
|
public Type MappedToType { get; }
|
||||||
|
|
||||||
|
public LifetimeManager LifetimeManager { get; }
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region IBuildPlanCreatorPolicy
|
||||||
|
|
||||||
|
public IBuildPlanPolicy CreatePlan(IBuilderContext context, INamedType buildKey)
|
||||||
|
{
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region IBuildPlanPolicy
|
||||||
|
|
||||||
|
public void BuildUp(IBuilderContext context)
|
||||||
|
{
|
||||||
|
context.Existing = LifetimeManager.GetValue();
|
||||||
|
context.BuildComplete = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Implementation
|
||||||
|
|
||||||
|
private static void InstanceIsAssignable(Type assignmentTargetType, object assignmentInstance, string argumentName)
|
||||||
|
{
|
||||||
|
if (!(assignmentTargetType ?? throw new ArgumentNullException(nameof(assignmentTargetType)))
|
||||||
|
.GetTypeInfo().IsAssignableFrom((assignmentInstance ?? throw new ArgumentNullException(nameof(assignmentInstance))).GetType().GetTypeInfo()))
|
||||||
|
{
|
||||||
|
throw new ArgumentException(
|
||||||
|
string.Format(
|
||||||
|
CultureInfo.CurrentCulture,
|
||||||
|
Constants.TypesAreNotAssignable,
|
||||||
|
assignmentTargetType, GetTypeName(assignmentInstance)),
|
||||||
|
argumentName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetTypeName(object assignmentInstance)
|
||||||
|
{
|
||||||
|
string assignmentInstanceType;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
assignmentInstanceType = assignmentInstance.GetType().FullName;
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
assignmentInstanceType = Constants.UnknownType;
|
||||||
|
}
|
||||||
|
|
||||||
|
return assignmentInstanceType;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region IDisposable
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
if (LifetimeManager is IDisposable disposable)
|
||||||
|
disposable.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,132 @@
|
||||||
|
using System;
|
||||||
|
using Unity.Builder;
|
||||||
|
using Unity.Policy;
|
||||||
|
using Unity.Storage;
|
||||||
|
|
||||||
|
namespace Unity.Registration
|
||||||
|
{
|
||||||
|
public class InternalRegistration : LinkedNode<Type, IBuilderPolicy>,
|
||||||
|
IPolicySet,
|
||||||
|
INamedType
|
||||||
|
{
|
||||||
|
#region Fields
|
||||||
|
|
||||||
|
private readonly int _hash;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
public InternalRegistration(Type type, string name)
|
||||||
|
{
|
||||||
|
Name = name;
|
||||||
|
Type = type;
|
||||||
|
_hash = (Type?.GetHashCode() ?? 0 + 37) ^ (Name?.GetHashCode() ?? 0 + 17);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region IPolicySet
|
||||||
|
|
||||||
|
public virtual IBuilderPolicy Get(Type policyInterface)
|
||||||
|
{
|
||||||
|
for (var node = (LinkedNode<Type, IBuilderPolicy>)this; node != null; node = node.Next)
|
||||||
|
{
|
||||||
|
if (node.Key == policyInterface)
|
||||||
|
return node.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void Set(Type policyInterface, IBuilderPolicy policy)
|
||||||
|
{
|
||||||
|
LinkedNode<Type, IBuilderPolicy> node;
|
||||||
|
LinkedNode<Type, IBuilderPolicy> last = null;
|
||||||
|
|
||||||
|
for (node = this; node != null; node = node.Next)
|
||||||
|
{
|
||||||
|
if (node.Key == policyInterface)
|
||||||
|
{
|
||||||
|
// Found it
|
||||||
|
node.Value = policy;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
last = node;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not found, so add a new one
|
||||||
|
last.Next = new LinkedNode<Type, IBuilderPolicy>
|
||||||
|
{
|
||||||
|
Key = policyInterface,
|
||||||
|
Value = policy
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void Clear(Type policyInterface)
|
||||||
|
{
|
||||||
|
LinkedNode<Type, IBuilderPolicy> node;
|
||||||
|
LinkedNode<Type, IBuilderPolicy> last = null;
|
||||||
|
|
||||||
|
for (node = this; node != null; node = node.Next)
|
||||||
|
{
|
||||||
|
if (node.Key == policyInterface)
|
||||||
|
{
|
||||||
|
if (null == last)
|
||||||
|
{
|
||||||
|
Key = node.Next?.Key;
|
||||||
|
Value = node.Next?.Value;
|
||||||
|
Next = node.Next?.Next;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
last.Key = node.Next?.Key;
|
||||||
|
last.Value = node.Next?.Value;
|
||||||
|
last.Next = node.Next?.Next;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
last = node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void ClearAll()
|
||||||
|
{
|
||||||
|
Key = null;
|
||||||
|
Value = null;
|
||||||
|
Next = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region INamedType
|
||||||
|
|
||||||
|
public Type Type { get; }
|
||||||
|
|
||||||
|
public string Name { get; }
|
||||||
|
|
||||||
|
public override bool Equals(object obj)
|
||||||
|
{
|
||||||
|
return obj is INamedType registration &&
|
||||||
|
Type == registration.Type &&
|
||||||
|
Name == registration.Name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
return _hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static implicit operator NamedTypeBuildKey(InternalRegistration namedType)
|
||||||
|
{
|
||||||
|
return new NamedTypeBuildKey(namedType.Type, namedType.Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,66 @@
|
||||||
|
using System;
|
||||||
|
using Unity.Lifetime;
|
||||||
|
using Unity.Policy;
|
||||||
|
|
||||||
|
namespace Unity.Registration
|
||||||
|
{
|
||||||
|
public class TypeRegistration : InternalRegistration,
|
||||||
|
IContainerRegistration
|
||||||
|
{
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
public TypeRegistration(Type typeFrom, Type typeTo, string name, LifetimeManager lifetimeManager)
|
||||||
|
: base(typeFrom ?? typeTo, string.IsNullOrEmpty(name) ? null : name)
|
||||||
|
{
|
||||||
|
MappedToType = typeTo;
|
||||||
|
|
||||||
|
// Make sure manager is not being used already
|
||||||
|
if (lifetimeManager.InUse)
|
||||||
|
{
|
||||||
|
if (lifetimeManager is ILifetimeFactoryPolicy factory)
|
||||||
|
lifetimeManager = (LifetimeManager)factory.CreateLifetimePolicy();
|
||||||
|
else
|
||||||
|
throw new InvalidOperationException(Constants.LifetimeManagerInUse);
|
||||||
|
}
|
||||||
|
|
||||||
|
LifetimeManager = lifetimeManager;
|
||||||
|
LifetimeManager.InUse = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region IContainerRegistration
|
||||||
|
|
||||||
|
public Type RegisteredType => Type;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The type that this registration is mapped to. If no type mapping was done, the
|
||||||
|
/// <see cref="InternalRegistration.Type"/> property and this one will have the same value.
|
||||||
|
/// </summary>
|
||||||
|
public Type MappedToType { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The lifetime manager for this registration.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// This property will be null if this registration is for an open generic.</remarks>
|
||||||
|
public LifetimeManager LifetimeManager { get; }
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region IPolicySet
|
||||||
|
|
||||||
|
public override IBuilderPolicy Get(Type policyInterface)
|
||||||
|
{
|
||||||
|
if (typeof(ILifetimePolicy) == policyInterface)
|
||||||
|
return LifetimeManager;
|
||||||
|
|
||||||
|
return base.Get(policyInterface);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
namespace Unity.Resolution
|
||||||
|
{
|
||||||
|
public enum TypeSelectStage
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// First stage. By default, nothing happens here.
|
||||||
|
/// </summary>
|
||||||
|
Setup,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks for already registered types
|
||||||
|
/// </summary>
|
||||||
|
Registration,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if type is array
|
||||||
|
/// </summary>
|
||||||
|
Array,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if type is generic
|
||||||
|
/// </summary>
|
||||||
|
Generic,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if type is Plain old clr object
|
||||||
|
/// </summary>
|
||||||
|
Poco,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an exception if pype could not be found
|
||||||
|
/// </summary>
|
||||||
|
Exception
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,199 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Unity.Utility;
|
||||||
|
|
||||||
|
namespace Unity.Storage
|
||||||
|
{
|
||||||
|
internal class HashRegistry<TKey, TValue> : IRegistry<TKey, TValue>
|
||||||
|
{
|
||||||
|
#region Constants
|
||||||
|
|
||||||
|
private const float LoadFactor = 0.72f;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Fields
|
||||||
|
|
||||||
|
public readonly int[] Buckets;
|
||||||
|
public readonly Entry[] Entries;
|
||||||
|
public int Count;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
public HashRegistry(int capacity)
|
||||||
|
{
|
||||||
|
var size = Prime.GetPrime(capacity);
|
||||||
|
Buckets = new int[size];
|
||||||
|
Entries = new Entry[size];
|
||||||
|
|
||||||
|
for (var i = 0; i < Buckets.Length; i++) Buckets[i] = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HashRegistry(int capacity, LinkedNode<TKey, TValue> head)
|
||||||
|
{
|
||||||
|
var size = Prime.GetPrime(capacity);
|
||||||
|
Buckets = new int[size];
|
||||||
|
Entries = new Entry[size];
|
||||||
|
|
||||||
|
for (var i = 0; i < Buckets.Length; i++) Buckets[i] = -1;
|
||||||
|
for (var node = head; node != null; node = node.Next)
|
||||||
|
{
|
||||||
|
this[node.Key] = node.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public HashRegistry(HashRegistry<TKey, TValue> dictionary)
|
||||||
|
{
|
||||||
|
var size = Prime.GetPrime(dictionary.Entries.Length * 2);
|
||||||
|
|
||||||
|
Buckets = new int[size];
|
||||||
|
Entries = new Entry[size];
|
||||||
|
for (var i = 0; i < Buckets.Length; i++) Buckets[i] = -1;
|
||||||
|
|
||||||
|
Array.Copy(dictionary.Entries, 0, Entries, 0, dictionary.Count);
|
||||||
|
for (var i = 0; i < dictionary.Count; i++)
|
||||||
|
{
|
||||||
|
var hashCode = Entries[i].HashCode;
|
||||||
|
if (hashCode < 0) continue;
|
||||||
|
|
||||||
|
var bucket = hashCode % size;
|
||||||
|
Entries[i].Next = Buckets[bucket];
|
||||||
|
Buckets[bucket] = i;
|
||||||
|
}
|
||||||
|
Count = dictionary.Count;
|
||||||
|
dictionary.Count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region IRegistry
|
||||||
|
|
||||||
|
public TValue this[TKey key]
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var hashCode = null == key ? 0 : key.GetHashCode() & 0x7FFFFFFF;
|
||||||
|
for (var i = Buckets[hashCode % Buckets.Length]; i >= 0; i = Entries[i].Next)
|
||||||
|
{
|
||||||
|
if (Entries[i].HashCode == hashCode && Equals(Entries[i].Key, key)) return Entries[i].Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return default(TValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
set
|
||||||
|
{
|
||||||
|
var hashCode = null == key ? 0 : key.GetHashCode() & 0x7FFFFFFF;
|
||||||
|
var targetBucket = hashCode % Buckets.Length;
|
||||||
|
|
||||||
|
for (var i = Buckets[targetBucket]; i >= 0; i = Entries[i].Next)
|
||||||
|
{
|
||||||
|
if (Entries[i].HashCode == hashCode && Equals(Entries[i].Key, key))
|
||||||
|
{
|
||||||
|
Entries[i].Value = value;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Entries[Count].HashCode = hashCode;
|
||||||
|
Entries[Count].Next = Buckets[targetBucket];
|
||||||
|
Entries[Count].Key = key;
|
||||||
|
Entries[Count].Value = value;
|
||||||
|
Buckets[targetBucket] = Count;
|
||||||
|
Count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool RequireToGrow => (Entries.Length - Count) < 100 &&
|
||||||
|
(float)Count / Entries.Length > LoadFactor;
|
||||||
|
|
||||||
|
public IEnumerable<TKey> Keys
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
for (var i = 0; i < Count; i++)
|
||||||
|
{
|
||||||
|
yield return Entries[i].Key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<TValue> Values
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
for (var i = 0; i < Count; i++)
|
||||||
|
{
|
||||||
|
yield return Entries[i].Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public TValue GetOrAdd(TKey key, Func<TValue> factory)
|
||||||
|
{
|
||||||
|
var hashCode = (key?.GetHashCode() ?? 0) & 0x7FFFFFFF;
|
||||||
|
var targetBucket = hashCode % Buckets.Length;
|
||||||
|
for (var i = Buckets[targetBucket]; i >= 0; i = Entries[i].Next)
|
||||||
|
{
|
||||||
|
var entry = Entries[i];
|
||||||
|
if (entry.HashCode != hashCode || Equals(entry.Key, key)) continue;
|
||||||
|
|
||||||
|
return Entries[i].Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
var value = factory();
|
||||||
|
Entries[Count].HashCode = hashCode;
|
||||||
|
Entries[Count].Next = Buckets[targetBucket];
|
||||||
|
Entries[Count].Key = key;
|
||||||
|
Entries[Count].Value = value;
|
||||||
|
Buckets[targetBucket] = Count;
|
||||||
|
Count++;
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TValue SetOrReplace(TKey key, TValue value)
|
||||||
|
{
|
||||||
|
var hashCode = (key?.GetHashCode() ?? 0) & 0x7FFFFFFF;
|
||||||
|
var targetBucket = hashCode % Buckets.Length;
|
||||||
|
for (var i = Buckets[targetBucket]; i >= 0; i = Entries[i].Next)
|
||||||
|
{
|
||||||
|
var entry = Entries[i];
|
||||||
|
if (entry.HashCode != hashCode || Equals(entry.Key, key)) continue;
|
||||||
|
|
||||||
|
var old = Entries[i].Value;
|
||||||
|
Entries[i].Value = value;
|
||||||
|
return old;
|
||||||
|
}
|
||||||
|
|
||||||
|
Entries[Count].HashCode = hashCode;
|
||||||
|
Entries[Count].Next = Buckets[targetBucket];
|
||||||
|
Entries[Count].Key = key;
|
||||||
|
Entries[Count].Value = value;
|
||||||
|
Buckets[targetBucket] = Count;
|
||||||
|
Count++;
|
||||||
|
|
||||||
|
return default(TValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Nested Types
|
||||||
|
|
||||||
|
public struct Entry
|
||||||
|
{
|
||||||
|
public int HashCode;
|
||||||
|
public int Next;
|
||||||
|
public TKey Key;
|
||||||
|
public TValue Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
using System;
|
||||||
|
using Unity.Policy;
|
||||||
|
|
||||||
|
namespace Unity.Storage
|
||||||
|
{
|
||||||
|
public interface IPolicySet
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Get policy
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="policyInterface">Type of policy to retrieve</param>
|
||||||
|
/// <returns>Instance of the policy or null if none found</returns>
|
||||||
|
IBuilderPolicy Get(Type policyInterface);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Set policy
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="policyInterface">Type of policy to be set</param>
|
||||||
|
/// <param name="policy">Policy instance to be set</param>
|
||||||
|
void Set(Type policyInterface, IBuilderPolicy policy);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Remove specific policy from the list
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="policyInterface">Type of policy to be removed</param>
|
||||||
|
void Clear(Type policyInterface);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Removes all policies from the list.
|
||||||
|
/// </summary>
|
||||||
|
void ClearAll();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Unity.Storage
|
||||||
|
{
|
||||||
|
|
||||||
|
public interface IRegistry<TKey, TValue>
|
||||||
|
{
|
||||||
|
TValue this[TKey index] { get; set; }
|
||||||
|
|
||||||
|
bool RequireToGrow { get; }
|
||||||
|
|
||||||
|
IEnumerable<TKey> Keys { get; }
|
||||||
|
|
||||||
|
IEnumerable<TValue> Values { get; }
|
||||||
|
|
||||||
|
TValue GetOrAdd(TKey key, Func<TValue> factory);
|
||||||
|
|
||||||
|
TValue SetOrReplace(TKey key, TValue value);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
namespace Unity.Storage
|
||||||
|
{
|
||||||
|
public class LinkedNode<TKey, TValue>
|
||||||
|
{
|
||||||
|
public TKey Key;
|
||||||
|
public TValue Value;
|
||||||
|
public LinkedNode<TKey, TValue> Next;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,155 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Unity.Policy;
|
||||||
|
|
||||||
|
namespace Unity.Storage
|
||||||
|
{
|
||||||
|
|
||||||
|
internal class LinkedRegistry : LinkedNode<string, IPolicySet>,
|
||||||
|
IRegistry<string, IPolicySet>
|
||||||
|
{
|
||||||
|
#region Fields
|
||||||
|
|
||||||
|
private int _count;
|
||||||
|
public const int ListToHashCutoverPoint = 8;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
public LinkedRegistry(string key, IPolicySet value)
|
||||||
|
{
|
||||||
|
Key = key;
|
||||||
|
Value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region IRegistry
|
||||||
|
|
||||||
|
public IPolicySet this[string key]
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
for (var node = (LinkedNode<string, IPolicySet>)this; node != null; node = node.Next)
|
||||||
|
{
|
||||||
|
if (Equals(node.Key, key))
|
||||||
|
return node.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return default(IPolicySet);
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
LinkedNode<string, IPolicySet> node;
|
||||||
|
LinkedNode<string, IPolicySet> last = null;
|
||||||
|
|
||||||
|
for (node = this; node != null; node = node.Next)
|
||||||
|
{
|
||||||
|
if (Equals(node.Key, key))
|
||||||
|
{
|
||||||
|
// Found it
|
||||||
|
node.Value = value;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
last = node;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not found, so add a new one
|
||||||
|
last.Next = new LinkedNode<string, IPolicySet>
|
||||||
|
{
|
||||||
|
Key = key,
|
||||||
|
Value = value
|
||||||
|
};
|
||||||
|
|
||||||
|
_count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool RequireToGrow => ListToHashCutoverPoint < _count;
|
||||||
|
|
||||||
|
public IEnumerable<string> Keys
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
for (LinkedNode<string, IPolicySet> node = this; node != null; node = node.Next)
|
||||||
|
{
|
||||||
|
yield return node.Key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<IPolicySet> Values
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
for (LinkedNode<string, IPolicySet> node = this; node != null; node = node.Next)
|
||||||
|
{
|
||||||
|
yield return node.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public IPolicySet GetOrAdd(string name, Func<IPolicySet> factory)
|
||||||
|
{
|
||||||
|
LinkedNode<string, IPolicySet> node;
|
||||||
|
LinkedNode<string, IPolicySet> last = null;
|
||||||
|
|
||||||
|
for (node = this; node != null; node = node.Next)
|
||||||
|
{
|
||||||
|
if (Equals(node.Key, name))
|
||||||
|
{
|
||||||
|
if (null == node.Value)
|
||||||
|
node.Value = factory();
|
||||||
|
|
||||||
|
return node.Value;
|
||||||
|
}
|
||||||
|
last = node;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not found, so add a new one
|
||||||
|
last.Next = new LinkedNode<string, IPolicySet>
|
||||||
|
{
|
||||||
|
Key = name,
|
||||||
|
Value = factory()
|
||||||
|
};
|
||||||
|
|
||||||
|
_count++;
|
||||||
|
|
||||||
|
return last.Next.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IPolicySet SetOrReplace(string name, IPolicySet value)
|
||||||
|
{
|
||||||
|
LinkedNode<string, IPolicySet> node;
|
||||||
|
LinkedNode<string, IPolicySet> last = null;
|
||||||
|
|
||||||
|
for (node = this; node != null; node = node.Next)
|
||||||
|
{
|
||||||
|
if (Equals(node.Key, name))
|
||||||
|
{
|
||||||
|
var old = node.Value;
|
||||||
|
node.Value = value;
|
||||||
|
return old;
|
||||||
|
}
|
||||||
|
last = node;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not found, so add a new one
|
||||||
|
last.Next = new LinkedNode<string, IPolicySet>
|
||||||
|
{
|
||||||
|
Key = name,
|
||||||
|
Value = value
|
||||||
|
};
|
||||||
|
|
||||||
|
_count++;
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,9 +1,8 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Unity.Policy;
|
using Unity.Policy;
|
||||||
|
|
||||||
namespace Unity.Container
|
namespace Unity.Storage
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A custom collection wrapper over <see cref="IBuilderPolicy"/> objects.
|
/// A custom collection wrapper over <see cref="IBuilderPolicy"/> objects.
|
||||||
|
@ -90,12 +89,12 @@ namespace Unity.Container
|
||||||
|
|
||||||
public void Set(Type type, string name, Type policyInterface, IBuilderPolicy policy)
|
public void Set(Type type, string name, Type policyInterface, IBuilderPolicy policy)
|
||||||
{
|
{
|
||||||
if(null == _policies)
|
if (null == _policies)
|
||||||
{
|
{
|
||||||
lock (_sync)
|
lock (_sync)
|
||||||
{
|
{
|
||||||
if (null == _policies)
|
if (null == _policies)
|
||||||
_policies = new ConcurrentDictionary<PolicyKey, IBuilderPolicy>(PolicyKeyEqualityComparer.Default);
|
_policies = new Dictionary<PolicyKey, IBuilderPolicy>(PolicyKeyEqualityComparer.Default);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_policies[new PolicyKey(type, name, policyInterface)] = policy;
|
_policies[new PolicyKey(type, name, policyInterface)] = policy;
|
|
@ -0,0 +1,126 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Unity.Registration;
|
||||||
|
using Unity.Utility;
|
||||||
|
|
||||||
|
namespace Unity.Storage
|
||||||
|
{
|
||||||
|
internal class ReverseHashSet : IEnumerable<IContainerRegistration>
|
||||||
|
{
|
||||||
|
#region Fields
|
||||||
|
|
||||||
|
private int[] _buckets;
|
||||||
|
private Slot[] _slots;
|
||||||
|
private int _count;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
public ReverseHashSet()
|
||||||
|
{
|
||||||
|
_count = 0;
|
||||||
|
_buckets = new int[37];
|
||||||
|
_slots = new Slot[37];
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region ReverseHashSet methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Add item to this HashSet. Later value replaces previosly set value
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="item"></param>
|
||||||
|
public void Add(IContainerRegistration item)
|
||||||
|
{
|
||||||
|
var hashCode = item?.GetHashCode() & 0x7FFFFFFF ?? 0 ;
|
||||||
|
var bucket = hashCode % _buckets.Length;
|
||||||
|
var collisionCount = 0;
|
||||||
|
|
||||||
|
for (int i = _buckets[bucket]; --i >= 0; i = _slots[i].Next)
|
||||||
|
{
|
||||||
|
if (_slots[i].HashCode == hashCode && Equals(_slots[i].Value, item))
|
||||||
|
{
|
||||||
|
_slots[i].Value = item;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
collisionCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_count == _slots.Length || 6 < collisionCount)
|
||||||
|
{
|
||||||
|
IncreaseCapacity();
|
||||||
|
bucket = hashCode % _buckets.Length;
|
||||||
|
}
|
||||||
|
|
||||||
|
_slots[_count].HashCode = hashCode;
|
||||||
|
_slots[_count].Value = item;
|
||||||
|
_slots[_count].Next = _buckets[bucket];
|
||||||
|
_count++;
|
||||||
|
_buckets[bucket] = _count;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Clear()
|
||||||
|
{
|
||||||
|
for (var i = 0; i < _count; i++)
|
||||||
|
{
|
||||||
|
_buckets[i] = 0;
|
||||||
|
_slots[_count].HashCode = 0;
|
||||||
|
_slots[_count].Value = null;
|
||||||
|
_slots[_count].Next = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
_count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerator<IContainerRegistration> GetEnumerator()
|
||||||
|
{
|
||||||
|
for(var i = 0; i < _count; i++)
|
||||||
|
yield return _slots[i].Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
IEnumerator IEnumerable.GetEnumerator()
|
||||||
|
{
|
||||||
|
return GetEnumerator();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Helper methods
|
||||||
|
|
||||||
|
|
||||||
|
private void IncreaseCapacity()
|
||||||
|
{
|
||||||
|
int newSize = HashHelpers.ExpandPrime(_count * 2);
|
||||||
|
|
||||||
|
var newSlots = new Slot[newSize];
|
||||||
|
Array.Copy(_slots, newSlots, _count);
|
||||||
|
|
||||||
|
var newBuckets = new int[newSize];
|
||||||
|
for (var i = 0; i < _count; i++)
|
||||||
|
{
|
||||||
|
var bucket = newSlots[i].HashCode % newSize;
|
||||||
|
newSlots[i].Next = newBuckets[bucket];
|
||||||
|
newBuckets[bucket] = i + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
_slots = newSlots;
|
||||||
|
_buckets = newBuckets;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
private struct Slot
|
||||||
|
{
|
||||||
|
internal int HashCode; // Lower 31 bits of hash code, 0 if unused
|
||||||
|
internal IContainerRegistration Value;
|
||||||
|
internal int Next; // Index of next entry, 0 if last
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -8,26 +8,24 @@ using System.Reflection;
|
||||||
using Unity.Builder.Strategy;
|
using Unity.Builder.Strategy;
|
||||||
using Unity.Strategy;
|
using Unity.Strategy;
|
||||||
|
|
||||||
namespace Unity.Container
|
namespace Unity.Storage
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a chain of responsibility for builder strategies partitioned by stages.
|
/// Represents a chain of responsibility for builder strategies partitioned by stages.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="TStageEnum">The stage enumeration to partition the strategies.</typeparam>
|
/// <typeparam name="TStageEnum">The stage enumeration to partition the strategies.</typeparam>
|
||||||
public class StagedStrategyChain<TStageEnum> : IStagedStrategyChain<IBuilderStrategy, TStageEnum>,
|
/// <typeparam name="TStrategyType"></typeparam>
|
||||||
IEnumerable<IBuilderStrategy>,
|
public class StagedStrategyChain<TStrategyType, TStageEnum> : IStagedStrategyChain<TStrategyType, TStageEnum>, IDisposable
|
||||||
IDisposable
|
|
||||||
{
|
{
|
||||||
#region Fields
|
#region Fields
|
||||||
|
|
||||||
private readonly object _lockObject = new object();
|
private readonly object _lockObject = new object();
|
||||||
private readonly StagedStrategyChain<TStageEnum> _innerChain;
|
private readonly StagedStrategyChain<TStrategyType, TStageEnum> _innerChain;
|
||||||
private readonly IList<IBuilderStrategy>[] _stages =
|
private readonly IList<TStrategyType>[] _stages = new IList<TStrategyType>[typeof(TStageEnum).GetTypeInfo()
|
||||||
new IList<IBuilderStrategy>[typeof(TStageEnum).GetTypeInfo()
|
.DeclaredFields
|
||||||
.DeclaredFields
|
.Count(f => f.IsPublic && f.IsStatic)];
|
||||||
.Count(f => f.IsPublic && f.IsStatic)];
|
|
||||||
|
|
||||||
private IStrategyChain _cache;
|
private IEnumerable<TStrategyType> _cache;
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
@ -35,7 +33,7 @@ namespace Unity.Container
|
||||||
#region Constructors
|
#region Constructors
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initialize a new instance of the <see cref="StagedStrategyChain{TStageEnum}"/> class.
|
/// Initialize a new instance of the <see cref="StagedStrategyChain{TStrategyType,TStageEnum}"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public StagedStrategyChain()
|
public StagedStrategyChain()
|
||||||
: this(null)
|
: this(null)
|
||||||
|
@ -43,10 +41,10 @@ namespace Unity.Container
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initialize a new instance of the <see cref="StagedStrategyChain{TStageEnum}"/> class with an inner strategy chain to use when building.
|
/// Initialize a new instance of the <see cref="StagedStrategyChain{TStrategyType, TStageEnum}"/> class with an inner strategy chain to use when building.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="innerChain">The inner strategy chain to use first when finding strategies in the build operation.</param>
|
/// <param name="innerChain">The inner strategy chain to use first when finding strategies in the build operation.</param>
|
||||||
public StagedStrategyChain(StagedStrategyChain<TStageEnum> innerChain)
|
public StagedStrategyChain(StagedStrategyChain<TStrategyType,TStageEnum> innerChain)
|
||||||
{
|
{
|
||||||
if (null != innerChain)
|
if (null != innerChain)
|
||||||
{
|
{
|
||||||
|
@ -56,7 +54,7 @@ namespace Unity.Container
|
||||||
|
|
||||||
for (var i = 0; i < _stages.Length; ++i)
|
for (var i = 0; i < _stages.Length; ++i)
|
||||||
{
|
{
|
||||||
_stages[i] = new List<IBuilderStrategy>();
|
_stages[i] = new List<TStrategyType>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,9 +71,9 @@ namespace Unity.Container
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private IEnumerable<IBuilderStrategy> Enumerate(int i)
|
private IEnumerable<TStrategyType> Enumerate(int i)
|
||||||
{
|
{
|
||||||
return (_innerChain?.Enumerate(i) ?? Enumerable.Empty<IBuilderStrategy>()).Concat(_stages[i]);
|
return (_innerChain?.Enumerate(i) ?? Enumerable.Empty<TStrategyType>()).Concat(_stages[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
@ -94,7 +92,7 @@ namespace Unity.Container
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="strategy">The strategy to add to the chain.</param>
|
/// <param name="strategy">The strategy to add to the chain.</param>
|
||||||
/// <param name="stage">The stage to add the strategy.</param>
|
/// <param name="stage">The stage to add the strategy.</param>
|
||||||
public void Add(IBuilderStrategy strategy, TStageEnum stage)
|
public void Add(TStrategyType strategy, TStageEnum stage)
|
||||||
{
|
{
|
||||||
lock (_lockObject)
|
lock (_lockObject)
|
||||||
{
|
{
|
||||||
|
@ -104,19 +102,6 @@ namespace Unity.Container
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Add a new strategy for the <paramref name="stage"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="TStrategy">The <see cref="System.Type"/> of strategy</typeparam>
|
|
||||||
/// <typeparam name="TStageEnum">The stage enum</typeparam>
|
|
||||||
/// <param name="chain">The chain this strategy is added to.</param>
|
|
||||||
/// <param name="stage">The stage to add the strategy to.</param>
|
|
||||||
public void AddNew<TStrategy>(TStageEnum stage)
|
|
||||||
where TStrategy : IBuilderStrategy, new()
|
|
||||||
{
|
|
||||||
Add(new TStrategy(), stage);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Clear the current strategy chain list.
|
/// Clear the current strategy chain list.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -136,34 +121,27 @@ namespace Unity.Container
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Makes a strategy chain based on this instance.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>A new <see cref="StrategyChain"/>.</returns>
|
|
||||||
public IStrategyChain MakeStrategyChain()
|
|
||||||
{
|
|
||||||
lock (_lockObject)
|
|
||||||
{
|
|
||||||
if (null == _cache)
|
|
||||||
{
|
|
||||||
_cache = new StrategyChain(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
return _cache;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
#region IEnumerable
|
#region IEnumerable
|
||||||
|
|
||||||
public IEnumerator<IBuilderStrategy> GetEnumerator()
|
public IEnumerator<TStrategyType> GetEnumerator()
|
||||||
{
|
{
|
||||||
return Enumerable.Range(0, _stages.Length)
|
var cache = _cache;
|
||||||
.SelectMany(Enumerate)
|
if (null != cache) return cache.GetEnumerator();
|
||||||
.GetEnumerator();
|
|
||||||
|
lock (_lockObject)
|
||||||
|
{
|
||||||
|
if (null == _cache)
|
||||||
|
{
|
||||||
|
_cache = Enumerable.Range(0, _stages.Length)
|
||||||
|
.SelectMany(Enumerate)
|
||||||
|
.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
return _cache.GetEnumerator();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator()
|
IEnumerator IEnumerable.GetEnumerator()
|
|
@ -0,0 +1,70 @@
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using Unity.Builder;
|
||||||
|
using Unity.Builder.Strategy;
|
||||||
|
using Unity.Injection;
|
||||||
|
using Unity.Lifetime;
|
||||||
|
using Unity.ObjectBuilder.Policies;
|
||||||
|
using Unity.Policy;
|
||||||
|
using Unity.Policy.Mapping;
|
||||||
|
using Unity.Registration;
|
||||||
|
using Unity.Strategy;
|
||||||
|
|
||||||
|
namespace Unity.Strategies
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a strategy for mapping build keys in the build up operation.
|
||||||
|
/// </summary>
|
||||||
|
public class BuildKeyMappingStrategy : BuilderStrategy, IRegisterTypeStrategy
|
||||||
|
{
|
||||||
|
#region BuilderStrategy
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Called during the chain of responsibility for a build operation. Looks for the <see cref="IBuildKeyMappingPolicy"/>
|
||||||
|
/// and if found maps the build key for the current operation.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context">The context for the operation.</param>
|
||||||
|
public override object PreBuildUp(IBuilderContext context)
|
||||||
|
{
|
||||||
|
IBuildKeyMappingPolicy policy = context.PersistentPolicies.Get<IBuildKeyMappingPolicy>(context.OriginalBuildKey.Type,
|
||||||
|
context.OriginalBuildKey.Name, out _)
|
||||||
|
?? (context.OriginalBuildKey.Type.GetTypeInfo().IsGenericType
|
||||||
|
? context.Policies.Get<IBuildKeyMappingPolicy>(context.OriginalBuildKey.Type.GetGenericTypeDefinition(),
|
||||||
|
context.OriginalBuildKey.Name, out _)
|
||||||
|
: null);
|
||||||
|
|
||||||
|
if (null == policy) return null;
|
||||||
|
|
||||||
|
context.BuildKey = policy.Map(context.BuildKey, context);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region IRegisterTypeStrategy
|
||||||
|
|
||||||
|
public void RegisterType(IContainerContext context, Type typeFrom, Type typeTo, string name,
|
||||||
|
LifetimeManager lifetimeManager, params InjectionMember[] injectionMembers)
|
||||||
|
{
|
||||||
|
// Validate imput
|
||||||
|
if (typeFrom == null || typeFrom == typeTo) return;
|
||||||
|
|
||||||
|
// Set mapping policy
|
||||||
|
var policy = typeFrom.GetTypeInfo().IsGenericTypeDefinition && typeTo.GetTypeInfo().IsGenericTypeDefinition
|
||||||
|
? new GenericTypeBuildKeyMappingPolicy(typeTo, name)
|
||||||
|
: (IBuildKeyMappingPolicy)new BuildKeyMappingPolicy(typeTo, name);
|
||||||
|
context.Policies.Set(typeFrom, name, typeof(IBuildKeyMappingPolicy), policy);
|
||||||
|
|
||||||
|
// Require Re-Resolve if no injectors specified
|
||||||
|
var members = null == injectionMembers ? new InjectionMember[0] : injectionMembers;
|
||||||
|
var overrides = members.Where(m => m is InjectionConstructor || m is InjectionMethod || m is InjectionProperty).Any();
|
||||||
|
if (lifetimeManager is IRequireBuildUpPolicy || overrides) return;
|
||||||
|
context.Policies.Set(typeFrom, name, typeof(IBuildPlanPolicy), new ResolveBuildUpPolicy());
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,84 @@
|
||||||
|
using System;
|
||||||
|
using System.Reflection;
|
||||||
|
using Unity.Builder;
|
||||||
|
using Unity.Builder.Strategy;
|
||||||
|
using Unity.Exceptions;
|
||||||
|
using Unity.ObjectBuilder.Policies;
|
||||||
|
using Unity.Policy;
|
||||||
|
|
||||||
|
namespace Unity.Strategies
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A <see cref="BuilderStrategy"/> that will look for a build plan
|
||||||
|
/// in the current context. If it exists, it invokes it, otherwise
|
||||||
|
/// it creates one and stores it for later, and invokes it.
|
||||||
|
/// </summary>
|
||||||
|
public class BuildPlanStrategy : BuilderStrategy
|
||||||
|
{
|
||||||
|
#region BuilderStrategy
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Called during the chain of responsibility for a build operation.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context">The context for the operation.</param>
|
||||||
|
public override object PreBuildUp(IBuilderContext context)
|
||||||
|
{
|
||||||
|
var plan = GetPolicy<IBuildPlanPolicy>(context.Policies, context.OriginalBuildKey, out var buildPlanLocation);
|
||||||
|
|
||||||
|
if (plan == null || plan is OverriddenBuildPlanMarkerPolicy)
|
||||||
|
{
|
||||||
|
var planCreator = GetPolicy<IBuildPlanCreatorPolicy>(context.Policies, context.BuildKey, out var creatorLocation);
|
||||||
|
if (planCreator != null)
|
||||||
|
{
|
||||||
|
plan = planCreator.CreatePlan(context, context.BuildKey);
|
||||||
|
(buildPlanLocation ?? creatorLocation).Set(context.OriginalBuildKey.Type, context.OriginalBuildKey.Name, typeof(IBuildPlanPolicy), plan);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
throw new ResolutionFailedException(context.OriginalBuildKey.Type, context.OriginalBuildKey.Name, null, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
plan?.BuildUp(context);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Implementation
|
||||||
|
|
||||||
|
|
||||||
|
public static TPolicyInterface GetPolicy<TPolicyInterface>(IPolicyList list, INamedType buildKey, out IPolicyList containingPolicyList)
|
||||||
|
{
|
||||||
|
return (TPolicyInterface)(list.Get(buildKey.Type, buildKey.Name, typeof(TPolicyInterface), out containingPolicyList) ??
|
||||||
|
GetExtended(list, typeof(TPolicyInterface), buildKey, buildKey.Type, out containingPolicyList) ??
|
||||||
|
list.Get(null, null, typeof(TPolicyInterface), out containingPolicyList)); // Nothing! Get Default
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IBuilderPolicy GetExtended(IPolicyList list, Type policyInterface, INamedType buildKey, Type buildType, out IPolicyList containingPolicyList)
|
||||||
|
{
|
||||||
|
containingPolicyList = null;
|
||||||
|
if (null == buildType) return null;
|
||||||
|
|
||||||
|
// Check if generic
|
||||||
|
if (buildType.GetTypeInfo().IsGenericType)
|
||||||
|
{
|
||||||
|
var newType = buildType.GetGenericTypeDefinition();
|
||||||
|
return list.Get(newType, buildKey.Name, policyInterface, out containingPolicyList) ??
|
||||||
|
list.Get(newType, string.Empty, policyInterface, out containingPolicyList);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if array
|
||||||
|
if (buildType.IsArray && buildType.GetArrayRank() == 1)
|
||||||
|
{
|
||||||
|
return list.Get(typeof(Array), buildKey.Name, policyInterface, out containingPolicyList) ??
|
||||||
|
list.Get(typeof(Array), string.Empty, policyInterface, out containingPolicyList);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check default for type
|
||||||
|
return list.Get(buildType, string.Empty, policyInterface, out containingPolicyList);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,104 @@
|
||||||
|
using System;
|
||||||
|
using System.Reflection;
|
||||||
|
using Unity.Builder;
|
||||||
|
using Unity.Builder.Strategy;
|
||||||
|
using Unity.Exceptions;
|
||||||
|
using Unity.Lifetime;
|
||||||
|
using Unity.Policy;
|
||||||
|
|
||||||
|
namespace Unity.Strategies
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// An <see cref="IBuilderStrategy"/> implementation that uses
|
||||||
|
/// a <see cref="ILifetimePolicy"/> to figure out if an object
|
||||||
|
/// has already been created and to update or remove that
|
||||||
|
/// object from some backing store.
|
||||||
|
/// </summary>
|
||||||
|
public class LifetimeStrategy : BuilderStrategy
|
||||||
|
{
|
||||||
|
#region Fields
|
||||||
|
|
||||||
|
private readonly object _genericLifetimeManagerLock = new object();
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region BuilderStrategy
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Called during the chain of responsibility for a build operation. The
|
||||||
|
/// PreBuildUp method is called when the chain is being executed in the
|
||||||
|
/// forward direction.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context">Context of the build operation.</param>
|
||||||
|
public override object PreBuildUp(IBuilderContext context)
|
||||||
|
{
|
||||||
|
if (null != context.Existing) return null;
|
||||||
|
|
||||||
|
var lifetimePolicy = GetLifetimePolicy(context, out _);
|
||||||
|
if (null == lifetimePolicy) return null;
|
||||||
|
|
||||||
|
if (lifetimePolicy is IRequiresRecovery recovery)
|
||||||
|
{
|
||||||
|
context.RecoveryStack.Add(recovery);
|
||||||
|
}
|
||||||
|
|
||||||
|
var existing = lifetimePolicy.GetValue(context.Lifetime);
|
||||||
|
if (existing != null)
|
||||||
|
{
|
||||||
|
context.Existing = existing;
|
||||||
|
context.BuildComplete = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return lifetimePolicy;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Called during the chain of responsibility for a build operation. The
|
||||||
|
/// PostBuildUp method is called when the chain has finished the PreBuildUp
|
||||||
|
/// phase and executes in reverse order from the PreBuildUp calls.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context">Context of the build operation.</param>
|
||||||
|
/// <param name="lifetimePolicy"></param>
|
||||||
|
public override void PostBuildUp(IBuilderContext context, object lifetimePolicy = null)
|
||||||
|
{
|
||||||
|
(lifetimePolicy as ILifetimePolicy)?.SetValue(context.Existing, context.Lifetime);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Implementation
|
||||||
|
|
||||||
|
private ILifetimePolicy GetLifetimePolicy(IBuilderContext context, out IPolicyList source)
|
||||||
|
{
|
||||||
|
var policy = context.Policies.Get(context.OriginalBuildKey.Type, context.OriginalBuildKey.Name, typeof(ILifetimePolicy), out source);
|
||||||
|
if (policy == null && context.OriginalBuildKey.Type.GetTypeInfo().IsGenericType)
|
||||||
|
{
|
||||||
|
policy = context.Policies.Get(context.BuildKey.Type.GetGenericTypeDefinition(), context.BuildKey.Name, typeof(ILifetimePolicy), out source);
|
||||||
|
if (!(policy is ILifetimeFactoryPolicy factoryPolicy)) return null;
|
||||||
|
|
||||||
|
lock (_genericLifetimeManagerLock)
|
||||||
|
{
|
||||||
|
// check whether the policy for closed-generic has been added since first checked
|
||||||
|
var newLifetime = (ILifetimePolicy)source.Get(context.OriginalBuildKey.Type, context.OriginalBuildKey.Name, typeof(ILifetimePolicy), out _);
|
||||||
|
if (null == newLifetime)
|
||||||
|
{
|
||||||
|
newLifetime = factoryPolicy.CreateLifetimePolicy();
|
||||||
|
source.Set(context.OriginalBuildKey.Type, context.OriginalBuildKey.Name, typeof(ILifetimePolicy), newLifetime);
|
||||||
|
if (newLifetime is IDisposable)
|
||||||
|
{
|
||||||
|
context.Lifetime.Add(newLifetime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return newLifetime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (ILifetimePolicy)policy;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<Import Project="..\package.props" />
|
<Import Project="..\package.props" />
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,176 @@
|
||||||
|
using System;
|
||||||
|
using Unity.Builder;
|
||||||
|
using Unity.Builder.Strategy;
|
||||||
|
using Unity.Events;
|
||||||
|
using Unity.Extension;
|
||||||
|
using Unity.Lifetime;
|
||||||
|
using Unity.Policy;
|
||||||
|
using Unity.Registration;
|
||||||
|
using Unity.Storage;
|
||||||
|
using Unity.Strategy;
|
||||||
|
|
||||||
|
namespace Unity
|
||||||
|
{
|
||||||
|
public partial class UnityContainer
|
||||||
|
{
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Abstraction layer between container and extensions
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Implemented as a nested class to gain access to
|
||||||
|
/// container that would otherwise be inaccessible.
|
||||||
|
/// </remarks>
|
||||||
|
private class ContainerContext : ExtensionContext,
|
||||||
|
IContainerContext,
|
||||||
|
IPolicyList
|
||||||
|
{
|
||||||
|
#region Fields
|
||||||
|
|
||||||
|
private readonly UnityContainer _container;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
public ContainerContext(UnityContainer container)
|
||||||
|
{
|
||||||
|
_container = container ?? throw new ArgumentNullException(nameof(container));
|
||||||
|
Policies = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region ExtensionContext
|
||||||
|
|
||||||
|
public override IUnityContainer Container => _container;
|
||||||
|
|
||||||
|
public override IStagedStrategyChain<IBuilderStrategy, UnityBuildStage> Strategies => _container._strategies;
|
||||||
|
|
||||||
|
public override IStagedStrategyChain<IBuilderStrategy, BuilderStage> BuildPlanStrategies => _container._buildPlanStrategies;
|
||||||
|
|
||||||
|
public override IPolicyList Policies { get; }
|
||||||
|
|
||||||
|
public override ILifetimeContainer Lifetime => _container._lifetimeContainer;
|
||||||
|
|
||||||
|
public override event EventHandler<RegisterEventArgs> Registering
|
||||||
|
{
|
||||||
|
add => _container.Registering += value;
|
||||||
|
remove => _container.Registering -= value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override event EventHandler<RegisterInstanceEventArgs> RegisteringInstance
|
||||||
|
{
|
||||||
|
add => _container.RegisteringInstance += value;
|
||||||
|
remove => _container.RegisteringInstance -= value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override event EventHandler<ChildContainerCreatedEventArgs> ChildContainerCreated
|
||||||
|
{
|
||||||
|
add => _container.ChildContainerCreated += value;
|
||||||
|
remove => _container.ChildContainerCreated -= value;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region IContainerContext
|
||||||
|
|
||||||
|
public IContainerContext RegistrationContext(InternalRegistration registration)
|
||||||
|
{
|
||||||
|
return new RegistrationContext(_container, registration);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region IPolicyList
|
||||||
|
|
||||||
|
public virtual void ClearAll()
|
||||||
|
{
|
||||||
|
_container._registrations =
|
||||||
|
new HashRegistry<Type, IRegistry<string, IPolicySet>>(ContainerInitialCapacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual IBuilderPolicy Get(Type type, string name, Type policyInterface, out IPolicyList list)
|
||||||
|
{
|
||||||
|
for (var registry = _container; null != registry; registry = registry._parent)
|
||||||
|
{
|
||||||
|
IPolicySet data;
|
||||||
|
if (null == (data = registry[type, name])) continue;
|
||||||
|
|
||||||
|
list = registry._context;
|
||||||
|
return data.Get(policyInterface);
|
||||||
|
}
|
||||||
|
|
||||||
|
list = null;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void Set(Type type, string name, Type policyInterface, IBuilderPolicy policy)
|
||||||
|
{
|
||||||
|
for (var registry = _container; null != registry; registry = registry._parent)
|
||||||
|
{
|
||||||
|
IPolicySet data;
|
||||||
|
if (null == (data = registry[type, name])) continue;
|
||||||
|
|
||||||
|
data.Set(policyInterface, policy);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_container[type, name, policyInterface] = policy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void Clear(Type type, string name, Type policyInterface)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
|
||||||
|
private class RegistrationContext : ContainerContext
|
||||||
|
{
|
||||||
|
private readonly InternalRegistration _registration;
|
||||||
|
|
||||||
|
internal RegistrationContext(UnityContainer container, InternalRegistration registration)
|
||||||
|
: base(container)
|
||||||
|
{
|
||||||
|
_registration = registration;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#region IPolicyList
|
||||||
|
|
||||||
|
public override IBuilderPolicy Get(Type type, string name, Type policyInterface, out IPolicyList list)
|
||||||
|
{
|
||||||
|
if (_registration.Type != type || _registration.Name != name)
|
||||||
|
return base.Get(type, name, policyInterface, out list);
|
||||||
|
|
||||||
|
list = this;
|
||||||
|
return _registration.Get(policyInterface);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public override void Set(Type type, string name, Type policyInterface, IBuilderPolicy policy)
|
||||||
|
{
|
||||||
|
if (_registration.Type != type || _registration.Name != name)
|
||||||
|
base.Set(type, name, policyInterface, policy);
|
||||||
|
|
||||||
|
_registration.Set(policyInterface, policy);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Clear(Type type, string name, Type policyInterface)
|
||||||
|
{
|
||||||
|
if (_registration.Type != type || _registration.Name != name)
|
||||||
|
base.Clear(type, name, policyInterface);
|
||||||
|
|
||||||
|
_registration.Clear(policyInterface);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,16 +7,20 @@ using Unity.Builder;
|
||||||
using Unity.Builder.Strategy;
|
using Unity.Builder.Strategy;
|
||||||
using Unity.Container;
|
using Unity.Container;
|
||||||
using Unity.Container.Lifetime;
|
using Unity.Container.Lifetime;
|
||||||
using Unity.Container.Registration;
|
|
||||||
using Unity.Events;
|
using Unity.Events;
|
||||||
using Unity.Extension;
|
using Unity.Extension;
|
||||||
using Unity.Lifetime;
|
using Unity.Lifetime;
|
||||||
using Unity.ObjectBuilder.BuildPlan;
|
|
||||||
using Unity.ObjectBuilder.BuildPlan.DynamicMethod;
|
using Unity.ObjectBuilder.BuildPlan.DynamicMethod;
|
||||||
|
using Unity.ObjectBuilder.BuildPlan.DynamicMethod.Creation;
|
||||||
|
using Unity.ObjectBuilder.BuildPlan.DynamicMethod.Method;
|
||||||
|
using Unity.ObjectBuilder.BuildPlan.DynamicMethod.Property;
|
||||||
using Unity.ObjectBuilder.BuildPlan.Selection;
|
using Unity.ObjectBuilder.BuildPlan.Selection;
|
||||||
using Unity.ObjectBuilder.Policies;
|
using Unity.ObjectBuilder.Policies;
|
||||||
using Unity.ObjectBuilder.Strategies;
|
|
||||||
using Unity.Policy;
|
using Unity.Policy;
|
||||||
|
using Unity.Policy.BuildPlanCreator;
|
||||||
|
using Unity.Registration;
|
||||||
|
using Unity.Storage;
|
||||||
|
using Unity.Strategies;
|
||||||
using Unity.Strategy;
|
using Unity.Strategy;
|
||||||
|
|
||||||
namespace Unity
|
namespace Unity
|
||||||
|
@ -25,21 +29,27 @@ namespace Unity
|
||||||
{
|
{
|
||||||
#region Fields
|
#region Fields
|
||||||
|
|
||||||
private LifetimeContainer _lifetimeContainer;
|
// Container specific
|
||||||
private readonly PolicyList _policies;
|
|
||||||
private readonly UnityContainer _parent;
|
private readonly UnityContainer _parent;
|
||||||
private readonly NamedTypesRegistry _registeredNames;
|
private readonly LifetimeContainer _lifetimeContainer;
|
||||||
private readonly List<UnityContainerExtension> _extensions;
|
private readonly List<UnityContainerExtension> _extensions;
|
||||||
private readonly StagedStrategyChain<UnityBuildStage> _strategies;
|
|
||||||
private readonly StagedStrategyChain<BuilderStage> _buildPlanStrategies;
|
// Policies
|
||||||
|
private readonly IPolicySet _defaultPolicies;
|
||||||
private readonly ContainerContext _context;
|
private readonly ContainerContext _context;
|
||||||
|
|
||||||
|
// Strategies
|
||||||
|
private readonly StagedStrategyChain<IBuilderStrategy, UnityBuildStage> _strategies;
|
||||||
|
private readonly StagedStrategyChain<IBuilderStrategy, BuilderStage> _buildPlanStrategies;
|
||||||
|
|
||||||
|
// Events
|
||||||
private event EventHandler<RegisterEventArgs> Registering;
|
private event EventHandler<RegisterEventArgs> Registering;
|
||||||
private event EventHandler<RegisterInstanceEventArgs> RegisteringInstance;
|
private event EventHandler<RegisterInstanceEventArgs> RegisteringInstance;
|
||||||
private event EventHandler<ChildContainerCreatedEventArgs> ChildContainerCreated;
|
private event EventHandler<ChildContainerCreatedEventArgs> ChildContainerCreated;
|
||||||
|
|
||||||
// Caches
|
// Caches
|
||||||
private IRegisterTypeStrategy[] _registerTypeStrategies;
|
private IRegisterTypeStrategy[] _registerTypeStrategies;
|
||||||
|
private IStrategyChain _strategyChain;
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
@ -53,82 +63,74 @@ namespace Unity
|
||||||
/// will apply its own settings first, and then check the parent for additional ones.</param>
|
/// will apply its own settings first, and then check the parent for additional ones.</param>
|
||||||
private UnityContainer(UnityContainer parent)
|
private UnityContainer(UnityContainer parent)
|
||||||
{
|
{
|
||||||
_extensions = new List<UnityContainerExtension>();
|
// Parent
|
||||||
|
|
||||||
_parent = parent;
|
_parent = parent;
|
||||||
_parent?._lifetimeContainer.Add(this);
|
_parent?._lifetimeContainer.Add(this);
|
||||||
_context = new ContainerContext(this);
|
|
||||||
_strategies = new StagedStrategyChain<UnityBuildStage>(_parent?._strategies);
|
|
||||||
_buildPlanStrategies = new StagedStrategyChain<BuilderStage>(_parent?._buildPlanStrategies);
|
|
||||||
_registeredNames = new NamedTypesRegistry(_parent?._registeredNames);
|
|
||||||
_lifetimeContainer = new LifetimeContainer { _strategies, _buildPlanStrategies };
|
|
||||||
_policies = new PolicyList(_parent?._policies);
|
|
||||||
_policies.Set<IRegisteredNamesPolicy>(new RegisteredNamesPolicy(_registeredNames), null);
|
|
||||||
|
|
||||||
if (null == _parent) InitializeStrategies();
|
// Strategies
|
||||||
|
_strategies = new StagedStrategyChain<IBuilderStrategy, UnityBuildStage>(_parent?._strategies);
|
||||||
|
_buildPlanStrategies = new StagedStrategyChain<IBuilderStrategy, BuilderStage>(_parent?._buildPlanStrategies);
|
||||||
|
|
||||||
|
// Lifetime
|
||||||
|
_lifetimeContainer = new LifetimeContainer(this) { _strategies, _buildPlanStrategies };
|
||||||
|
|
||||||
|
// Default Policies
|
||||||
|
if (null == _parent) InitializeRootContainer();
|
||||||
|
_defaultPolicies = parent?._defaultPolicies ?? GetDefaultPolicies();
|
||||||
|
this[null, null] = _defaultPolicies;
|
||||||
|
|
||||||
|
// Context and policies
|
||||||
|
_extensions = new List<UnityContainerExtension>();
|
||||||
|
_context = new ContainerContext(this);
|
||||||
|
|
||||||
// Caches
|
// Caches
|
||||||
OnStrategiesChanged(this, null);
|
OnStrategiesChanged(this, null);
|
||||||
_strategies.Invalidated += OnStrategiesChanged;
|
_strategies.Invalidated += OnStrategiesChanged;
|
||||||
|
|
||||||
RegisterInstance(typeof(IUnityContainer), null, this, new ContainerLifetimeManager());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
#region Default Strategies
|
#region Defaults
|
||||||
|
|
||||||
protected void InitializeStrategies()
|
protected void InitializeRootContainer()
|
||||||
{
|
{
|
||||||
// Main strategy chain
|
// Main strategy chain
|
||||||
_strategies.AddNew<BuildKeyMappingStrategy>(UnityBuildStage.TypeMapping);
|
_strategies.Add(new BuildKeyMappingStrategy(), UnityBuildStage.TypeMapping);
|
||||||
_strategies.AddNew<LifetimeStrategy>(UnityBuildStage.Lifetime);
|
_strategies.Add(new LifetimeStrategy(), UnityBuildStage.Lifetime);
|
||||||
|
_strategies.Add(new BuildPlanStrategy(), UnityBuildStage.Creation);
|
||||||
_strategies.AddNew<ArrayResolutionStrategy>(UnityBuildStage.Creation);
|
|
||||||
_strategies.AddNew<BuildPlanStrategy>(UnityBuildStage.Creation);
|
|
||||||
|
|
||||||
// Build plan strategy chain
|
// Build plan strategy chain
|
||||||
_buildPlanStrategies.AddNew<DynamicMethodConstructorStrategy>(BuilderStage.Creation);
|
_buildPlanStrategies.Add(new DynamicMethodConstructorStrategy(), BuilderStage.Creation);
|
||||||
_buildPlanStrategies.AddNew<DynamicMethodPropertySetterStrategy>(BuilderStage.Initialization);
|
_buildPlanStrategies.Add(new DynamicMethodPropertySetterStrategy(), BuilderStage.Initialization);
|
||||||
_buildPlanStrategies.AddNew<DynamicMethodCallStrategy>(BuilderStage.Initialization);
|
_buildPlanStrategies.Add(new DynamicMethodCallStrategy(), BuilderStage.Initialization);
|
||||||
|
|
||||||
// Policies - mostly used by the build plan strategies
|
// Special Cases
|
||||||
_policies.SetDefault<IConstructorSelectorPolicy>(new DefaultUnityConstructorSelectorPolicy());
|
this[null, null] = _defaultPolicies;
|
||||||
_policies.SetDefault<IPropertySelectorPolicy>(new DefaultUnityPropertySelectorPolicy());
|
this[typeof(Func<>), string.Empty, typeof(ILifetimePolicy)] = new PerResolveLifetimeManager();
|
||||||
_policies.SetDefault<IMethodSelectorPolicy>(new DefaultUnityMethodSelectorPolicy());
|
this[typeof(Func<>), string.Empty, typeof(IBuildPlanPolicy)] = new DeferredResolveCreatorPolicy();
|
||||||
_policies.SetDefault<IBuildPlanCreatorPolicy>(new DynamicMethodBuildPlanCreatorPolicy(_buildPlanStrategies));
|
this[typeof(Lazy<>), string.Empty, typeof(IBuildPlanCreatorPolicy)] = new GenericLazyBuildPlanCreatorPolicy();
|
||||||
_policies.Set<IBuildPlanPolicy>(new DeferredResolveBuildPlanPolicy(), typeof(Func<>));
|
this[typeof(Array), string.Empty, typeof(IBuildPlanCreatorPolicy)] =
|
||||||
_policies.Set<ILifetimePolicy>(new PerResolveLifetimeManager(), typeof(Func<>));
|
new DelegateBasedBuildPlanCreatorPolicy(typeof(UnityContainer).GetTypeInfo().GetDeclaredMethod(nameof(ResolveArray)),
|
||||||
_policies.Set<IBuildPlanCreatorPolicy>(new LazyDynamicMethodBuildPlanCreatorPolicy(), typeof(Lazy<>));
|
context => context.OriginalBuildKey.Type.GetElementType());
|
||||||
_policies.Set<IBuildPlanCreatorPolicy>(new EnumerableDynamicMethodBuildPlanCreatorPolicy(), typeof(IEnumerable<>));
|
this[typeof(IEnumerable<>), string.Empty, typeof(IBuildPlanCreatorPolicy)] =
|
||||||
|
new DelegateBasedBuildPlanCreatorPolicy(typeof(UnityContainer).GetTypeInfo().GetDeclaredMethod(nameof(ResolveEnumerable)),
|
||||||
|
context => context.BuildKey.Type.GetTypeInfo().GenericTypeArguments.First());
|
||||||
|
// Register this instance
|
||||||
|
RegisterInstance(typeof(IUnityContainer), null, this, new ContainerLifetimeManager());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void SetLifetimeManager(Type lifetimeType, string name, LifetimeManager lifetimeManager)
|
private IPolicySet GetDefaultPolicies()
|
||||||
{
|
{
|
||||||
if (lifetimeManager.InUse)
|
var defaults = new InternalRegistration(null, null);
|
||||||
{
|
|
||||||
throw new InvalidOperationException(Constants.LifetimeManagerInUse);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lifetimeType.GetTypeInfo().IsGenericTypeDefinition)
|
defaults.Set(typeof(IConstructorSelectorPolicy), new DefaultUnityConstructorSelectorPolicy());
|
||||||
{
|
defaults.Set(typeof(IPropertySelectorPolicy), new DefaultUnityPropertySelectorPolicy());
|
||||||
LifetimeManagerFactory factory =
|
defaults.Set(typeof(IMethodSelectorPolicy), new DefaultUnityMethodSelectorPolicy());
|
||||||
new LifetimeManagerFactory(new ContainerContext(this), lifetimeManager.GetType());
|
defaults.Set(typeof(IBuildPlanCreatorPolicy), new DynamicMethodBuildPlanCreatorPolicy(_buildPlanStrategies));
|
||||||
_policies.Set<ILifetimeFactoryPolicy>(factory,
|
|
||||||
new NamedTypeBuildKey(lifetimeType, name));
|
return defaults;
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
lifetimeManager.InUse = true;
|
|
||||||
_policies.Set<ILifetimePolicy>(lifetimeManager,
|
|
||||||
new NamedTypeBuildKey(lifetimeType, name));
|
|
||||||
if (lifetimeManager is IDisposable)
|
|
||||||
{
|
|
||||||
_lifetimeContainer.Add(lifetimeManager);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
@ -136,28 +138,12 @@ namespace Unity
|
||||||
|
|
||||||
#region Implementation
|
#region Implementation
|
||||||
|
|
||||||
private UnityContainer GetRootContainer()
|
|
||||||
{
|
|
||||||
UnityContainer container;
|
|
||||||
|
|
||||||
for (container = this; container._parent != null; container = container._parent) ;
|
|
||||||
|
|
||||||
return container;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnStrategiesChanged(object sender, EventArgs e)
|
private void OnStrategiesChanged(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
_registerTypeStrategies = _strategies.OfType<IRegisterTypeStrategy>().ToArray();
|
_registerTypeStrategies = _strategies.OfType<IRegisterTypeStrategy>().ToArray();
|
||||||
|
_strategyChain = new StrategyChain(_strategies);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Verifies that an argument instance is assignable from the provided type (meaning
|
|
||||||
/// interfaces are implemented, or classes exist in the base class hierarchy, or instance can be
|
|
||||||
/// assigned through a runtime wrapper, as is the case for COM Objects).
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="assignmentTargetType">The argument type that will be assigned to.</param>
|
|
||||||
/// <param name="assignmentInstance">The instance that will be assigned.</param>
|
|
||||||
/// <param name="argumentName">Argument name.</param>
|
|
||||||
private static void InstanceIsAssignable(Type assignmentTargetType, object assignmentInstance, string argumentName)
|
private static void InstanceIsAssignable(Type assignmentTargetType, object assignmentInstance, string argumentName)
|
||||||
{
|
{
|
||||||
if (!(assignmentTargetType ?? throw new ArgumentNullException(nameof(assignmentTargetType)))
|
if (!(assignmentTargetType ?? throw new ArgumentNullException(nameof(assignmentTargetType)))
|
||||||
|
@ -187,90 +173,18 @@ namespace Unity
|
||||||
return assignmentInstanceType;
|
return assignmentInstanceType;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
private static IPolicySet CreateRegistration(Type type, string name)
|
||||||
|
|
||||||
|
|
||||||
#region Nested Types
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Implementation of the ExtensionContext that is actually used
|
|
||||||
/// by the UnityContainer implementation.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// This is a nested class so that it can access state in the
|
|
||||||
/// container that would otherwise be inaccessible.
|
|
||||||
/// </remarks>
|
|
||||||
private class ContainerContext : ExtensionContext, IContainerContext
|
|
||||||
{
|
{
|
||||||
private readonly UnityContainer _container;
|
return new InternalRegistration(type, name);
|
||||||
|
|
||||||
public ContainerContext(UnityContainer container)
|
|
||||||
{
|
|
||||||
_container = container ?? throw new ArgumentNullException(nameof(container));
|
|
||||||
}
|
|
||||||
|
|
||||||
public override IUnityContainer Container => _container;
|
|
||||||
|
|
||||||
public override IStagedStrategyChain<IBuilderStrategy, UnityBuildStage> Strategies => _container._strategies;
|
|
||||||
|
|
||||||
public override IStagedStrategyChain<IBuilderStrategy, BuilderStage> BuildPlanStrategies => _container._buildPlanStrategies;
|
|
||||||
|
|
||||||
public override IPolicyList Policies => _container._policies;
|
|
||||||
|
|
||||||
public override ILifetimeContainer Lifetime => _container._lifetimeContainer;
|
|
||||||
|
|
||||||
public override event EventHandler<RegisterEventArgs> Registering
|
|
||||||
{
|
|
||||||
add => _container.Registering += value;
|
|
||||||
remove => _container.Registering -= value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// This event is raised when the <see cref="Unity.UnityContainer.RegisterInstance(Type,string,object,LifetimeManager)"/> method,
|
|
||||||
/// or one of its overloads, is called.
|
|
||||||
/// </summary>
|
|
||||||
public override event EventHandler<RegisterInstanceEventArgs> RegisteringInstance
|
|
||||||
{
|
|
||||||
add => _container.RegisteringInstance += value;
|
|
||||||
remove => _container.RegisteringInstance -= value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override event EventHandler<ChildContainerCreatedEventArgs> ChildContainerCreated
|
|
||||||
{
|
|
||||||
add => _container.ChildContainerCreated += value;
|
|
||||||
remove => _container.ChildContainerCreated -= value;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private UnityContainer GetRootContainer()
|
||||||
// Works like the ExternallyControlledLifetimeManager, but uses regular instead of weak references
|
|
||||||
private class ContainerLifetimeManager : LifetimeManager, IBuildPlanPolicy
|
|
||||||
{
|
{
|
||||||
private object _value;
|
UnityContainer container;
|
||||||
|
|
||||||
public override object GetValue(ILifetimeContainer container = null)
|
for (container = this; container._parent != null; container = container._parent) ;
|
||||||
{
|
|
||||||
return _value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void SetValue(object newValue, ILifetimeContainer container = null)
|
return container;
|
||||||
{
|
|
||||||
_value = newValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void RemoveValue(ILifetimeContainer container = null)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public void BuildUp(IBuilderContext context)
|
|
||||||
{
|
|
||||||
context.Existing = _value;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override LifetimeManager OnCreateLifetimeManager()
|
|
||||||
{
|
|
||||||
return new ContainerLifetimeManager();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
|
@ -0,0 +1,163 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using Unity.Events;
|
||||||
|
using Unity.Extension;
|
||||||
|
using Unity.Policy;
|
||||||
|
using Unity.Storage;
|
||||||
|
|
||||||
|
namespace Unity
|
||||||
|
{
|
||||||
|
public partial class UnityContainer : IUnityContainer
|
||||||
|
{
|
||||||
|
#region Public Constructor
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create a default <see cref="UnityContainer"/>.
|
||||||
|
/// </summary>
|
||||||
|
public UnityContainer()
|
||||||
|
: this(null)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Extension Management
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Add an extension object to the container.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="extension"><see cref="UnityContainerExtension"/> to add.</param>
|
||||||
|
/// <returns>The <see cref="UnityContainer"/> object that this method was called on (this in C#, Me in Visual Basic).</returns>
|
||||||
|
public IUnityContainer AddExtension(UnityContainerExtension extension)
|
||||||
|
{
|
||||||
|
_extensions.Add(extension ?? throw new ArgumentNullException(nameof(extension)));
|
||||||
|
extension.InitializeExtension(_context);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// GetOrDefault access to a configuration interface exposed by an extension.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>Extensions can expose configuration interfaces as well as adding
|
||||||
|
/// strategies and policies to the container. This method walks the list of
|
||||||
|
/// added extensions and returns the first one that implements the requested type.
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="configurationInterface"><see cref="Type"/> of configuration interface required.</param>
|
||||||
|
/// <returns>The requested extension's configuration interface, or null if not found.</returns>
|
||||||
|
public object Configure(Type configurationInterface)
|
||||||
|
{
|
||||||
|
return _extensions.FirstOrDefault(ex => configurationInterface.GetTypeInfo()
|
||||||
|
.IsAssignableFrom(ex.GetType().GetTypeInfo()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Remove all installed extensions typeFrom this container.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// <para>
|
||||||
|
/// This method removes all extensions typeFrom the container, including the default ones
|
||||||
|
/// that implement the out-of-the-box behavior. After this method, if you want to use
|
||||||
|
/// the container again you will need to either read the default extensions or replace
|
||||||
|
/// them with your own.
|
||||||
|
/// </para>
|
||||||
|
/// <para>
|
||||||
|
/// The registered instances and singletons that have already been set up in this container
|
||||||
|
/// do not get removed.
|
||||||
|
/// </para>
|
||||||
|
/// </remarks>
|
||||||
|
/// <returns>The <see cref="UnityContainer"/> object that this method was called on (this in C#, Me in Visual Basic).</returns>
|
||||||
|
public IUnityContainer RemoveAllExtensions()
|
||||||
|
{
|
||||||
|
var toRemove = new List<UnityContainerExtension>(_extensions);
|
||||||
|
toRemove.Reverse();
|
||||||
|
foreach (UnityContainerExtension extension in toRemove)
|
||||||
|
{
|
||||||
|
extension.Remove();
|
||||||
|
(extension as IDisposable)?.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
_extensions.Clear();
|
||||||
|
|
||||||
|
// Reset our policies, strategies, and registered names to reset to "zero"
|
||||||
|
_strategies.Clear();
|
||||||
|
((IPolicyList)_context).ClearAll();
|
||||||
|
|
||||||
|
if (null == _parent)
|
||||||
|
InitializeRootContainer();
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Child container management
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create a child container.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// A child container shares the parent's configuration, but can be configured with different
|
||||||
|
/// settings or lifetime.</remarks>
|
||||||
|
/// <returns>The new child container.</returns>
|
||||||
|
public IUnityContainer CreateChildContainer()
|
||||||
|
{
|
||||||
|
var child = new UnityContainer(this);
|
||||||
|
ChildContainerCreated?.Invoke(this, new ChildContainerCreatedEventArgs(child._context));
|
||||||
|
return child;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The parent of this container.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The parent container, or null if this container doesn'type have one.</value>
|
||||||
|
public IUnityContainer Parent => _parent;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region IDisposable Implementation
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Dispose this container instance.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Disposing the container also disposes any child containers,
|
||||||
|
/// and disposes any instances whose lifetimes are managed
|
||||||
|
/// by the container.
|
||||||
|
/// </remarks>
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Dispose(true);
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Dispose this container instance.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// This class doesn'type have a finalizer, so <paramref name="disposing"/> will always be true.</remarks>
|
||||||
|
/// <param name="disposing">True if being called typeFrom the IDisposable.Dispose
|
||||||
|
/// method, false if being called typeFrom a finalizer.</param>
|
||||||
|
protected virtual void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (disposing)
|
||||||
|
{
|
||||||
|
_parent?._lifetimeContainer?.Remove(this);
|
||||||
|
_lifetimeContainer?.Dispose();
|
||||||
|
|
||||||
|
foreach (IDisposable disposable in _extensions.OfType<IDisposable>().ToArray())
|
||||||
|
disposable.Dispose();
|
||||||
|
|
||||||
|
_extensions.Clear();
|
||||||
|
_registrations = new HashRegistry<Type, IRegistry<string, IPolicySet>>(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,492 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using Unity.Builder;
|
||||||
|
using Unity.Events;
|
||||||
|
using Unity.Lifetime;
|
||||||
|
using Unity.Policy;
|
||||||
|
using Unity.Registration;
|
||||||
|
using Unity.Storage;
|
||||||
|
|
||||||
|
namespace Unity
|
||||||
|
{
|
||||||
|
public partial class UnityContainer
|
||||||
|
{
|
||||||
|
#region Constants
|
||||||
|
|
||||||
|
private const int ContainerInitialCapacity = 37;
|
||||||
|
private const int ListToHashCutoverPoint = 8;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Fields
|
||||||
|
|
||||||
|
private readonly object _syncRoot = new object();
|
||||||
|
private HashRegistry<Type, IRegistry<string, IPolicySet>> _registrations =
|
||||||
|
new HashRegistry<Type, IRegistry<string, IPolicySet>>(ContainerInitialCapacity);
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Type Registration
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// RegisterType a type mapping with the container, where the created instances will use
|
||||||
|
/// the given <see cref="LifetimeManager"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="typeFrom"><see cref="Type"/> that will be requested.</param>
|
||||||
|
/// <param name="typeTo"><see cref="Type"/> that will actually be returned.</param>
|
||||||
|
/// <param name="name">Name to use for registration, null if a default registration.</param>
|
||||||
|
/// <param name="lifetimeManager">The <see cref="LifetimeManager"/> that controls the lifetime
|
||||||
|
/// of the returned instance.</param>
|
||||||
|
/// <param name="injectionMembers">Injection configuration objects.</param>
|
||||||
|
/// <returns>The <see cref="UnityContainer"/> object that this method was called on (this in C#, Me in Visual Basic).</returns>
|
||||||
|
public IUnityContainer RegisterType(Type typeFrom, Type typeTo, string name, LifetimeManager lifetimeManager, InjectionMember[] injectionMembers)
|
||||||
|
{
|
||||||
|
// Validate imput
|
||||||
|
if (string.Empty == name) name = null;
|
||||||
|
if (null == typeTo) throw new ArgumentNullException(nameof(typeTo));
|
||||||
|
if (null == lifetimeManager) lifetimeManager = TransientLifetimeManager.Instance;
|
||||||
|
if (typeFrom != null && !typeFrom.GetTypeInfo().IsGenericType && !typeTo.GetTypeInfo().IsGenericType &&
|
||||||
|
!typeFrom.GetTypeInfo().IsAssignableFrom(typeTo.GetTypeInfo()))
|
||||||
|
{
|
||||||
|
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture,
|
||||||
|
Constants.TypesAreNotAssignable, typeFrom, typeTo), nameof(typeFrom));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create registration and add to appropriate storage
|
||||||
|
var container = (lifetimeManager is ISingletonLifetimePolicy) ? GetRootContainer() : this;
|
||||||
|
var registration = new TypeRegistration(typeFrom, typeTo, name, lifetimeManager);
|
||||||
|
|
||||||
|
// Add or replace existing
|
||||||
|
if (container.SetOrUpdate(registration) is IDisposable disposable)
|
||||||
|
{
|
||||||
|
container._lifetimeContainer.Remove(disposable);
|
||||||
|
disposable.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
// If Disposable add to container's lifetime
|
||||||
|
if (registration.LifetimeManager is IDisposable manager)
|
||||||
|
container._lifetimeContainer.Add(manager);
|
||||||
|
|
||||||
|
// Add Injection Members
|
||||||
|
var context = container._context.RegistrationContext(registration);
|
||||||
|
if (null != injectionMembers && injectionMembers.Length > 0)
|
||||||
|
{
|
||||||
|
foreach (var member in injectionMembers)
|
||||||
|
{
|
||||||
|
member.AddPolicies(registration.RegisteredType, registration.MappedToType,
|
||||||
|
registration.Name, context.Policies);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register policies for each strategy
|
||||||
|
var strategies = container._registerTypeStrategies;
|
||||||
|
foreach (var strategy in strategies)
|
||||||
|
strategy.RegisterType(context, registration.RegisteredType, registration.MappedToType,
|
||||||
|
registration.Name, registration.LifetimeManager, injectionMembers);
|
||||||
|
|
||||||
|
// Raise event
|
||||||
|
container.Registering?.Invoke(this, new RegisterEventArgs(registration.RegisteredType,
|
||||||
|
registration.MappedToType,
|
||||||
|
registration.Name,
|
||||||
|
registration.LifetimeManager));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Instance Registration
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Register an instance with the container.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks> <para>
|
||||||
|
/// Instance registration is much like setting a type as a singleton, except that instead
|
||||||
|
/// of the container creating the instance the first time it is requested, the user
|
||||||
|
/// creates the instance ahead of type and adds that instance to the container.
|
||||||
|
/// </para></remarks>
|
||||||
|
/// <param name="registrationType">Type of instance to register (may be an implemented interface instead of the full type).</param>
|
||||||
|
/// <param name="instance">Object to be returned.</param>
|
||||||
|
/// <param name="registrationName">Name for registration.</param>
|
||||||
|
/// <param name="lifetimeManager">
|
||||||
|
/// <para>If null or <see cref="ContainerControlledLifetimeManager"/>, the container will take over the lifetime of the instance,
|
||||||
|
/// calling Dispose on it (if it's <see cref="IDisposable"/>) when the container is Disposed.</para>
|
||||||
|
/// <para>
|
||||||
|
/// If <see cref="ExternallyControlledLifetimeManager"/>, container will not maintain a strong reference to <paramref name="instance"/>.
|
||||||
|
/// User is responsible for disposing instance, and for keeping the instance typeFrom being garbage collected.</para></param>
|
||||||
|
/// <returns>The <see cref="UnityContainer"/> object that this method was called on (this in C#, Me in Visual Basic).</returns>
|
||||||
|
public IUnityContainer RegisterInstance(Type registrationType, string registrationName, object instance, LifetimeManager lifetimeManager)
|
||||||
|
{
|
||||||
|
// Validate imput
|
||||||
|
if (string.Empty == registrationName) registrationName = null;
|
||||||
|
if (null == instance) throw new ArgumentNullException(nameof(instance));
|
||||||
|
|
||||||
|
// TODO: Move to strategy
|
||||||
|
var lifetime = lifetimeManager ?? new ContainerControlledLifetimeManager();
|
||||||
|
if (lifetime.InUse) throw new InvalidOperationException(Constants.LifetimeManagerInUse);
|
||||||
|
lifetime.SetValue(instance, _lifetimeContainer);
|
||||||
|
|
||||||
|
// Create registration and add to appropriate storage
|
||||||
|
var registration = new InstanceRegistration(registrationType, registrationName, instance, lifetime);
|
||||||
|
var container = (lifetimeManager is ISingletonLifetimePolicy) ? GetRootContainer() : this;
|
||||||
|
|
||||||
|
// Add or replace existing
|
||||||
|
if (container.SetOrUpdate(registration) is IDisposable disposable)
|
||||||
|
{
|
||||||
|
container._lifetimeContainer.Remove(disposable);
|
||||||
|
disposable.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (registration.LifetimeManager is IDisposable manager)
|
||||||
|
container._lifetimeContainer.Add(manager);
|
||||||
|
|
||||||
|
// Raise event
|
||||||
|
container.RegisteringInstance?.Invoke(this, new RegisterInstanceEventArgs(registration.RegisteredType, instance,
|
||||||
|
registration.Name, registration.LifetimeManager));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Check Registration
|
||||||
|
|
||||||
|
|
||||||
|
public bool IsRegistered(Type type, string name)
|
||||||
|
{
|
||||||
|
for (var registry = this; null != registry; registry = registry._parent)
|
||||||
|
{
|
||||||
|
if (null == registry[type, name]) continue;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
private IRegistry<string, IPolicySet> this[Type type]
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var hashCode = (type?.GetHashCode() ?? 0) & 0x7FFFFFFF;
|
||||||
|
var targetBucket = hashCode % _registrations.Buckets.Length;
|
||||||
|
for (var i = _registrations.Buckets[targetBucket]; i >= 0; i = _registrations.Entries[i].Next)
|
||||||
|
{
|
||||||
|
if (_registrations.Entries[i].HashCode != hashCode ||
|
||||||
|
_registrations.Entries[i].Key != type)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _registrations.Entries[i].Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private IPolicySet this[Type type, string name]
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var hashCode = (type?.GetHashCode() ?? 0) & 0x7FFFFFFF;
|
||||||
|
var targetBucket = hashCode % _registrations.Buckets.Length;
|
||||||
|
for (var i = _registrations.Buckets[targetBucket]; i >= 0; i = _registrations.Entries[i].Next)
|
||||||
|
{
|
||||||
|
if (_registrations.Entries[i].HashCode != hashCode ||
|
||||||
|
_registrations.Entries[i].Key != type)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _registrations.Entries[i].Value?[name];
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
var hashCode = (type?.GetHashCode() ?? 0) & 0x7FFFFFFF;
|
||||||
|
var targetBucket = hashCode % _registrations.Buckets.Length;
|
||||||
|
var collisions = 0;
|
||||||
|
lock (_syncRoot)
|
||||||
|
{
|
||||||
|
for (var i = _registrations.Buckets[targetBucket]; i >= 0; i = _registrations.Entries[i].Next)
|
||||||
|
{
|
||||||
|
if (_registrations.Entries[i].HashCode != hashCode ||
|
||||||
|
_registrations.Entries[i].Key != type)
|
||||||
|
{
|
||||||
|
collisions++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var existing = _registrations.Entries[i].Value;
|
||||||
|
if (existing.RequireToGrow)
|
||||||
|
{
|
||||||
|
existing = existing is HashRegistry<string, IPolicySet> registry
|
||||||
|
? new HashRegistry<string, IPolicySet>(registry)
|
||||||
|
: new HashRegistry<string, IPolicySet>(LinkedRegistry.ListToHashCutoverPoint * 2,
|
||||||
|
(LinkedRegistry)existing);
|
||||||
|
|
||||||
|
_registrations.Entries[i].Value = existing;
|
||||||
|
}
|
||||||
|
|
||||||
|
existing[name] = value;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_registrations.RequireToGrow || ListToHashCutoverPoint < collisions)
|
||||||
|
{
|
||||||
|
_registrations = new HashRegistry<Type, IRegistry<string, IPolicySet>>(_registrations);
|
||||||
|
targetBucket = hashCode % _registrations.Buckets.Length;
|
||||||
|
}
|
||||||
|
|
||||||
|
_registrations.Entries[_registrations.Count].HashCode = hashCode;
|
||||||
|
_registrations.Entries[_registrations.Count].Next = _registrations.Buckets[targetBucket];
|
||||||
|
_registrations.Entries[_registrations.Count].Key = type;
|
||||||
|
_registrations.Entries[_registrations.Count].Value = new LinkedRegistry(name, value);
|
||||||
|
_registrations.Buckets[targetBucket] = _registrations.Count;
|
||||||
|
_registrations.Count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private IBuilderPolicy this[Type type, string name, Type interfaceType]
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var collisions = 0;
|
||||||
|
var hashCode = (type?.GetHashCode() ?? 0) & 0x7FFFFFFF;
|
||||||
|
var targetBucket = hashCode % _registrations.Buckets.Length;
|
||||||
|
IPolicySet registration = null;
|
||||||
|
lock (_syncRoot)
|
||||||
|
{
|
||||||
|
for (var i = _registrations.Buckets[targetBucket]; i >= 0; i = _registrations.Entries[i].Next)
|
||||||
|
{
|
||||||
|
if (_registrations.Entries[i].HashCode != hashCode ||
|
||||||
|
_registrations.Entries[i].Key != type)
|
||||||
|
{
|
||||||
|
collisions++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var existing = _registrations.Entries[i].Value;
|
||||||
|
if (existing.RequireToGrow)
|
||||||
|
{
|
||||||
|
existing = existing is HashRegistry<string, IPolicySet> registry
|
||||||
|
? new HashRegistry<string, IPolicySet>(registry)
|
||||||
|
: new HashRegistry<string, IPolicySet>(LinkedRegistry.ListToHashCutoverPoint * 2,
|
||||||
|
(LinkedRegistry)existing);
|
||||||
|
|
||||||
|
_registrations.Entries[i].Value = existing;
|
||||||
|
}
|
||||||
|
|
||||||
|
registration = existing.GetOrAdd(name, () => CreateRegistration(type, name));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null == registration)
|
||||||
|
{
|
||||||
|
if (_registrations.RequireToGrow || ListToHashCutoverPoint < collisions)
|
||||||
|
{
|
||||||
|
_registrations = new HashRegistry<Type, IRegistry<string, IPolicySet>>(_registrations);
|
||||||
|
targetBucket = hashCode % _registrations.Buckets.Length;
|
||||||
|
}
|
||||||
|
|
||||||
|
registration = CreateRegistration(type, name);
|
||||||
|
_registrations.Entries[_registrations.Count].HashCode = hashCode;
|
||||||
|
_registrations.Entries[_registrations.Count].Next = _registrations.Buckets[targetBucket];
|
||||||
|
_registrations.Entries[_registrations.Count].Key = type;
|
||||||
|
_registrations.Entries[_registrations.Count].Value = new LinkedRegistry(name, registration);
|
||||||
|
_registrations.Buckets[targetBucket] = _registrations.Count;
|
||||||
|
_registrations.Count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return registration.Get(interfaceType);
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
var collisions = 0;
|
||||||
|
var hashCode = (type?.GetHashCode() ?? 0) & 0x7FFFFFFF;
|
||||||
|
var targetBucket = hashCode % _registrations.Buckets.Length;
|
||||||
|
lock (_syncRoot)
|
||||||
|
{
|
||||||
|
for (var i = _registrations.Buckets[targetBucket]; i >= 0; i = _registrations.Entries[i].Next)
|
||||||
|
{
|
||||||
|
if (_registrations.Entries[i].HashCode != hashCode ||
|
||||||
|
_registrations.Entries[i].Key != type)
|
||||||
|
{
|
||||||
|
collisions++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var existing = _registrations.Entries[i].Value;
|
||||||
|
if (existing.RequireToGrow)
|
||||||
|
{
|
||||||
|
existing = existing is HashRegistry<string, IPolicySet> registry
|
||||||
|
? new HashRegistry<string, IPolicySet>(registry)
|
||||||
|
: new HashRegistry<string, IPolicySet>(LinkedRegistry.ListToHashCutoverPoint * 2,
|
||||||
|
(LinkedRegistry)existing);
|
||||||
|
|
||||||
|
_registrations.Entries[i].Value = existing;
|
||||||
|
}
|
||||||
|
|
||||||
|
existing.GetOrAdd(name, () => CreateRegistration(type, name)).Set(interfaceType, value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_registrations.RequireToGrow || ListToHashCutoverPoint < collisions)
|
||||||
|
{
|
||||||
|
_registrations = new HashRegistry<Type, IRegistry<string, IPolicySet>>(_registrations);
|
||||||
|
targetBucket = hashCode % _registrations.Buckets.Length;
|
||||||
|
}
|
||||||
|
|
||||||
|
var registration = CreateRegistration(type, name);
|
||||||
|
registration.Set(interfaceType, value);
|
||||||
|
|
||||||
|
_registrations.Entries[_registrations.Count].HashCode = hashCode;
|
||||||
|
_registrations.Entries[_registrations.Count].Next = _registrations.Buckets[targetBucket];
|
||||||
|
_registrations.Entries[_registrations.Count].Key = type;
|
||||||
|
_registrations.Entries[_registrations.Count].Value = new LinkedRegistry(name, registration);
|
||||||
|
_registrations.Buckets[targetBucket] = _registrations.Count;
|
||||||
|
_registrations.Count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#region Special Accessors
|
||||||
|
|
||||||
|
private IPolicySet SetOrUpdate(INamedType registration)
|
||||||
|
{
|
||||||
|
var collisions = 0;
|
||||||
|
var hashCode = (registration.Type?.GetHashCode() ?? 0) & 0x7FFFFFFF;
|
||||||
|
var targetBucket = hashCode % _registrations.Buckets.Length;
|
||||||
|
lock (_syncRoot)
|
||||||
|
{
|
||||||
|
for (var i = _registrations.Buckets[targetBucket]; i >= 0; i = _registrations.Entries[i].Next)
|
||||||
|
{
|
||||||
|
if (_registrations.Entries[i].HashCode != hashCode ||
|
||||||
|
_registrations.Entries[i].Key != registration.Type)
|
||||||
|
{
|
||||||
|
collisions++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var existing = _registrations.Entries[i].Value;
|
||||||
|
if (existing.RequireToGrow)
|
||||||
|
{
|
||||||
|
existing = existing is HashRegistry<string, IPolicySet> registry
|
||||||
|
? new HashRegistry<string, IPolicySet>(registry)
|
||||||
|
: new HashRegistry<string, IPolicySet>(LinkedRegistry.ListToHashCutoverPoint * 2, (LinkedRegistry)existing);
|
||||||
|
|
||||||
|
_registrations.Entries[i].Value = existing;
|
||||||
|
}
|
||||||
|
|
||||||
|
return existing.SetOrReplace(registration.Name, (IPolicySet)registration);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_registrations.RequireToGrow || ListToHashCutoverPoint < collisions)
|
||||||
|
{
|
||||||
|
_registrations = new HashRegistry<Type, IRegistry<string, IPolicySet>>(_registrations);
|
||||||
|
targetBucket = hashCode % _registrations.Buckets.Length;
|
||||||
|
}
|
||||||
|
|
||||||
|
_registrations.Entries[_registrations.Count].HashCode = hashCode;
|
||||||
|
_registrations.Entries[_registrations.Count].Next = _registrations.Buckets[targetBucket];
|
||||||
|
_registrations.Entries[_registrations.Count].Key = registration.Type;
|
||||||
|
_registrations.Entries[_registrations.Count].Value = new LinkedRegistry(registration.Name, (IPolicySet)registration);
|
||||||
|
_registrations.Buckets[targetBucket] = _registrations.Count;
|
||||||
|
_registrations.Count++;
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Registrations Collection
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// GetOrDefault a sequence of <see cref="IContainerRegistration"/> that describe the current state
|
||||||
|
/// of the container.
|
||||||
|
/// </summary>
|
||||||
|
public IEnumerable<IContainerRegistration> Registrations
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return GetRegisteredTypes(this).SelectMany(type => GetRegisteredType(this, type));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ISet<Type> GetRegisteredTypes(UnityContainer container)
|
||||||
|
{
|
||||||
|
var set = null == container._parent ? new HashSet<Type>()
|
||||||
|
: GetRegisteredTypes(container._parent);
|
||||||
|
|
||||||
|
foreach (var type in container._registrations.Keys.Where(t => null != t))
|
||||||
|
set.Add(type);
|
||||||
|
|
||||||
|
return set;
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerable<IContainerRegistration> GetRegisteredType(UnityContainer container, Type type)
|
||||||
|
{
|
||||||
|
ReverseHashSet set;
|
||||||
|
|
||||||
|
if (null != container._parent)
|
||||||
|
set = (ReverseHashSet)GetRegisteredType(container._parent, type);
|
||||||
|
else
|
||||||
|
set = new ReverseHashSet();
|
||||||
|
|
||||||
|
foreach (var registration in container[type]?.Values.OfType<IContainerRegistration>()
|
||||||
|
?? Enumerable.Empty<IContainerRegistration>())
|
||||||
|
{
|
||||||
|
set.Add(registration);
|
||||||
|
}
|
||||||
|
|
||||||
|
return set;
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerable<string> GetRegisteredNames(UnityContainer container, Type type)
|
||||||
|
{
|
||||||
|
ISet<string> set;
|
||||||
|
|
||||||
|
if (null != container._parent)
|
||||||
|
set = (ISet<string>)GetRegisteredNames(container._parent, type);
|
||||||
|
else
|
||||||
|
set = new HashSet<string>();
|
||||||
|
|
||||||
|
foreach (var registration in container[type]?.Values.OfType<IContainerRegistration>()
|
||||||
|
?? Enumerable.Empty<IContainerRegistration>())
|
||||||
|
{
|
||||||
|
set.Add(registration.Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
var generic = type.GetTypeInfo().IsGenericType ? type.GetGenericTypeDefinition() : type;
|
||||||
|
|
||||||
|
if (generic != type)
|
||||||
|
{
|
||||||
|
foreach (var registration in container[generic]?.Values.OfType<IContainerRegistration>()
|
||||||
|
?? Enumerable.Empty<IContainerRegistration>())
|
||||||
|
{
|
||||||
|
set.Add(registration.Name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return set;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,251 @@
|
||||||
|
using System;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using Unity.Builder;
|
||||||
|
using Unity.Exceptions;
|
||||||
|
using Unity.Policy;
|
||||||
|
using Unity.Resolution;
|
||||||
|
using Unity.Storage;
|
||||||
|
|
||||||
|
namespace Unity
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
/// <summary>
|
||||||
|
/// A simple, extensible dependency injection container.
|
||||||
|
/// </summary>
|
||||||
|
public partial class UnityContainer
|
||||||
|
{
|
||||||
|
#region Getting objects
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// GetOrDefault an instance of the requested type with the given name typeFrom the container.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="type"><see cref="Type"/> of object to get typeFrom the container.</param>
|
||||||
|
/// <param name="name">Name of the object to retrieve.</param>
|
||||||
|
/// <param name="resolverOverrides">Any overrides for the resolve call.</param>
|
||||||
|
/// <returns>The retrieved object.</returns>
|
||||||
|
public object Resolve(Type type, string name, params ResolverOverride[] resolverOverrides)
|
||||||
|
{
|
||||||
|
return BuildUp(type, null, name, resolverOverrides);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region BuildUp existing object
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Run an existing object through the container and perform injection on it.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// <para>
|
||||||
|
/// This method is useful when you don'type control the construction of an
|
||||||
|
/// instance (ASP.NET pages or objects created via XAML, for instance)
|
||||||
|
/// but you still want properties and other injection performed.
|
||||||
|
/// </para></remarks>
|
||||||
|
/// <param name="typeToBuild"><see cref="Type"/> of object to perform injection on.</param>
|
||||||
|
/// <param name="existing">Instance to build up.</param>
|
||||||
|
/// <param name="nameToBuild">name to use when looking up the typemappings and other configurations.</param>
|
||||||
|
/// <param name="resolverOverrides">Any overrides for the buildup.</param>
|
||||||
|
/// <returns>The resulting object. By default, this will be <paramref name="existing"/>, but
|
||||||
|
/// container extensions may add things like automatic proxy creation which would
|
||||||
|
/// cause this to return a different object (but still type compatible with <paramref name="typeToBuild"/>).</returns>
|
||||||
|
public object BuildUp(Type typeToBuild, object existing, string nameToBuild, params ResolverOverride[] resolverOverrides)
|
||||||
|
{
|
||||||
|
// Verify arguments
|
||||||
|
var name = string.IsNullOrEmpty(nameToBuild) ? null : nameToBuild;
|
||||||
|
var type = typeToBuild ?? throw new ArgumentNullException(nameof(typeToBuild));
|
||||||
|
if (null != existing) InstanceIsAssignable(type, existing, nameof(existing));
|
||||||
|
|
||||||
|
IBuilderContext context = null;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var registration = Registration(type, name, true);
|
||||||
|
var policies = new PolicyListWrapper(registration, _context);
|
||||||
|
var transient = new PolicyList(policies);
|
||||||
|
context = new BuilderContext(this, _lifetimeContainer,
|
||||||
|
_strategyChain,
|
||||||
|
policies,
|
||||||
|
transient,
|
||||||
|
registration,
|
||||||
|
existing, resolverOverrides);
|
||||||
|
|
||||||
|
if (type.GetTypeInfo().IsGenericTypeDefinition)
|
||||||
|
{
|
||||||
|
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture,
|
||||||
|
Constants.CannotResolveOpenGenericType,
|
||||||
|
type.FullName), nameof(typeToBuild));
|
||||||
|
}
|
||||||
|
|
||||||
|
context.Strategies.BuildUp(context);
|
||||||
|
return context.Existing;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
throw new ResolutionFailedException(type, name, ex, context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private class PolicyListWrapper : IPolicyList
|
||||||
|
{
|
||||||
|
private readonly INamedType _store;
|
||||||
|
private readonly IPolicyList _policies;
|
||||||
|
|
||||||
|
public PolicyListWrapper(INamedType store, IPolicyList policies)
|
||||||
|
{
|
||||||
|
_store = store;
|
||||||
|
_policies = policies;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Clear(Type type, string name, Type policyInterface)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ClearAll()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public IBuilderPolicy Get(Type type, string name, Type policyInterface, out IPolicyList list)
|
||||||
|
{
|
||||||
|
list = null;
|
||||||
|
|
||||||
|
if (type != _store.Type || name != _store.Name)
|
||||||
|
return _policies.Get(type, name, policyInterface, out list);
|
||||||
|
|
||||||
|
var result = ((IPolicySet)_store).Get(policyInterface);
|
||||||
|
if (null != result) list = this;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Set(Type type, string name, Type policyInterface, IBuilderPolicy policy)
|
||||||
|
{
|
||||||
|
if (type != _store.Type || name != _store.Name)
|
||||||
|
_policies.Set(type, name, policyInterface, policy);
|
||||||
|
|
||||||
|
((IPolicySet)_store).Set(policyInterface, policy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#region Resolving Enumerables
|
||||||
|
|
||||||
|
private static void ResolveArray<T>(IBuilderContext context)
|
||||||
|
{
|
||||||
|
if (null != context.Existing) return;
|
||||||
|
|
||||||
|
var container = (UnityContainer)context.Container;
|
||||||
|
context.Existing = container.GetRegisteredNames(container, typeof(T))
|
||||||
|
.Where(registration => null != registration)
|
||||||
|
.Select(registration => context.NewBuildUp(typeof(T), registration))
|
||||||
|
.Cast<T>()
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
context.BuildComplete = true;
|
||||||
|
context.SetPerBuildSingleton();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ResolveEnumerable<T>(IBuilderContext context)
|
||||||
|
{
|
||||||
|
if (null != context.Existing) return;
|
||||||
|
|
||||||
|
var container = (UnityContainer)context.Container;
|
||||||
|
context.Existing = container.GetRegisteredNames(container, typeof(T))
|
||||||
|
.Select(registration => context.NewBuildUp(typeof(T), registration))
|
||||||
|
.Cast<T>()
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
context.BuildComplete = true;
|
||||||
|
context.SetPerBuildSingleton();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Implementation
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves registration for requested named type
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="type">Registration type</param>
|
||||||
|
/// <param name="name">Registration name</param>
|
||||||
|
/// <param name="create">Instruncts container if it should create registration if not found</param>
|
||||||
|
/// <returns>Registration for requested named type or null if named type is not registered and
|
||||||
|
/// <see cref="create"/> is false</returns>
|
||||||
|
public INamedType Registration(Type type, string name, bool create = false)
|
||||||
|
{
|
||||||
|
for (var container = this; null != container; container = container._parent)
|
||||||
|
{
|
||||||
|
IPolicySet data;
|
||||||
|
if (null == (data = container[type, name])) continue;
|
||||||
|
|
||||||
|
return (INamedType)data;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!create) return null;
|
||||||
|
|
||||||
|
var collisions = 0;
|
||||||
|
var hashCode = (type?.GetHashCode() ?? 0) & 0x7FFFFFFF;
|
||||||
|
var targetBucket = hashCode % _registrations.Buckets.Length;
|
||||||
|
lock (_syncRoot)
|
||||||
|
{
|
||||||
|
for (var i = _registrations.Buckets[targetBucket]; i >= 0; i = _registrations.Entries[i].Next)
|
||||||
|
{
|
||||||
|
if (_registrations.Entries[i].HashCode != hashCode ||
|
||||||
|
_registrations.Entries[i].Key != type)
|
||||||
|
{
|
||||||
|
collisions++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var existing = _registrations.Entries[i].Value;
|
||||||
|
if (existing.RequireToGrow)
|
||||||
|
{
|
||||||
|
existing = existing is HashRegistry<string, IPolicySet> registry
|
||||||
|
? new HashRegistry<string, IPolicySet>(registry)
|
||||||
|
: new HashRegistry<string, IPolicySet>(LinkedRegistry.ListToHashCutoverPoint * 2,
|
||||||
|
(LinkedRegistry)existing);
|
||||||
|
|
||||||
|
_registrations.Entries[i].Value = existing;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (INamedType)existing.GetOrAdd(name, () => CreateRegistration(type, name));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_registrations.RequireToGrow || ListToHashCutoverPoint < collisions)
|
||||||
|
{
|
||||||
|
_registrations = new HashRegistry<Type, IRegistry<string, IPolicySet>>(_registrations);
|
||||||
|
targetBucket = hashCode % _registrations.Buckets.Length;
|
||||||
|
}
|
||||||
|
|
||||||
|
var registration = CreateRegistration(type, name);
|
||||||
|
_registrations.Entries[_registrations.Count].HashCode = hashCode;
|
||||||
|
_registrations.Entries[_registrations.Count].Next = _registrations.Buckets[targetBucket];
|
||||||
|
_registrations.Entries[_registrations.Count].Key = type;
|
||||||
|
_registrations.Entries[_registrations.Count].Value = new LinkedRegistry(name, registration);
|
||||||
|
_registrations.Buckets[targetBucket] = _registrations.Count;
|
||||||
|
_registrations.Count++;
|
||||||
|
|
||||||
|
return (INamedType)registration;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,420 +0,0 @@
|
||||||
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Globalization;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Reflection;
|
|
||||||
using Unity.Builder;
|
|
||||||
using Unity.Container.Registration;
|
|
||||||
using Unity.Events;
|
|
||||||
using Unity.Exceptions;
|
|
||||||
using Unity.Extension;
|
|
||||||
using Unity.Injection;
|
|
||||||
using Unity.Lifetime;
|
|
||||||
using Unity.ObjectBuilder;
|
|
||||||
using Unity.Policy;
|
|
||||||
using Unity.Registration;
|
|
||||||
using Unity.Resolution;
|
|
||||||
using Unity.Strategy;
|
|
||||||
|
|
||||||
namespace Unity
|
|
||||||
{
|
|
||||||
/// <inheritdoc />
|
|
||||||
/// <summary>
|
|
||||||
/// A simple, extensible dependency injection container.
|
|
||||||
/// </summary>
|
|
||||||
public partial class UnityContainer : IUnityContainer
|
|
||||||
{
|
|
||||||
#region Public Constructor
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Create a default <see cref="UnityContainer"/>.
|
|
||||||
/// </summary>
|
|
||||||
public UnityContainer()
|
|
||||||
: this(null)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region Type Registration
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// RegisterType a type mapping with the container, where the created instances will use
|
|
||||||
/// the given <see cref="LifetimeManager"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="typeFrom"><see cref="Type"/> that will be requested.</param>
|
|
||||||
/// <param name="typeTo"><see cref="Type"/> that will actually be returned.</param>
|
|
||||||
/// <param name="name">Name to use for registration, null if a default registration.</param>
|
|
||||||
/// <param name="lifetimeManager">The <see cref="LifetimeManager"/> that controls the lifetime
|
|
||||||
/// of the returned instance.</param>
|
|
||||||
/// <param name="injectionMembers">Injection configuration objects.</param>
|
|
||||||
/// <returns>The <see cref="UnityContainer"/> object that this method was called on
|
|
||||||
/// (this in C#, Me in Visual Basic).</returns>
|
|
||||||
public IUnityContainer RegisterType(Type typeFrom, Type typeTo, string name,
|
|
||||||
LifetimeManager lifetimeManager, InjectionMember[] injectionMembers)
|
|
||||||
{
|
|
||||||
// Validate input
|
|
||||||
if (string.Empty == name) name = null;
|
|
||||||
|
|
||||||
if (null == typeTo) throw new ArgumentNullException(nameof(typeTo));
|
|
||||||
|
|
||||||
if (typeFrom != null && !typeFrom.GetTypeInfo().IsGenericType && !typeTo.GetTypeInfo().IsGenericType &&
|
|
||||||
!typeFrom.GetTypeInfo().IsAssignableFrom(typeTo.GetTypeInfo()))
|
|
||||||
{
|
|
||||||
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Constants.TypesAreNotAssignable,
|
|
||||||
typeFrom, typeTo), nameof(typeFrom));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Register Type
|
|
||||||
var buildType = typeFrom ?? typeTo;
|
|
||||||
var container = (lifetimeManager is ISingletonLifetimePolicy) ? GetRootContainer() : this;
|
|
||||||
|
|
||||||
// Clear build plan
|
|
||||||
container._policies.Set(buildType, name, typeof(IBuildPlanPolicy), new OverriddenBuildPlanMarkerPolicy());
|
|
||||||
|
|
||||||
// Register Type/Name
|
|
||||||
container._registeredNames.RegisterType(buildType, name);
|
|
||||||
|
|
||||||
// Add Injection Members to the list
|
|
||||||
if (null != injectionMembers && injectionMembers.Length > 0)
|
|
||||||
{
|
|
||||||
foreach (var member in injectionMembers)
|
|
||||||
{
|
|
||||||
if (member is IInjectionFactory && null != typeFrom && typeFrom != typeTo)
|
|
||||||
throw new InvalidOperationException(Constants.CannotInjectFactory);
|
|
||||||
|
|
||||||
member.AddPolicies(buildType, typeTo, name, container._policies);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Register policies for each strategy
|
|
||||||
var strategies = container._registerTypeStrategies;
|
|
||||||
foreach (var strategy in strategies)
|
|
||||||
strategy.RegisterType(_context, typeFrom, typeTo, name, lifetimeManager, injectionMembers);
|
|
||||||
|
|
||||||
// Raise event
|
|
||||||
container.Registering?.Invoke(this, new RegisterEventArgs(typeFrom, typeTo, name, lifetimeManager));
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region Instance Registration
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// RegisterType an instance with the container.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// <para>
|
|
||||||
/// Instance registration is much like setting a type as a singleton, except that instead
|
|
||||||
/// of the container creating the instance the first time it is requested, the user
|
|
||||||
/// creates the instance ahead of type and adds that instance to the container.
|
|
||||||
/// </para>
|
|
||||||
/// </remarks>
|
|
||||||
/// <param name="toType">Type of instance to register (may be an implemented interface instead of the full type).</param>
|
|
||||||
/// <param name="instance">Object to returned.</param>
|
|
||||||
/// <param name="name">Name for registration.</param>
|
|
||||||
/// <param name="manager">
|
|
||||||
/// <para>If true, the container will take over the lifetime of the instance,
|
|
||||||
/// calling Dispose on it (if it's <see cref="IDisposable"/>) when the container is Disposed.</para>
|
|
||||||
/// <para>
|
|
||||||
/// If false, container will not maintain a strong reference to <paramref name="instance"/>. User is responsible
|
|
||||||
/// for disposing instance, and for keeping the instance typeFrom being garbage collected.</para></param>
|
|
||||||
/// <returns>The <see cref="UnityContainer"/> object that this method was called on (this in C#, Me in Visual Basic).</returns>
|
|
||||||
public IUnityContainer RegisterInstance(Type toType, string name, object instance, LifetimeManager manager)
|
|
||||||
{
|
|
||||||
if (null == instance) throw new ArgumentNullException(nameof(instance));
|
|
||||||
if (null != toType) InstanceIsAssignable(toType, instance, nameof(instance));
|
|
||||||
|
|
||||||
var type = toType ?? instance.GetType();
|
|
||||||
var lifetime = manager ?? new ContainerControlledLifetimeManager();
|
|
||||||
var container = (manager is ISingletonLifetimePolicy) ? GetRootContainer() : this;
|
|
||||||
|
|
||||||
container._registeredNames.RegisterType(type, name);
|
|
||||||
|
|
||||||
lifetime.SetValue(instance, _lifetimeContainer);
|
|
||||||
container.SetLifetimeManager(type, name, lifetime);
|
|
||||||
|
|
||||||
if (lifetime is IBuildPlanPolicy buildPlanPolicy)
|
|
||||||
container._policies.Set(type, name, typeof(IBuildPlanPolicy), buildPlanPolicy);
|
|
||||||
else
|
|
||||||
container._policies.Set(type, name, typeof(IBuildPlanPolicy), new OverriddenBuildPlanMarkerPolicy());
|
|
||||||
|
|
||||||
container.RegisteringInstance?.Invoke(this, new RegisterInstanceEventArgs(type, instance,
|
|
||||||
name, lifetime));
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region Getting objects
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// GetOrDefault an instance of the requested type with the given name typeFrom the container.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="type"><see cref="Type"/> of object to get typeFrom the container.</param>
|
|
||||||
/// <param name="name">Name of the object to retrieve.</param>
|
|
||||||
/// <param name="resolverOverrides">Any overrides for the resolve call.</param>
|
|
||||||
/// <returns>The retrieved object.</returns>
|
|
||||||
public object Resolve(Type type, string name, params ResolverOverride[] resolverOverrides)
|
|
||||||
{
|
|
||||||
return BuildUp(type, null, name, resolverOverrides);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region BuildUp existing object
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Run an existing object through the container and perform injection on it.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// <para>
|
|
||||||
/// This method is useful when you don'type control the construction of an
|
|
||||||
/// instance (ASP.NET pages or objects created via XAML, for instance)
|
|
||||||
/// but you still want properties and other injection performed.
|
|
||||||
/// </para></remarks>
|
|
||||||
/// <param name="typeToBuild"><see cref="Type"/> of object to perform injection on.</param>
|
|
||||||
/// <param name="existing">Instance to build up.</param>
|
|
||||||
/// <param name="name">name to use when looking up the typemappings and other configurations.</param>
|
|
||||||
/// <param name="resolverOverrides">Any overrides for the buildup.</param>
|
|
||||||
/// <returns>The resulting object. By default, this will be <paramref name="existing"/>, but
|
|
||||||
/// container extensions may add things like automatic proxy creation which would
|
|
||||||
/// cause this to return a different object (but still type compatible with <paramref name="typeToBuild"/>).</returns>
|
|
||||||
public object BuildUp(Type typeToBuild, object existing, string name, params ResolverOverride[] resolverOverrides)
|
|
||||||
{
|
|
||||||
var type = typeToBuild ?? throw new ArgumentNullException(nameof(typeToBuild));
|
|
||||||
if (null != existing) InstanceIsAssignable(type, existing, nameof(existing));
|
|
||||||
|
|
||||||
IBuilderContext context = null;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
context = new BuilderContext(this, _strategies.MakeStrategyChain(),
|
|
||||||
_lifetimeContainer,
|
|
||||||
_policies,
|
|
||||||
new NamedTypeBuildKey(type, name),
|
|
||||||
existing);
|
|
||||||
context.AddResolverOverrides(resolverOverrides);
|
|
||||||
|
|
||||||
if (type.GetTypeInfo().IsGenericTypeDefinition)
|
|
||||||
{
|
|
||||||
throw new ArgumentException(
|
|
||||||
String.Format(CultureInfo.CurrentCulture,
|
|
||||||
Constants.CannotResolveOpenGenericType,
|
|
||||||
type.FullName), nameof(type));
|
|
||||||
}
|
|
||||||
|
|
||||||
return context.Strategies.ExecuteBuildUp(context);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
throw new ResolutionFailedException(type, name, ex, context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region Extension Management
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Add an extension object to the container.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="extension"><see cref="UnityContainerExtension"/> to add.</param>
|
|
||||||
/// <returns>The <see cref="UnityContainer"/> object that this method was called on (this in C#, Me in Visual Basic).</returns>
|
|
||||||
public IUnityContainer AddExtension(UnityContainerExtension extension)
|
|
||||||
{
|
|
||||||
_extensions.Add(extension ?? throw new ArgumentNullException(nameof(extension)));
|
|
||||||
extension.InitializeExtension(new ContainerContext(this));
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// GetOrDefault access to a configuration interface exposed by an extension.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>Extensions can expose configuration interfaces as well as adding
|
|
||||||
/// strategies and policies to the container. This method walks the list of
|
|
||||||
/// added extensions and returns the first one that implements the requested type.
|
|
||||||
/// </remarks>
|
|
||||||
/// <param name="configurationInterface"><see cref="Type"/> of configuration interface required.</param>
|
|
||||||
/// <returns>The requested extension's configuration interface, or null if not found.</returns>
|
|
||||||
public object Configure(Type configurationInterface)
|
|
||||||
{
|
|
||||||
return _extensions.FirstOrDefault(ex => configurationInterface.GetTypeInfo()
|
|
||||||
.IsAssignableFrom(ex.GetType().GetTypeInfo()));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Remove all installed extensions typeFrom this container.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// <para>
|
|
||||||
/// This method removes all extensions typeFrom the container, including the default ones
|
|
||||||
/// that implement the out-of-the-box behavior. After this method, if you want to use
|
|
||||||
/// the container again you will need to either read the default extensions or replace
|
|
||||||
/// them with your own.
|
|
||||||
/// </para>
|
|
||||||
/// <para>
|
|
||||||
/// The registered instances and singletons that have already been set up in this container
|
|
||||||
/// do not get removed.
|
|
||||||
/// </para>
|
|
||||||
/// </remarks>
|
|
||||||
/// <returns>The <see cref="UnityContainer"/> object that this method was called on (this in C#, Me in Visual Basic).</returns>
|
|
||||||
public IUnityContainer RemoveAllExtensions()
|
|
||||||
{
|
|
||||||
var toRemove = new List<UnityContainerExtension>(_extensions);
|
|
||||||
toRemove.Reverse();
|
|
||||||
foreach (UnityContainerExtension extension in toRemove)
|
|
||||||
{
|
|
||||||
extension.Remove();
|
|
||||||
(extension as IDisposable)?.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
_extensions.Clear();
|
|
||||||
|
|
||||||
// Reset our policies, strategies, and registered names to reset to "zero"
|
|
||||||
_strategies.Clear();
|
|
||||||
_policies.ClearAll();
|
|
||||||
_registeredNames.Clear();
|
|
||||||
|
|
||||||
if (null == _parent)
|
|
||||||
InitializeStrategies();
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region Child container management
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Create a child container.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// A child container shares the parent's configuration, but can be configured with different
|
|
||||||
/// settings or lifetime.</remarks>
|
|
||||||
/// <returns>The new child container.</returns>
|
|
||||||
public IUnityContainer CreateChildContainer()
|
|
||||||
{
|
|
||||||
var child = new UnityContainer(this);
|
|
||||||
ChildContainerCreated?.Invoke(this, new ChildContainerCreatedEventArgs(child._context));
|
|
||||||
return child;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The parent of this container.
|
|
||||||
/// </summary>
|
|
||||||
/// <value>The parent container, or null if this container doesn'type have one.</value>
|
|
||||||
public IUnityContainer Parent => _parent;
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region IDisposable Implementation
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Dispose this container instance.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// Disposing the container also disposes any child containers,
|
|
||||||
/// and disposes any instances whose lifetimes are managed
|
|
||||||
/// by the container.
|
|
||||||
/// </remarks>
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
Dispose(true);
|
|
||||||
GC.SuppressFinalize(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Dispose this container instance.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// This class doesn'type have a finalizer, so <paramref name="disposing"/> will always be true.</remarks>
|
|
||||||
/// <param name="disposing">True if being called typeFrom the IDisposable.Dispose
|
|
||||||
/// method, false if being called typeFrom a finalizer.</param>
|
|
||||||
protected virtual void Dispose(bool disposing)
|
|
||||||
{
|
|
||||||
if (disposing)
|
|
||||||
{
|
|
||||||
if (_lifetimeContainer != null)
|
|
||||||
{
|
|
||||||
_lifetimeContainer.Dispose();
|
|
||||||
_lifetimeContainer = null;
|
|
||||||
|
|
||||||
if (_parent != null && _parent._lifetimeContainer != null)
|
|
||||||
{
|
|
||||||
_parent._lifetimeContainer.Remove(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (IDisposable disposable in Enumerable.OfType<IDisposable>(_extensions))
|
|
||||||
disposable.Dispose();
|
|
||||||
|
|
||||||
_extensions.Clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns information about existing registration
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="type">Type to check</param>
|
|
||||||
/// <param name="name">Name of the registration</param>
|
|
||||||
/// <returns>True if registratin exists</returns>
|
|
||||||
public bool IsRegistered(Type type, string name)
|
|
||||||
{
|
|
||||||
return null != _policies.Get(type, name, typeof(IBuildPlanPolicy), out _);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// GetOrDefault a sequence of <see cref="ContainerRegistration"/> that describe the current state
|
|
||||||
/// of the container.
|
|
||||||
/// </summary>
|
|
||||||
public IEnumerable<IContainerRegistration> Registrations
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
var allRegisteredNames = new Dictionary<Type, List<string>>();
|
|
||||||
FillTypeRegistrationDictionary(allRegisteredNames);
|
|
||||||
|
|
||||||
return
|
|
||||||
from type in allRegisteredNames.Keys
|
|
||||||
from name in allRegisteredNames[type]
|
|
||||||
select new ContainerRegistration(type, name, _policies);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void FillTypeRegistrationDictionary(IDictionary<Type, List<string>> typeRegistrations)
|
|
||||||
{
|
|
||||||
if (_parent != null)
|
|
||||||
{
|
|
||||||
_parent.FillTypeRegistrationDictionary(typeRegistrations);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (Type t in _registeredNames.RegisteredTypes)
|
|
||||||
{
|
|
||||||
if (!typeRegistrations.ContainsKey(t))
|
|
||||||
{
|
|
||||||
typeRegistrations[t] = new List<string>();
|
|
||||||
}
|
|
||||||
|
|
||||||
typeRegistrations[t] =
|
|
||||||
(typeRegistrations[t].Concat(_registeredNames.GetKeys(t))).Distinct().ToList();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -17,7 +17,6 @@ namespace Unity
|
||||||
public const string CannotInjectMethodWithRefParams = "The method {0}.{1}({2}) has at least one ref parameter.Methods with ref parameters cannot be injected.";
|
public const string CannotInjectMethodWithRefParams = "The method {0}.{1}({2}) has at least one ref parameter.Methods with ref parameters cannot be injected.";
|
||||||
public const string CannotInjectOpenGenericMethod = "The method {1} on type {0} is marked for injection, but it is an open generic method. Injection cannot be performed.";
|
public const string CannotInjectOpenGenericMethod = "The method {1} on type {0} is marked for injection, but it is an open generic method. Injection cannot be performed.";
|
||||||
public const string CannotInjectStaticMethod = "The method {0}.{1}({2}) is static. Static methods cannot be injected.";
|
public const string CannotInjectStaticMethod = "The method {0}.{1}({2}) is static. Static methods cannot be injected.";
|
||||||
public const string CannotInjectFactory = "Injection factory can not be used in combination with type mapping (RegisterType<To, From>() or RegisterType<To>(new [Delegate]InjectionFactory()) )";
|
|
||||||
public const string CannotResolveOpenGenericType = "The type {0} is an open generic type. An open generic type cannot be resolved.";
|
public const string CannotResolveOpenGenericType = "The type {0} is an open generic type. An open generic type cannot be resolved.";
|
||||||
public const string ConstructorArgumentResolveOperation = "Resolving parameter '{0}' of constructor {1}";
|
public const string ConstructorArgumentResolveOperation = "Resolving parameter '{0}' of constructor {1}";
|
||||||
public const string ConstructorParameterResolutionFailed = "The parameter {0} could not be resolved when attempting to call constructor {1}.";
|
public const string ConstructorParameterResolutionFailed = "The parameter {0} could not be resolved when attempting to call constructor {1}.";
|
||||||
|
@ -32,6 +31,7 @@ namespace Unity
|
||||||
public const string MissingDependency = "Could not resolve dependency for build key {0}.";
|
public const string MissingDependency = "Could not resolve dependency for build key {0}.";
|
||||||
public const string MultipleInjectionConstructors = "The type {0} has multiple constructors marked with the InjectionConstructor attribute. Unable to disambiguate.";
|
public const string MultipleInjectionConstructors = "The type {0} has multiple constructors marked with the InjectionConstructor attribute. Unable to disambiguate.";
|
||||||
public const string MustHaveOpenGenericType = "The supplied type {0} must be an open generic type.";
|
public const string MustHaveOpenGenericType = "The supplied type {0} must be an open generic type.";
|
||||||
|
public const string MustHaveOpenArrayType = "The supplied type {0} must be an array type.";
|
||||||
public const string MustHaveSameNumberOfGenericArguments = "The supplied type {0} does not have the same number of generic arguments as the target type {1}.";
|
public const string MustHaveSameNumberOfGenericArguments = "The supplied type {0} does not have the same number of generic arguments as the target type {1}.";
|
||||||
public const string NoConstructorFound = "The type {0} does not have an accessible constructor.";
|
public const string NoConstructorFound = "The type {0} does not have an accessible constructor.";
|
||||||
public const string NoMatchingGenericArgument = "The type {0} does not have a generic argument named '{1}'";
|
public const string NoMatchingGenericArgument = "The type {0} does not have a generic argument named '{1}'";
|
||||||
|
|
|
@ -0,0 +1,78 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Unity.Utility
|
||||||
|
{
|
||||||
|
internal static class HashHelpers
|
||||||
|
{
|
||||||
|
// Table of prime numbers to use as hash table sizes.
|
||||||
|
public static readonly int[] Primes = {
|
||||||
|
1, 3, 7, 11, 17, 23, 29, 37, 47, 59, 71, 89, 107, 131, 163, 197, 239, 293, 353, 431, 521, 631, 761, 919,
|
||||||
|
1103, 1327, 1597, 1931, 2333, 2801, 3371, 4049, 4861, 5839, 7013, 8419, 10103, 12143, 14591,
|
||||||
|
17519, 21023, 25229, 30293, 36353, 43627, 52361, 62851, 75431, 90523, 108631, 130363, 156437,
|
||||||
|
187751, 225307, 270371, 324449, 389357, 467237, 560689, 672827, 807403, 968897, 1162687, 1395263,
|
||||||
|
1674319, 2009191, 2411033, 2893249, 3471899, 4166287, 4999559, 5999471, 7199369};
|
||||||
|
|
||||||
|
internal const Int32 HashPrime = 101;
|
||||||
|
|
||||||
|
|
||||||
|
public static bool IsPrime(int candidate)
|
||||||
|
{
|
||||||
|
if ((candidate & 1) != 0)
|
||||||
|
{
|
||||||
|
int limit = (int)Math.Sqrt(candidate);
|
||||||
|
for (int divisor = 3; divisor <= limit; divisor += 2)
|
||||||
|
{
|
||||||
|
if ((candidate % divisor) == 0)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return (candidate == 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int GetPrime(int min)
|
||||||
|
{
|
||||||
|
if (min < 0)
|
||||||
|
throw new ArgumentException("Capacity Overflow");
|
||||||
|
|
||||||
|
for (int i = 0; i < Primes.Length; i++)
|
||||||
|
{
|
||||||
|
int prime = Primes[i];
|
||||||
|
if (prime >= min) return prime;
|
||||||
|
}
|
||||||
|
|
||||||
|
//outside of our predefined table.
|
||||||
|
//compute the hard way.
|
||||||
|
for (int i = (min | 1); i < Int32.MaxValue; i += 2)
|
||||||
|
{
|
||||||
|
if (IsPrime(i) && ((i - 1) % HashPrime != 0))
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
return min;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int GetMinPrime()
|
||||||
|
{
|
||||||
|
return Primes[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns size of hashtable to grow to.
|
||||||
|
public static int ExpandPrime(int oldSize)
|
||||||
|
{
|
||||||
|
int newSize = 2 * oldSize;
|
||||||
|
|
||||||
|
// Allow the hashtables to grow to maximum possible size (~2G elements) before encoutering capacity overflow.
|
||||||
|
// Note that this check works even when _items.Length overflowed thanks to the (uint) cast
|
||||||
|
if ((uint)newSize > MaxPrimeArrayLength && MaxPrimeArrayLength > oldSize)
|
||||||
|
{
|
||||||
|
return MaxPrimeArrayLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
return GetPrime(newSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// This is the maximum prime smaller than Array.MaxArrayLength
|
||||||
|
public const int MaxPrimeArrayLength = 0x7FEFFFFD;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,39 +1,11 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Security.Cryptography;
|
|
||||||
using BenchmarkDotNet.Attributes;
|
|
||||||
using BenchmarkDotNet.Attributes.Jobs;
|
|
||||||
using BenchmarkDotNet.Running;
|
|
||||||
|
|
||||||
namespace MyBenchmarks
|
namespace Performance
|
||||||
{
|
{
|
||||||
[ClrJob]
|
class Program
|
||||||
[BenchmarkCategory("Collections")]
|
|
||||||
public class Md5VsSha256
|
|
||||||
{
|
{
|
||||||
private const int N = 10000;
|
static void Main(string[] args)
|
||||||
private readonly byte[] data;
|
|
||||||
|
|
||||||
private readonly SHA256 sha256 = SHA256.Create();
|
|
||||||
private readonly MD5 md5 = MD5.Create();
|
|
||||||
|
|
||||||
public Md5VsSha256()
|
|
||||||
{
|
{
|
||||||
data = new byte[N];
|
|
||||||
new Random(42).NextBytes(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Benchmark]
|
|
||||||
public byte[] Sha256() => sha256.ComputeHash(data);
|
|
||||||
|
|
||||||
[Benchmark]
|
|
||||||
public byte[] Md5() => md5.ComputeHash(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Program
|
|
||||||
{
|
|
||||||
public static void Main(string[] args)
|
|
||||||
{
|
|
||||||
var summary = BenchmarkRunner.Run<Md5VsSha256>();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,27 +5,14 @@
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<TargetFramework>net47</TargetFramework>
|
<TargetFramework>net47</TargetFramework>
|
||||||
|
<UnityAbstractions>..\..\..\Abstractions\src\Unity.Abstractions.csproj</UnityAbstractions>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<Compile Remove="BenchmarkDotNet.Artifacts\**" />
|
|
||||||
<EmbeddedResource Remove="BenchmarkDotNet.Artifacts\**" />
|
|
||||||
<None Remove="BenchmarkDotNet.Artifacts\**" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="BenchmarkDotNet" Version="0.10.11" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\..\src\Unity.Container.csproj" />
|
<ProjectReference Include="..\..\src\Unity.Container.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<UnityAbstractions>..\..\..\Abstractions\src\Unity.Abstractions.csproj</UnityAbstractions>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup Condition="Exists('$(UnityAbstractions)')">
|
<ItemGroup Condition="Exists('$(UnityAbstractions)')">
|
||||||
<ProjectReference Include="$(UnityAbstractions)" />
|
<ProjectReference Include="$(UnityAbstractions)" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
|
||||||
|
namespace Unity.Specification
|
||||||
|
{
|
||||||
|
[TestClass]
|
||||||
|
public class ResolutionTestFixture : Resolution.SpecificationTests
|
||||||
|
{
|
||||||
|
public override IUnityContainer GetContainer()
|
||||||
|
{
|
||||||
|
return new UnityContainer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,377 +0,0 @@
|
||||||
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
|
||||||
using Microsoft.Practices.Unity;
|
|
||||||
using Microsoft.Practices.Unity.TestSupport;
|
|
||||||
using Microsoft.Practices.Unity.Utility;
|
|
||||||
using Unity.Exceptions;
|
|
||||||
using Unity.Lifetime;
|
|
||||||
|
|
||||||
namespace Unity.Tests.ChildContainer
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Summary description for UnityChildContainers
|
|
||||||
/// </summary>
|
|
||||||
[TestClass]
|
|
||||||
public class ChildContainerFixture
|
|
||||||
{
|
|
||||||
[TestMethod]
|
|
||||||
public void CreateChildUsingParentsConfiguration()
|
|
||||||
{
|
|
||||||
UnityContainer parent = new UnityContainer();
|
|
||||||
parent.RegisterType<ITemporary, Temporary>();
|
|
||||||
IUnityContainer child = parent.CreateChildContainer();
|
|
||||||
|
|
||||||
ITemporary temp = child.Resolve<ITemporary>();
|
|
||||||
|
|
||||||
Assert.IsNotNull(temp);
|
|
||||||
Assert.IsInstanceOfType(temp, typeof(Temporary));
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public void NamesRegisteredInParentAppearInChild()
|
|
||||||
{
|
|
||||||
UnityContainer parent = new UnityContainer();
|
|
||||||
parent.RegisterType<ITemporary, SpecialTemp>("test");
|
|
||||||
IUnityContainer child = parent.CreateChildContainer();
|
|
||||||
|
|
||||||
ITemporary temp = child.Resolve<ITemporary>("test");
|
|
||||||
|
|
||||||
Assert.IsInstanceOfType(temp, typeof(SpecialTemp));
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public void NamesRegisteredInParentAppearInChildGetAll()
|
|
||||||
{
|
|
||||||
string[] numbers = { "first", "second", "third" };
|
|
||||||
UnityContainer parent = new UnityContainer();
|
|
||||||
parent.RegisterInstance(numbers[0], "first")
|
|
||||||
.RegisterInstance(numbers[1], "second");
|
|
||||||
|
|
||||||
IUnityContainer child = parent.CreateChildContainer()
|
|
||||||
.RegisterInstance(numbers[2], "third");
|
|
||||||
|
|
||||||
List<string> nums = new List<string>(child.ResolveAll<string>());
|
|
||||||
CollectionAssert.AreEquivalent(numbers, nums);
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public void ChildConfigurationOverridesParentConfiguration()
|
|
||||||
{
|
|
||||||
UnityContainer parent = new UnityContainer();
|
|
||||||
parent.RegisterType<ITemporary, Temporary>();
|
|
||||||
|
|
||||||
IUnityContainer child = parent.CreateChildContainer()
|
|
||||||
.RegisterType<ITemporary, SpecialTemp>();
|
|
||||||
|
|
||||||
ITemporary parentTemp = parent.Resolve<ITemporary>();
|
|
||||||
ITemporary childTemp = child.Resolve<ITemporary>();
|
|
||||||
|
|
||||||
Assert.IsInstanceOfType(parentTemp, typeof(Temporary));
|
|
||||||
Assert.IsInstanceOfType(childTemp, typeof(SpecialTemp));
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public void DisposingParentDisposesChild()
|
|
||||||
{
|
|
||||||
UnityContainer parent = new UnityContainer();
|
|
||||||
IUnityContainer child = parent.CreateChildContainer();
|
|
||||||
|
|
||||||
MyDisposableObject spy = new MyDisposableObject();
|
|
||||||
child.RegisterInstance(spy);
|
|
||||||
parent.Dispose();
|
|
||||||
|
|
||||||
Assert.IsTrue(spy.WasDisposed);
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public void CanDisposeChildWithoutDisposingParent()
|
|
||||||
{
|
|
||||||
MyDisposableObject parentSpy = new MyDisposableObject();
|
|
||||||
MyDisposableObject childSpy = new MyDisposableObject();
|
|
||||||
UnityContainer parent = new UnityContainer();
|
|
||||||
|
|
||||||
parent.RegisterInstance(parentSpy);
|
|
||||||
IUnityContainer child = parent.CreateChildContainer()
|
|
||||||
.RegisterInstance(childSpy);
|
|
||||||
child.Dispose();
|
|
||||||
|
|
||||||
Assert.IsFalse(parentSpy.WasDisposed);
|
|
||||||
Assert.IsTrue(childSpy.WasDisposed);
|
|
||||||
|
|
||||||
childSpy.WasDisposed = false;
|
|
||||||
parent.Dispose();
|
|
||||||
|
|
||||||
Assert.IsTrue(parentSpy.WasDisposed);
|
|
||||||
Assert.IsFalse(childSpy.WasDisposed);
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public void VerifyToList()
|
|
||||||
{
|
|
||||||
string[] numbers = { "first", "second", "third" };
|
|
||||||
UnityContainer parent = new UnityContainer();
|
|
||||||
|
|
||||||
parent.RegisterInstance(numbers[0], "first")
|
|
||||||
.RegisterInstance(numbers[1], "second");
|
|
||||||
IUnityContainer child = parent.CreateChildContainer()
|
|
||||||
.RegisterInstance(numbers[2], "third");
|
|
||||||
|
|
||||||
List<string> nums = new List<string>(child.ResolveAll<string>());
|
|
||||||
CollectionAssert.AreEquivalent(numbers, nums);
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public void ChangesInParentReflectsInChild()
|
|
||||||
{
|
|
||||||
string[] numbers = { "first", "second", "third", "fourth" };
|
|
||||||
UnityContainer parent = new UnityContainer();
|
|
||||||
|
|
||||||
parent.RegisterInstance(numbers[0], "1")
|
|
||||||
.RegisterInstance(numbers[1], "2");
|
|
||||||
IUnityContainer child = parent.CreateChildContainer();
|
|
||||||
|
|
||||||
List<string> childnums = new List<string>(child.ResolveAll<string>());
|
|
||||||
List<string> parentnums = new List<string>(parent.ResolveAll<string>());
|
|
||||||
|
|
||||||
CollectionAssert.AreEquivalent(childnums, parentnums);
|
|
||||||
|
|
||||||
parent.RegisterInstance(numbers[3], "4"); //Register an instance in Parent but not in child
|
|
||||||
|
|
||||||
List<string> childnums2 = new List<string>(child.ResolveAll<string>());
|
|
||||||
List<string> parentnums2 = new List<string>(parent.ResolveAll<string>());
|
|
||||||
|
|
||||||
CollectionAssert.AreEquivalent(childnums2, parentnums2); //Both parent child should have same instances
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public void DuplicateRegInParentAndChild()
|
|
||||||
{
|
|
||||||
string[] numbers = { "first", "second", "third", "fourth" };
|
|
||||||
|
|
||||||
UnityContainer parent = new UnityContainer();
|
|
||||||
parent.RegisterInstance(numbers[0], "1")
|
|
||||||
.RegisterInstance(numbers[1], "2");
|
|
||||||
|
|
||||||
IUnityContainer child = parent.CreateChildContainer();
|
|
||||||
|
|
||||||
List<string> childnums = new List<string>(child.ResolveAll<string>());
|
|
||||||
List<string> parentnums = new List<string>(parent.ResolveAll<string>());
|
|
||||||
|
|
||||||
CollectionAssert.AreEquivalent(childnums, parentnums);
|
|
||||||
|
|
||||||
parent.RegisterInstance(numbers[3], "4");
|
|
||||||
child.RegisterInstance(numbers[3], "4");
|
|
||||||
|
|
||||||
List<string> childnums2 = new List<string>(child.ResolveAll<string>());
|
|
||||||
List<string> parentnums2 = new List<string>(parent.ResolveAll<string>());
|
|
||||||
|
|
||||||
CollectionAssert.AreEquivalent(childnums2, parentnums2); //Both parent child should have same instances
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public void VerifyArgumentNullException()
|
|
||||||
{
|
|
||||||
string[] numbers = { "first", "second", "third" };
|
|
||||||
|
|
||||||
UnityContainer parent = new UnityContainer();
|
|
||||||
parent.RegisterInstance("1", numbers[0])
|
|
||||||
.RegisterInstance("2", numbers[1]);
|
|
||||||
IUnityContainer child = parent.CreateChildContainer()
|
|
||||||
.RegisterInstance("3", numbers[2]);
|
|
||||||
|
|
||||||
List<string> nums = new List<string>(child.ResolveAll<string>());
|
|
||||||
|
|
||||||
AssertHelper.ThrowsException<ArgumentNullException>(() => Guard.ArgumentNotNull(null, String.Empty));
|
|
||||||
|
|
||||||
CollectionAssert.AreEquivalent(numbers, nums);
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public void CreateParentChildContainersWithSameName()
|
|
||||||
{
|
|
||||||
IUnityContainer parent = new UnityContainer();
|
|
||||||
|
|
||||||
parent.RegisterType<ITemporary, Temp>("First");
|
|
||||||
parent = (UnityContainer)parent.CreateChildContainer();
|
|
||||||
parent.RegisterType<ITemporary, Temp>("First");
|
|
||||||
|
|
||||||
List<ITemporary> count = new List<ITemporary>(parent.ResolveAll<ITemporary>());
|
|
||||||
|
|
||||||
Assert.AreEqual(1, count.Count);
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public void MoreChildContainers1()
|
|
||||||
{
|
|
||||||
UnityContainer parent = new UnityContainer();
|
|
||||||
|
|
||||||
parent.RegisterType<ITemporary, Temp>("First");
|
|
||||||
parent.RegisterType<ITemporary, Temp>("First");
|
|
||||||
UnityContainer child1 = (UnityContainer)parent.CreateChildContainer();
|
|
||||||
child1.RegisterType<ITemporary, Temp>("First");
|
|
||||||
child1.RegisterType<ITemporary, Temp>("First");
|
|
||||||
UnityContainer child2 = (UnityContainer)child1.CreateChildContainer();
|
|
||||||
child2.RegisterType<ITemporary, Temp>("First");
|
|
||||||
child2.RegisterType<ITemporary, Temp>("First");
|
|
||||||
UnityContainer child3 = (UnityContainer)child2.CreateChildContainer();
|
|
||||||
child3.RegisterType<ITemporary, Temp>("First");
|
|
||||||
child3.RegisterType<ITemporary, Temp>("First");
|
|
||||||
IUnityContainer child4 = child3.CreateChildContainer();
|
|
||||||
child4.RegisterType<ITemporary, Temp>("First");
|
|
||||||
ITemporary first = child4.Resolve<ITemporary>("First");
|
|
||||||
|
|
||||||
child4.RegisterType<ITemporary, Temp>("First", new ContainerControlledLifetimeManager());
|
|
||||||
List<ITemporary> count = new List<ITemporary>(child4.ResolveAll<ITemporary>());
|
|
||||||
|
|
||||||
Assert.AreEqual(1, count.Count);
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public void MoreChildContainers2()
|
|
||||||
{
|
|
||||||
UnityContainer parent = new UnityContainer();
|
|
||||||
parent.RegisterType<ITemporary, Temp>("First", new HierarchicalLifetimeManager());
|
|
||||||
|
|
||||||
UnityContainer child1 = (UnityContainer)parent.CreateChildContainer();
|
|
||||||
child1.RegisterType<ITemporary, Temp>("First", new HierarchicalLifetimeManager());
|
|
||||||
var result = parent.Resolve<ITemporary>("First");
|
|
||||||
var result1 = child1.Resolve<ITemporary>("First");
|
|
||||||
|
|
||||||
Assert.AreNotEqual<int>(result.GetHashCode(), result1.GetHashCode());
|
|
||||||
|
|
||||||
UnityContainer child2 = (UnityContainer)child1.CreateChildContainer();
|
|
||||||
child2.RegisterType<ITemporary, Temp>("First", new HierarchicalLifetimeManager());
|
|
||||||
var result2 = child2.Resolve<ITemporary>("First");
|
|
||||||
|
|
||||||
Assert.AreNotEqual<int>(result.GetHashCode(), result2.GetHashCode());
|
|
||||||
Assert.AreNotEqual<int>(result1.GetHashCode(), result2.GetHashCode());
|
|
||||||
|
|
||||||
List<ITemporary> count = new List<ITemporary>(child2.ResolveAll<ITemporary>());
|
|
||||||
|
|
||||||
Assert.AreEqual(1, count.Count);
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public void GetObjectAfterDispose()
|
|
||||||
{
|
|
||||||
UnityContainer parent = new UnityContainer();
|
|
||||||
parent.RegisterType<Temp>("First", new ContainerControlledLifetimeManager());
|
|
||||||
|
|
||||||
IUnityContainer child = parent.CreateChildContainer();
|
|
||||||
child.RegisterType<ITemporary>("First", new ContainerControlledLifetimeManager());
|
|
||||||
parent.Dispose();
|
|
||||||
AssertHelper.ThrowsException<ResolutionFailedException>(() => child.Resolve<ITemporary>("First"));
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public void VerifyArgumentNotNullOrEmpty()
|
|
||||||
{
|
|
||||||
string[] numbers = { "first", "second", "third" };
|
|
||||||
|
|
||||||
UnityContainer parent = new UnityContainer();
|
|
||||||
parent.RegisterInstance("1", numbers[0])
|
|
||||||
.RegisterInstance("2", numbers[1]);
|
|
||||||
IUnityContainer child = parent.CreateChildContainer()
|
|
||||||
.RegisterInstance("3", numbers[2]);
|
|
||||||
List<string> nums = new List<string>(child.ResolveAll<string>());
|
|
||||||
|
|
||||||
AssertHelper.ThrowsException<ArgumentException>(() => Guard.ArgumentNotNullOrEmpty(String.Empty, String.Empty));
|
|
||||||
|
|
||||||
CollectionAssert.AreEquivalent(numbers, nums);
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public void VerifyArgumentNotNullOrEmpty1()
|
|
||||||
{
|
|
||||||
string[] numbers = { "first", "second", "third" };
|
|
||||||
|
|
||||||
UnityContainer parent = new UnityContainer();
|
|
||||||
parent.RegisterInstance("1", numbers[0])
|
|
||||||
.RegisterInstance("2", numbers[1]);
|
|
||||||
IUnityContainer child = parent.CreateChildContainer()
|
|
||||||
.RegisterInstance("3", numbers[2]);
|
|
||||||
List<string> nums = new List<string>(child.ResolveAll<string>());
|
|
||||||
|
|
||||||
AssertHelper.ThrowsException<ArgumentNullException>(() => Guard.ArgumentNotNullOrEmpty(null, null));
|
|
||||||
|
|
||||||
CollectionAssert.AreEquivalent(numbers, nums);
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public void VerifyArgumentNotNullOrEmpty2()
|
|
||||||
{
|
|
||||||
string[] numbers = { "first", "second", "third" };
|
|
||||||
|
|
||||||
UnityContainer parent = new UnityContainer();
|
|
||||||
parent.RegisterInstance("1", numbers[0])
|
|
||||||
.RegisterInstance("2", numbers[1]);
|
|
||||||
IUnityContainer child = parent.CreateChildContainer()
|
|
||||||
.RegisterInstance("3", numbers[2]);
|
|
||||||
List<string> nums = new List<string>(child.ResolveAll<string>());
|
|
||||||
|
|
||||||
Guard.ArgumentNotNullOrEmpty("first", "numbers");
|
|
||||||
|
|
||||||
CollectionAssert.AreEquivalent(numbers, nums);
|
|
||||||
}
|
|
||||||
|
|
||||||
//bug # 3978 http://unity.codeplex.com/WorkItem/View.aspx?WorkItemId=6053
|
|
||||||
[TestMethod]
|
|
||||||
public void ChildParentRegisrationOverlapTest()
|
|
||||||
{
|
|
||||||
IUnityContainer container = new UnityContainer();
|
|
||||||
|
|
||||||
container.RegisterInstance("str1", "string1");
|
|
||||||
container.RegisterInstance("str2", "string2");
|
|
||||||
|
|
||||||
IUnityContainer child = container.CreateChildContainer();
|
|
||||||
|
|
||||||
child.RegisterInstance("str2", "string20");
|
|
||||||
child.RegisterInstance("str3", "string30");
|
|
||||||
|
|
||||||
var childStrList = child.ResolveAll<string>();
|
|
||||||
var parentStrList = container.ResolveAll<string>();
|
|
||||||
string childString = String.Empty;
|
|
||||||
string parentString = String.Empty;
|
|
||||||
|
|
||||||
foreach (string str in childStrList) { childString = childString + str; }
|
|
||||||
foreach (string str1 in parentStrList) { parentString = parentString + str1; }
|
|
||||||
|
|
||||||
Assert.AreEqual<string>("string1string20string30", childString);
|
|
||||||
Assert.AreEqual<string>("string1string2", parentString);
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface ITemporary
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Temp : ITemporary
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Temporary : ITemporary
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public class SpecialTemp : ITemporary //Second level
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public class MyDisposableObject : IDisposable
|
|
||||||
{
|
|
||||||
private bool wasDisposed = false;
|
|
||||||
|
|
||||||
public bool WasDisposed
|
|
||||||
{
|
|
||||||
get { return wasDisposed; }
|
|
||||||
set { wasDisposed = value; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
wasDisposed = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -199,24 +199,24 @@ namespace Unity.Tests.ChildContainer
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void ChainOfContainers()
|
public void ChainOfContainers()
|
||||||
{
|
{
|
||||||
UnityContainer parent = new UnityContainer();
|
var parent = new UnityContainer();
|
||||||
IUnityContainer child = parent.CreateChildContainer();
|
var child1 = parent.CreateChildContainer();
|
||||||
IUnityContainer child2 = child.CreateChildContainer();
|
var child2 = child1.CreateChildContainer();
|
||||||
IUnityContainer child3 = child2.CreateChildContainer();
|
var child3 = child2.CreateChildContainer();
|
||||||
|
|
||||||
TestContainer obj1 = new TestContainer();
|
var obj1 = new TestContainer();
|
||||||
|
|
||||||
parent.RegisterInstance<TestContainer>("InParent", obj1);
|
parent.RegisterInstance("InParent", obj1);
|
||||||
child.RegisterInstance<TestContainer>("InChild", obj1);
|
child1.RegisterInstance("InChild1", obj1);
|
||||||
child2.RegisterInstance<TestContainer>("InChild2", obj1);
|
child2.RegisterInstance("InChild2", obj1);
|
||||||
child3.RegisterInstance<TestContainer>("InChild3", obj1);
|
child3.RegisterInstance("InChild3", obj1);
|
||||||
|
|
||||||
object objresolve = child3.Resolve<TestContainer>("InParent");
|
object objresolve = child3.Resolve<TestContainer>("InParent");
|
||||||
object objresolve1 = parent.Resolve<TestContainer>("InChild3");
|
object objresolve1 = parent.Resolve<TestContainer>("InChild3");
|
||||||
|
|
||||||
Assert.AreSame(obj1, objresolve);
|
Assert.AreSame(obj1, objresolve);
|
||||||
|
|
||||||
child.Dispose();
|
child1.Dispose();
|
||||||
|
|
||||||
//parent not getting disposed
|
//parent not getting disposed
|
||||||
Assert.IsTrue(obj1.WasDisposed);
|
Assert.IsTrue(obj1.WasDisposed);
|
||||||
|
|
|
@ -1,149 +0,0 @@
|
||||||
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
|
||||||
using Microsoft.Practices.Unity;
|
|
||||||
using Unity.Attributes;
|
|
||||||
|
|
||||||
namespace Unity.Tests
|
|
||||||
{
|
|
||||||
[TestClass]
|
|
||||||
public class ConstructorInjectionFixture
|
|
||||||
{
|
|
||||||
[TestMethod]
|
|
||||||
public void ConstPropInjectionSameClassTwice()
|
|
||||||
{
|
|
||||||
IUnityContainer uc = new UnityContainer();
|
|
||||||
uc.RegisterType<InjectTestClass2_Prop>()
|
|
||||||
.RegisterType<InjectTestClass_Prop>();
|
|
||||||
InjectTestClass2_Prop obj_test = uc.Resolve<InjectTestClass2_Prop>();
|
|
||||||
obj_test.Propertyfirst.NameInjectTestClassProp = "First";
|
|
||||||
obj_test.Propertysecond.NameInjectTestClassProp = "Second";
|
|
||||||
|
|
||||||
Assert.AreEqual("Second", obj_test.Propertysecond.NameInjectTestClassProp);
|
|
||||||
Assert.AreEqual("First", obj_test.Propertyfirst.NameInjectTestClassProp);
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]// log Bug
|
|
||||||
public void TestMethodwithParamaterAsInterface()
|
|
||||||
{
|
|
||||||
IUnityContainer uc = new UnityContainer();
|
|
||||||
uc.RegisterType<InjectionTestInterface, InjectionTestClass2>()
|
|
||||||
.RegisterType<InjectionTestInterface, InjectionTestClass2>("hi")
|
|
||||||
.RegisterType<InjectionTestInterface, InjectionTestClass1>()
|
|
||||||
.RegisterType<InjectionTestInterface, InjectionTestClass1>("hello");
|
|
||||||
|
|
||||||
InjectionTestInterface obj3 = uc.Resolve<InjectionTestInterface>("hi");
|
|
||||||
InjectionTestInterface obj2 = uc.Resolve<InjectionTestInterface>("hello");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// ConstructorInjectionFixture class used for property injection testing.
|
|
||||||
/// </summary>
|
|
||||||
public class InjectTestClass_Prop
|
|
||||||
{
|
|
||||||
private string nameInjectTestClassProp = "In InjectTestClass1_Prop";
|
|
||||||
|
|
||||||
public string NameInjectTestClassProp
|
|
||||||
{
|
|
||||||
get { return this.nameInjectTestClassProp; }
|
|
||||||
set { nameInjectTestClassProp = value; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// ConstructorInjectionFixture class used for injection.
|
|
||||||
/// </summary>
|
|
||||||
public class InjectTestClass2_Prop
|
|
||||||
{
|
|
||||||
public string Name = "In InjectTestClass2_Prop";
|
|
||||||
private InjectTestClass_Prop objinject1;
|
|
||||||
private InjectTestClass_Prop objinject2;
|
|
||||||
|
|
||||||
public InjectTestClass_Prop Propertyfirst
|
|
||||||
{
|
|
||||||
get { return objinject1; }
|
|
||||||
set { objinject1 = value; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public InjectTestClass_Prop Propertysecond
|
|
||||||
{
|
|
||||||
get { return objinject2; }
|
|
||||||
set { objinject2 = value; }
|
|
||||||
}
|
|
||||||
|
|
||||||
//InjectTestClass_Prop objinject1_created, InjectTestClass_Prop objinject2_created
|
|
||||||
[InjectionConstructor]
|
|
||||||
public InjectTestClass2_Prop(InjectTestClass_Prop objinject1_created, InjectTestClass_Prop objinject2_created)
|
|
||||||
{
|
|
||||||
objinject1 = objinject1_created;
|
|
||||||
objinject2 = objinject2_created;
|
|
||||||
objinject1.NameInjectTestClassProp = "First time call";
|
|
||||||
objinject2.NameInjectTestClassProp = "Second time call";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#region InjectClass
|
|
||||||
|
|
||||||
public interface InjectionTestInterface
|
|
||||||
{
|
|
||||||
string Text
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
set;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class InjectionTestClass : InjectionTestInterface
|
|
||||||
{
|
|
||||||
private string name = "InjectionTestClass";
|
|
||||||
public string Name
|
|
||||||
{
|
|
||||||
get { return this.name; }
|
|
||||||
set { this.name = value; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public string Text
|
|
||||||
{
|
|
||||||
get { return this.name; }
|
|
||||||
set { this.name = value; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class InjectionTestClass1 : InjectionTestInterface
|
|
||||||
{
|
|
||||||
private string name = "InjectionTestClass1";
|
|
||||||
|
|
||||||
public string Name
|
|
||||||
{
|
|
||||||
get { return this.name; }
|
|
||||||
set { this.name = value; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public string Text
|
|
||||||
{
|
|
||||||
get { return this.name; }
|
|
||||||
set { this.name = value; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class InjectionTestClass2 : InjectionTestInterface
|
|
||||||
{
|
|
||||||
private string name = "InjectionTestClass2";
|
|
||||||
private InjectionTestInterface intobj;
|
|
||||||
|
|
||||||
public InjectionTestClass2(InjectionTestInterface intobj1)
|
|
||||||
{
|
|
||||||
this.intobj = intobj1;
|
|
||||||
intobj1.Text = "Hello";
|
|
||||||
}
|
|
||||||
|
|
||||||
public string Text
|
|
||||||
{
|
|
||||||
get { return this.name; }
|
|
||||||
set { this.name = value; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion InjectClass
|
|
||||||
}
|
|
|
@ -1,12 +1,12 @@
|
||||||
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
|
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Microsoft.Practices.Unity;
|
|
||||||
using Microsoft.Practices.Unity.TestSupport;
|
using Microsoft.Practices.Unity.TestSupport;
|
||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
using Unity.Exceptions;
|
using Unity.Exceptions;
|
||||||
|
|
||||||
namespace Unity.Tests
|
namespace Unity.Tests.Container
|
||||||
{
|
{
|
||||||
[TestClass]
|
[TestClass]
|
||||||
public class ContainerBasicFixture
|
public class ContainerBasicFixture
|
|
@ -1,12 +1,12 @@
|
||||||
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
|
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using Microsoft.Practices.Unity;
|
|
||||||
using Microsoft.Practices.Unity.TestSupport;
|
using Microsoft.Practices.Unity.TestSupport;
|
||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
using Unity.Attributes;
|
using Unity.Attributes;
|
||||||
using Unity.Exceptions;
|
using Unity.Exceptions;
|
||||||
|
|
||||||
namespace Unity.Tests
|
namespace Unity.Tests.Container
|
||||||
{
|
{
|
||||||
[TestClass]
|
[TestClass]
|
||||||
public class ContainerBuildUpFixture
|
public class ContainerBuildUpFixture
|
|
@ -2,16 +2,14 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using Microsoft.Practices.ObjectBuilder2;
|
|
||||||
using Microsoft.Practices.Unity.Tests.TestDoubles;
|
using Microsoft.Practices.Unity.Tests.TestDoubles;
|
||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
using Unity;
|
|
||||||
using Unity.Builder;
|
using Unity.Builder;
|
||||||
using Unity.Builder.Strategy;
|
using Unity.Builder.Strategy;
|
||||||
using Unity.Exceptions;
|
using Unity.Exceptions;
|
||||||
using Unity.Lifetime;
|
using Unity.Lifetime;
|
||||||
|
|
||||||
namespace Microsoft.Practices.Unity.Tests
|
namespace Unity.Tests.Container
|
||||||
{
|
{
|
||||||
// Test for a race condition in the ContainerControlledLifetime
|
// Test for a race condition in the ContainerControlledLifetime
|
||||||
// class.
|
// class.
|
||||||
|
@ -21,9 +19,9 @@ namespace Microsoft.Practices.Unity.Tests
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void ContainerControlledLifetimeReturnsSameInstanceFromMultipleThreads()
|
public void ContainerControlledLifetimeReturnsSameInstanceFromMultipleThreads()
|
||||||
{
|
{
|
||||||
IUnityContainer container = new UnityContainer()
|
IUnityContainer container = new UnityContainer();
|
||||||
.AddExtension(new SpyExtension(new DelayStrategy(), UnityBuildStage.Lifetime))
|
container.AddExtension(new SpyExtension(new DelayStrategy(), UnityBuildStage.Lifetime));
|
||||||
.RegisterType<object>(new ContainerControlledLifetimeManager());
|
container.RegisterType<object>(new ContainerControlledLifetimeManager());
|
||||||
|
|
||||||
object result1 = null;
|
object result1 = null;
|
||||||
object result2 = null;
|
object result2 = null;
|
||||||
|
@ -38,6 +36,9 @@ namespace Microsoft.Practices.Unity.Tests
|
||||||
result2 = container.Resolve<object>();
|
result2 = container.Resolve<object>();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
thread1.Name = "1";
|
||||||
|
thread2.Name = "2";
|
||||||
|
|
||||||
thread1.Start();
|
thread1.Start();
|
||||||
thread2.Start();
|
thread2.Start();
|
||||||
|
|
||||||
|
@ -119,6 +120,7 @@ namespace Microsoft.Practices.Unity.Tests
|
||||||
this.shouldThrow = false;
|
this.shouldThrow = false;
|
||||||
throw new Exception("Throwing from buildup chain");
|
throw new Exception("Throwing from buildup chain");
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,9 +1,9 @@
|
||||||
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
|
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
|
||||||
using Microsoft.Practices.Unity;
|
|
||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
using Unity.Attributes;
|
using Unity.Attributes;
|
||||||
|
|
||||||
namespace Unity.Tests
|
namespace Unity.Tests.Container
|
||||||
{
|
{
|
||||||
[TestClass]
|
[TestClass]
|
||||||
public class ContainerDefaultContentFixture
|
public class ContainerDefaultContentFixture
|
|
@ -1,15 +1,12 @@
|
||||||
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
|
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using Microsoft.Practices.Unity.Tests.TestDoubles;
|
using Microsoft.Practices.Unity.Tests.TestDoubles;
|
||||||
|
using Microsoft.Practices.Unity.TestSupport;
|
||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
using Unity;
|
|
||||||
using Unity.Builder;
|
using Unity.Builder;
|
||||||
using Unity.Extension;
|
using Unity.Extension;
|
||||||
using Unity.Tests.TestDoubles;
|
|
||||||
using IMockConfiguration = Microsoft.Practices.Unity.TestSupport.IMockConfiguration;
|
|
||||||
using MockContainerExtension = Microsoft.Practices.Unity.TestSupport.MockContainerExtension;
|
|
||||||
|
|
||||||
namespace Microsoft.Practices.Unity.Tests
|
namespace Unity.Tests
|
||||||
{
|
{
|
||||||
[TestClass]
|
[TestClass]
|
||||||
public class UnityExtensionFixture
|
public class UnityExtensionFixture
|
|
@ -4,11 +4,9 @@ using System.Collections.Generic;
|
||||||
using Microsoft.Practices.Unity.Tests.TestObjects;
|
using Microsoft.Practices.Unity.Tests.TestObjects;
|
||||||
using Microsoft.Practices.Unity.TestSupport;
|
using Microsoft.Practices.Unity.TestSupport;
|
||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
using Unity;
|
|
||||||
using Unity.Injection;
|
using Unity.Injection;
|
||||||
using Unity.Tests.TestSupport;
|
|
||||||
|
|
||||||
namespace Microsoft.Practices.Unity.Tests
|
namespace Unity.Tests
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Tests for the hierarchical features of the UnityContainer.
|
/// Tests for the hierarchical features of the UnityContainer.
|
||||||
|
@ -19,11 +17,11 @@ namespace Microsoft.Practices.Unity.Tests
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void ChildBuildsUsingParentsConfiguration()
|
public void ChildBuildsUsingParentsConfiguration()
|
||||||
{
|
{
|
||||||
UnityContainer parent = new UnityContainer();
|
var parent = new UnityContainer();
|
||||||
parent.RegisterType<ILogger, MockLogger>();
|
parent.RegisterType<ILogger, MockLogger>();
|
||||||
|
|
||||||
IUnityContainer child = parent.CreateChildContainer();
|
var child = parent.CreateChildContainer();
|
||||||
ILogger logger = child.Resolve<ILogger>();
|
var logger = child.Resolve<ILogger>();
|
||||||
|
|
||||||
Assert.IsNotNull(logger);
|
Assert.IsNotNull(logger);
|
||||||
AssertExtensions.IsInstanceOfType(logger, typeof(MockLogger));
|
AssertExtensions.IsInstanceOfType(logger, typeof(MockLogger));
|
||||||
|
@ -47,11 +45,11 @@ namespace Microsoft.Practices.Unity.Tests
|
||||||
{
|
{
|
||||||
string[] databases = { "northwind", "adventureworks", "fabrikam" };
|
string[] databases = { "northwind", "adventureworks", "fabrikam" };
|
||||||
UnityContainer parent = new UnityContainer();
|
UnityContainer parent = new UnityContainer();
|
||||||
parent.RegisterInstance<string>("nwnd", databases[0])
|
parent.RegisterInstance("nwnd", databases[0])
|
||||||
.RegisterInstance<string>("advwks", databases[1]);
|
.RegisterInstance("advwks", databases[1]);
|
||||||
|
|
||||||
IUnityContainer child = parent.CreateChildContainer()
|
IUnityContainer child = parent.CreateChildContainer()
|
||||||
.RegisterInstance<string>("fbkm", databases[2]);
|
.RegisterInstance("fbkm", databases[2]);
|
||||||
|
|
||||||
List<string> dbs = new List<string>(child.ResolveAll<string>());
|
List<string> dbs = new List<string>(child.ResolveAll<string>());
|
||||||
CollectionAssertExtensions.AreEquivalent(databases, dbs);
|
CollectionAssertExtensions.AreEquivalent(databases, dbs);
|
||||||
|
@ -114,7 +112,7 @@ namespace Microsoft.Practices.Unity.Tests
|
||||||
IUnityContainer child = parent.CreateChildContainer();
|
IUnityContainer child = parent.CreateChildContainer();
|
||||||
|
|
||||||
DisposableObject spy = new DisposableObject();
|
DisposableObject spy = new DisposableObject();
|
||||||
child.RegisterInstance<DisposableObject>(spy);
|
child.RegisterInstance(spy);
|
||||||
|
|
||||||
parent.Dispose();
|
parent.Dispose();
|
||||||
Assert.IsTrue(spy.WasDisposed);
|
Assert.IsTrue(spy.WasDisposed);
|
|
@ -1,156 +0,0 @@
|
||||||
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using Microsoft.Practices.Unity.TestSupport;
|
|
||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
|
||||||
using Unity;
|
|
||||||
|
|
||||||
namespace Microsoft.Practices.Unity.Tests
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Summary description for ContainerRegistrationsFixture
|
|
||||||
/// </summary>
|
|
||||||
[TestClass]
|
|
||||||
public class ContainerRegistrationsFixture
|
|
||||||
{
|
|
||||||
private IUnityContainer container;
|
|
||||||
|
|
||||||
[TestInitialize]
|
|
||||||
public void Setup()
|
|
||||||
{
|
|
||||||
container = new UnityContainer();
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public void ContainerListsItselfAsRegistered()
|
|
||||||
{
|
|
||||||
Assert.IsTrue(container.IsRegistered(typeof(IUnityContainer)));
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public void ContainerDoesNotListItselfUnderNonDefaultName()
|
|
||||||
{
|
|
||||||
Assert.IsFalse(container.IsRegistered(typeof(IUnityContainer), "other"));
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public void ContainerListsItselfAsRegisteredUsingGenericOverload()
|
|
||||||
{
|
|
||||||
Assert.IsTrue(container.IsRegistered<IUnityContainer>());
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public void ContainerDoesNotListItselfUnderNonDefaultNameUsingGenericOverload()
|
|
||||||
{
|
|
||||||
Assert.IsFalse(container.IsRegistered<IUnityContainer>("other"));
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public void IsRegisteredWorksForRegisteredType()
|
|
||||||
{
|
|
||||||
container.RegisterType<ILogger, MockLogger>();
|
|
||||||
|
|
||||||
Assert.IsTrue(container.IsRegistered<ILogger>());
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public void ContainerIncludesItselfUnderRegistrations()
|
|
||||||
{
|
|
||||||
Assert.IsNotNull(container.Registrations.Where(r => r.RegisteredType == typeof(IUnityContainer)).FirstOrDefault());
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public void NewRegistrationsShowUpInRegistrationsSequence()
|
|
||||||
{
|
|
||||||
container.RegisterType<ILogger, MockLogger>()
|
|
||||||
.RegisterType<ILogger, MockLogger>("second");
|
|
||||||
|
|
||||||
var registrations = (from r in container.Registrations
|
|
||||||
where r.RegisteredType == typeof(ILogger)
|
|
||||||
select r).ToList();
|
|
||||||
|
|
||||||
Assert.AreEqual(2, registrations.Count);
|
|
||||||
|
|
||||||
Assert.IsTrue(registrations.Any(r => r.Name == null));
|
|
||||||
Assert.IsTrue(registrations.Any(r => r.Name == "second"));
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public void TypeMappingShowsUpInRegistrationsCorrectly()
|
|
||||||
{
|
|
||||||
container.RegisterType<ILogger, MockLogger>();
|
|
||||||
|
|
||||||
var registration =
|
|
||||||
(from r in container.Registrations where r.RegisteredType == typeof(ILogger) select r).First();
|
|
||||||
Assert.AreSame(typeof(MockLogger), registration.MappedToType);
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public void NonMappingRegistrationShowsUpInRegistrationsSequence()
|
|
||||||
{
|
|
||||||
container.RegisterType<MockLogger>();
|
|
||||||
var registration = (from r in container.Registrations
|
|
||||||
where r.RegisteredType == typeof(MockLogger)
|
|
||||||
select r).First();
|
|
||||||
|
|
||||||
Assert.AreSame(registration.RegisteredType, registration.MappedToType);
|
|
||||||
Assert.IsNull(registration.Name);
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public void RegistrationOfOpenGenericTypeShowsUpInRegistrationsSequence()
|
|
||||||
{
|
|
||||||
container.RegisterType(typeof(IDictionary<,>), typeof(Dictionary<,>), "test");
|
|
||||||
var registration = container.Registrations.First(r => r.RegisteredType == typeof(IDictionary<,>));
|
|
||||||
|
|
||||||
Assert.AreSame(typeof(Dictionary<,>), registration.MappedToType);
|
|
||||||
Assert.AreEqual("test", registration.Name);
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public void RegistrationsInParentContainerAppearInChild()
|
|
||||||
{
|
|
||||||
container.RegisterType<ILogger, MockLogger>();
|
|
||||||
var child = container.CreateChildContainer();
|
|
||||||
|
|
||||||
var registration =
|
|
||||||
(from r in child.Registrations where r.RegisteredType == typeof(ILogger) select r).First();
|
|
||||||
|
|
||||||
Assert.AreSame(typeof(MockLogger), registration.MappedToType);
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public void RegistrationsInChildContainerDoNotAppearInParent()
|
|
||||||
{
|
|
||||||
var child = container.CreateChildContainer()
|
|
||||||
.RegisterType<ILogger, MockLogger>("named");
|
|
||||||
|
|
||||||
var childRegistration = child.Registrations.Where(r => r.RegisteredType == typeof(ILogger)).First();
|
|
||||||
var parentRegistration =
|
|
||||||
container.Registrations.Where(r => r.RegisteredType == typeof(ILogger)).FirstOrDefault();
|
|
||||||
|
|
||||||
Assert.IsNull(parentRegistration);
|
|
||||||
Assert.IsNotNull(childRegistration);
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public void DuplicateRegistrationsInParentAndChildOnlyShowUpOnceInChild()
|
|
||||||
{
|
|
||||||
container.RegisterType<ILogger, MockLogger>("one");
|
|
||||||
|
|
||||||
var child = container.CreateChildContainer()
|
|
||||||
.RegisterType<ILogger, SpecialLogger>("one");
|
|
||||||
|
|
||||||
var registrations = from r in child.Registrations
|
|
||||||
where r.RegisteredType == typeof(ILogger)
|
|
||||||
select r;
|
|
||||||
|
|
||||||
Assert.AreEqual(1, registrations.Count());
|
|
||||||
|
|
||||||
var childRegistration = registrations.First();
|
|
||||||
Assert.AreSame(typeof(SpecialLogger), childRegistration.MappedToType);
|
|
||||||
Assert.AreEqual("one", childRegistration.Name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -356,20 +356,23 @@ namespace Unity.Tests.CollectionSupport
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void Enumerable_DisposingScopeDisposesService()
|
public void Enumerable_DisposingScopeDisposesService()
|
||||||
{
|
{
|
||||||
|
EmailService singleton;
|
||||||
|
OtherEmailService transient3;
|
||||||
|
|
||||||
using (IUnityContainer provider = new UnityContainer())
|
using (IUnityContainer provider = new UnityContainer())
|
||||||
{
|
{
|
||||||
|
EmailService disposableService;
|
||||||
|
OtherEmailService transient1;
|
||||||
|
OtherEmailService transient2;
|
||||||
|
|
||||||
// Arrange
|
// Arrange
|
||||||
provider.RegisterType<IService, EmailService>("Singleton", new ContainerControlledLifetimeManager());
|
provider.RegisterType<IService, EmailService>("Singleton", new ContainerControlledLifetimeManager());
|
||||||
provider.RegisterType<IService, EmailService>("Scoped", new HierarchicalLifetimeManager());
|
provider.RegisterType<IService, EmailService>("Scoped", new HierarchicalLifetimeManager());
|
||||||
provider.RegisterType<IService, OtherEmailService>("Transient", new HierarchicalLifetimeManager());
|
provider.RegisterType<IService, OtherEmailService>("Transient", new HierarchicalLifetimeManager());
|
||||||
|
|
||||||
EmailService disposableService;
|
|
||||||
OtherEmailService transient1;
|
|
||||||
OtherEmailService transient2;
|
|
||||||
EmailService singleton;
|
|
||||||
|
|
||||||
// Act and Assert
|
// Act and Assert
|
||||||
OtherEmailService transient3 = (OtherEmailService)provider.Resolve<IService>("Transient");
|
transient3 = (OtherEmailService)provider.Resolve<IService>("Transient");
|
||||||
using (var scope = provider.CreateChildContainer())
|
using (var scope = provider.CreateChildContainer())
|
||||||
{
|
{
|
||||||
disposableService = (EmailService)scope.Resolve<IService>("Scoped");
|
disposableService = (EmailService)scope.Resolve<IService>("Scoped");
|
||||||
|
@ -387,15 +390,10 @@ namespace Unity.Tests.CollectionSupport
|
||||||
Assert.IsTrue(transient1.Disposed);
|
Assert.IsTrue(transient1.Disposed);
|
||||||
Assert.IsTrue(transient2.Disposed);
|
Assert.IsTrue(transient2.Disposed);
|
||||||
Assert.IsFalse(singleton.Disposed);
|
Assert.IsFalse(singleton.Disposed);
|
||||||
|
|
||||||
var disposableProvider = provider as IDisposable;
|
|
||||||
if (disposableProvider != null)
|
|
||||||
{
|
|
||||||
disposableProvider.Dispose();
|
|
||||||
Assert.IsTrue(singleton.Disposed);
|
|
||||||
Assert.IsTrue(transient3.Disposed);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Assert.IsTrue(transient3.Disposed);
|
||||||
|
Assert.IsTrue(singleton.Disposed);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
|
|
|
@ -32,7 +32,7 @@ namespace Unity.Tests.Extension
|
||||||
|
|
||||||
public IMyCustomConfigurator AddPolicy()
|
public IMyCustomConfigurator AddPolicy()
|
||||||
{
|
{
|
||||||
Context.Policies.Set<IBuildPlanPolicy>(new MyCustomPolicy(), null);
|
Context.Policies.Set(null, null, typeof(IBuildPlanPolicy), new MyCustomPolicy());
|
||||||
this.checkPolicyAdded = true;
|
this.checkPolicyAdded = true;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,11 +4,9 @@
|
||||||
|
|
||||||
using Microsoft.Practices.Unity;
|
using Microsoft.Practices.Unity;
|
||||||
using Microsoft.Practices.Unity.Tests.TestDoubles;
|
using Microsoft.Practices.Unity.Tests.TestDoubles;
|
||||||
|
using Microsoft.Practices.Unity.TestSupport;
|
||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
using Unity.Builder;
|
using Unity.Builder;
|
||||||
using Unity.Tests.TestDoubles;
|
|
||||||
using IMockConfiguration = Microsoft.Practices.Unity.TestSupport.IMockConfiguration;
|
|
||||||
using MockContainerExtension = Microsoft.Practices.Unity.TestSupport.MockContainerExtension;
|
|
||||||
|
|
||||||
namespace Unity.Tests.Extension
|
namespace Unity.Tests.Extension
|
||||||
{
|
{
|
||||||
|
|
|
@ -17,8 +17,8 @@ namespace Microsoft.Practices.Unity.Tests
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void CanSpecializeGenericTypes()
|
public void CanSpecializeGenericTypes()
|
||||||
{
|
{
|
||||||
IUnityContainer container = new UnityContainer()
|
IUnityContainer container = new UnityContainer();
|
||||||
.RegisterType(typeof(ICommand<>), typeof(ConcreteCommand<>));
|
container.RegisterType(typeof(ICommand<>), typeof(ConcreteCommand<>));
|
||||||
ICommand<User> cmd = container.Resolve<ICommand<User>>();
|
ICommand<User> cmd = container.Resolve<ICommand<User>>();
|
||||||
AssertExtensions.IsInstanceOfType(cmd, typeof(ConcreteCommand<User>));
|
AssertExtensions.IsInstanceOfType(cmd, typeof(ConcreteCommand<User>));
|
||||||
}
|
}
|
||||||
|
@ -34,10 +34,12 @@ namespace Microsoft.Practices.Unity.Tests
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void CanChainGenericTypes()
|
public void CanChainGenericTypes()
|
||||||
{
|
{
|
||||||
IUnityContainer container = new UnityContainer()
|
IUnityContainer container = new UnityContainer();
|
||||||
.RegisterType(typeof(ICommand<>), typeof(LoggingCommand<>),
|
container.RegisterType(typeof(ICommand<>), typeof(LoggingCommand<>), new InjectionConstructor(new ResolvedParameter(typeof(ICommand<>), "concrete")));
|
||||||
new InjectionConstructor(new ResolvedParameter(typeof(ICommand<>), "concrete")))
|
container.RegisterType(typeof(ICommand<>), typeof(ConcreteCommand<>), "concrete");
|
||||||
.RegisterType(typeof(ICommand<>), typeof(ConcreteCommand<>), "concrete");
|
|
||||||
|
var md = container.Resolve<ICommand<User>>("concrete");
|
||||||
|
|
||||||
|
|
||||||
ICommand<User> cmd = container.Resolve<ICommand<User>>();
|
ICommand<User> cmd = container.Resolve<ICommand<User>>();
|
||||||
LoggingCommand<User> logCmd = (LoggingCommand<User>)cmd;
|
LoggingCommand<User> logCmd = (LoggingCommand<User>)cmd;
|
||||||
|
@ -50,8 +52,7 @@ namespace Microsoft.Practices.Unity.Tests
|
||||||
public void CanChainGenericTypesViaRegisterTypeMethod()
|
public void CanChainGenericTypesViaRegisterTypeMethod()
|
||||||
{
|
{
|
||||||
IUnityContainer container = new UnityContainer()
|
IUnityContainer container = new UnityContainer()
|
||||||
.RegisterType(typeof(ICommand<>), typeof(LoggingCommand<>),
|
.RegisterType(typeof(ICommand<>), typeof(LoggingCommand<>), new InjectionConstructor(new ResolvedParameter(typeof(ICommand<>), "concrete")))
|
||||||
new InjectionConstructor(new ResolvedParameter(typeof(ICommand<>), "concrete")))
|
|
||||||
.RegisterType(typeof(ICommand<>), typeof(ConcreteCommand<>), "concrete");
|
.RegisterType(typeof(ICommand<>), typeof(ConcreteCommand<>), "concrete");
|
||||||
|
|
||||||
ICommand<User> cmd = container.Resolve<ICommand<User>>();
|
ICommand<User> cmd = container.Resolve<ICommand<User>>();
|
||||||
|
@ -76,9 +77,8 @@ namespace Microsoft.Practices.Unity.Tests
|
||||||
public void ConfiguredGenericMethodInjectionIsCalled()
|
public void ConfiguredGenericMethodInjectionIsCalled()
|
||||||
{
|
{
|
||||||
IUnityContainer container = new UnityContainer()
|
IUnityContainer container = new UnityContainer()
|
||||||
.RegisterType(typeof(ICommand<>), typeof(LoggingCommand<>),
|
.RegisterType(typeof(ICommand<>), typeof(LoggingCommand<>), new InjectionConstructor(new ResolvedParameter(typeof(ICommand<>), "concrete")),
|
||||||
new InjectionConstructor(new ResolvedParameter(typeof(ICommand<>), "concrete")),
|
new InjectionMethod("ChainedExecute", new ResolvedParameter(typeof(ICommand<>), "inner")))
|
||||||
new InjectionMethod("ChainedExecute", new ResolvedParameter(typeof(ICommand<>), "inner")))
|
|
||||||
.RegisterType(typeof(ICommand<>), typeof(ConcreteCommand<>), "concrete")
|
.RegisterType(typeof(ICommand<>), typeof(ConcreteCommand<>), "concrete")
|
||||||
.RegisterType(typeof(ICommand<>), typeof(ConcreteCommand<>), "inner");
|
.RegisterType(typeof(ICommand<>), typeof(ConcreteCommand<>), "inner");
|
||||||
|
|
||||||
|
@ -175,9 +175,8 @@ namespace Microsoft.Practices.Unity.Tests
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void ContainerControlledOpenGenericsAreDisposed()
|
public void ContainerControlledOpenGenericsAreDisposed()
|
||||||
{
|
{
|
||||||
var container = new UnityContainer()
|
var container = new UnityContainer();
|
||||||
.RegisterType(typeof(ICommand<>), typeof(DisposableCommand<>),
|
container.RegisterType(typeof(ICommand<>), typeof(DisposableCommand<>), new ContainerControlledLifetimeManager());
|
||||||
new ContainerControlledLifetimeManager());
|
|
||||||
|
|
||||||
var accountCommand = container.Resolve<ICommand<Account>>();
|
var accountCommand = container.Resolve<ICommand<Account>>();
|
||||||
var userCommand = container.Resolve<ICommand<User>>();
|
var userCommand = container.Resolve<ICommand<User>>();
|
|
@ -1,6 +1,7 @@
|
||||||
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
|
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using Microsoft.Practices.Unity;
|
||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
using Unity.Injection;
|
using Unity.Injection;
|
||||||
using Unity.Lifetime;
|
using Unity.Lifetime;
|
||||||
|
@ -26,7 +27,8 @@ namespace Unity.Tests.Generics
|
||||||
public void ResolveConfiguredGenericType()
|
public void ResolveConfiguredGenericType()
|
||||||
{
|
{
|
||||||
IUnityContainer container = new UnityContainer()
|
IUnityContainer container = new UnityContainer()
|
||||||
.RegisterType(typeof(GenericArrayPropertyDependency<>), "testing", new InjectionProperty("Stuff"))
|
.RegisterType(typeof(GenericArrayPropertyDependency<>), "testing",
|
||||||
|
new InjectionProperty("Stuff"))
|
||||||
.RegisterInstance<string>("first", "first")
|
.RegisterInstance<string>("first", "first")
|
||||||
.RegisterInstance<string>("second", "second");
|
.RegisterInstance<string>("second", "second");
|
||||||
|
|
||||||
|
@ -48,9 +50,10 @@ namespace Unity.Tests.Generics
|
||||||
myDict.Add("One", "two");
|
myDict.Add("One", "two");
|
||||||
myDict.Add("Two", "three");
|
myDict.Add("Two", "three");
|
||||||
|
|
||||||
IUnityContainer container = new UnityContainer()
|
IUnityContainer container = new UnityContainer();
|
||||||
.RegisterInstance(myDict)
|
container.RegisterInstance(myDict);
|
||||||
.RegisterType(typeof(IDictionary<,>), typeof(Dictionary<,>), new ExternallyControlledLifetimeManager());
|
container.RegisterType(typeof(IDictionary<,>), typeof(Dictionary<,>), new ExternallyControlledLifetimeManager(),
|
||||||
|
new InjectionConstructor());
|
||||||
|
|
||||||
IDictionary<string, string> result = container.Resolve<IDictionary<string, string>>();
|
IDictionary<string, string> result = container.Resolve<IDictionary<string, string>>();
|
||||||
Assert.AreSame(myDict, result);
|
Assert.AreSame(myDict, result);
|
||||||
|
@ -80,13 +83,13 @@ namespace Unity.Tests.Generics
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void Testmethod_NoLifetimeSpecified()
|
public void Testmethod_NoLifetimeSpecified()
|
||||||
{
|
{
|
||||||
List<int> myList = new List<int>();
|
var myList = new List<int>();
|
||||||
IUnityContainer container = new UnityContainer()
|
var container = new UnityContainer()
|
||||||
.RegisterInstance<List<int>>(myList)
|
.RegisterInstance<IList<int>>(myList)
|
||||||
.RegisterType<List<int>>(new InjectionConstructor());
|
.RegisterType<List<int>>();
|
||||||
|
|
||||||
List<int> result = container.Resolve<List<int>>();
|
var result = container.Resolve<IList<int>>();
|
||||||
Assert.AreNotSame(myList, result);
|
Assert.AreSame(myList, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -110,13 +113,13 @@ namespace Unity.Tests.Generics
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void Testmethod_ListOfString()
|
public void Testmethod_ListOfString()
|
||||||
{
|
{
|
||||||
List<string> myList = new List<string>();
|
var myList = new List<string>();
|
||||||
IUnityContainer container = new UnityContainer()
|
var container = new UnityContainer()
|
||||||
.RegisterInstance<List<string>>(myList)
|
.RegisterInstance<IList<string>>(myList)
|
||||||
.RegisterType<List<string>>(new InjectionConstructor());
|
.RegisterType<List<string>>();
|
||||||
|
|
||||||
List<string> result = container.Resolve<List<string>>();
|
IList<string> result = container.Resolve<IList<string>>();
|
||||||
Assert.AreNotSame(myList, result);
|
Assert.AreSame(myList, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -126,12 +129,12 @@ namespace Unity.Tests.Generics
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void Testmethod_ListOfObjectType()
|
public void Testmethod_ListOfObjectType()
|
||||||
{
|
{
|
||||||
List<Foo> myList = new List<Foo>();
|
var myList = new List<Foo>();
|
||||||
IUnityContainer container = new UnityContainer()
|
var container = new UnityContainer()
|
||||||
.RegisterInstance<IList<Foo>>(myList)
|
.RegisterInstance(myList)
|
||||||
.RegisterType<IList<Foo>, List<Foo>>(new InjectionConstructor());
|
.RegisterType<IList<Foo>, List<Foo>>();
|
||||||
|
|
||||||
IList<Foo> result = container.Resolve<IList<Foo>>();
|
var result = container.Resolve<IList<Foo>>();
|
||||||
Assert.IsInstanceOfType(result, typeof(List<Foo>));
|
Assert.IsInstanceOfType(result, typeof(List<Foo>));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,6 @@ using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using Microsoft.Practices.Unity.TestSupport;
|
using Microsoft.Practices.Unity.TestSupport;
|
||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
using Unity.Tests.TestSupport;
|
|
||||||
|
|
||||||
namespace Microsoft.Practices.Unity.Tests
|
namespace Microsoft.Practices.Unity.Tests
|
||||||
{
|
{
|
|
@ -1,189 +0,0 @@
|
||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
|
||||||
using System.Linq;
|
|
||||||
using Microsoft.Practices.Unity.TestSupport;
|
|
||||||
using Unity;
|
|
||||||
using Unity.Attributes;
|
|
||||||
using Unity.Exceptions;
|
|
||||||
using Unity.Injection;
|
|
||||||
using Unity.Lifetime;
|
|
||||||
using Unity.Tests.TestObjects;
|
|
||||||
using UnityContainer = Unity.UnityContainer;
|
|
||||||
|
|
||||||
namespace GitHub
|
|
||||||
{
|
|
||||||
[TestClass]
|
|
||||||
public class Issues
|
|
||||||
{
|
|
||||||
[TestMethod]
|
|
||||||
public void unitycontainer_unity_164()
|
|
||||||
{
|
|
||||||
var container = new UnityContainer();
|
|
||||||
|
|
||||||
container.RegisterType<ILogger, MockLogger>();
|
|
||||||
var foo2 = new MockLogger();
|
|
||||||
|
|
||||||
container.RegisterType<ILogger>(new InjectionFactory(x => foo2));
|
|
||||||
var result = container.Resolve<ILogger>();
|
|
||||||
|
|
||||||
Assert.AreSame(result, foo2);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public void unity_156()
|
|
||||||
{
|
|
||||||
using (var container = new UnityContainer())
|
|
||||||
{
|
|
||||||
var td = new MockLogger();
|
|
||||||
|
|
||||||
container.RegisterType<MockLogger>(new ContainerControlledLifetimeManager(), new InjectionFactory(_ => td));
|
|
||||||
container.RegisterType<ILogger, MockLogger>();
|
|
||||||
|
|
||||||
Assert.AreSame(td, container.Resolve<ILogger>());
|
|
||||||
Assert.AreSame(td, container.Resolve<MockLogger>());
|
|
||||||
}
|
|
||||||
using (var container = new UnityContainer())
|
|
||||||
{
|
|
||||||
var td = new MockLogger();
|
|
||||||
|
|
||||||
container.RegisterType<MockLogger>(new ContainerControlledLifetimeManager(), new InjectionFactory(_ => td));
|
|
||||||
container.RegisterType<ILogger, MockLogger>();
|
|
||||||
|
|
||||||
Assert.AreSame(td, container.Resolve<MockLogger>());
|
|
||||||
Assert.AreSame(td, container.Resolve<ILogger>());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public void unity_154_5()
|
|
||||||
{
|
|
||||||
IUnityContainer container = new UnityContainer();
|
|
||||||
container.RegisterType<OtherEmailService>(new ContainerControlledLifetimeManager());
|
|
||||||
container.RegisterType<IService, OtherEmailService>();
|
|
||||||
container.RegisterType<IOtherService, OtherEmailService>(new InjectionConstructor(container));
|
|
||||||
|
|
||||||
Assert.AreNotSame(container.Resolve<IService>(),
|
|
||||||
container.Resolve<IOtherService>());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public void unity_154()
|
|
||||||
{
|
|
||||||
IUnityContainer container = new UnityContainer();
|
|
||||||
container.RegisterType<OtherEmailService>(new ContainerControlledLifetimeManager());
|
|
||||||
container.RegisterType<IService, OtherEmailService>();
|
|
||||||
container.RegisterType<IOtherService, OtherEmailService>();
|
|
||||||
|
|
||||||
Assert.AreSame(container.Resolve<IService>(),
|
|
||||||
container.Resolve<IOtherService>());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public void unity_153()
|
|
||||||
{
|
|
||||||
IUnityContainer rootContainer = new UnityContainer();
|
|
||||||
rootContainer.RegisterType<ILogger, MockLogger>(new HierarchicalLifetimeManager());
|
|
||||||
|
|
||||||
using (IUnityContainer childContainer = rootContainer.CreateChildContainer())
|
|
||||||
{
|
|
||||||
var a = childContainer.Resolve<ILogger>();
|
|
||||||
var b = childContainer.Resolve<ILogger>();
|
|
||||||
|
|
||||||
Assert.AreSame(a, b);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public void Issue_35()
|
|
||||||
{
|
|
||||||
IUnityContainer container = new UnityContainer();
|
|
||||||
|
|
||||||
container.RegisterType<ILogger, MockLogger>(new ContainerControlledLifetimeManager());
|
|
||||||
ILogger logger = container.Resolve<ILogger>();
|
|
||||||
|
|
||||||
Assert.IsNotNull(logger);
|
|
||||||
Assert.AreSame(container.Resolve<ILogger>(), logger);
|
|
||||||
|
|
||||||
container.RegisterType<MockLogger>(new TransientLifetimeManager());
|
|
||||||
|
|
||||||
Assert.AreSame(container.Resolve<ILogger>(), logger);
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public void GitHub_Issue_88() // https://github.com/unitycontainer/unity/issues/88
|
|
||||||
{
|
|
||||||
using (var unityContainer = new UnityContainer())
|
|
||||||
{
|
|
||||||
unityContainer.RegisterInstance(true);
|
|
||||||
unityContainer.RegisterInstance("true", true);
|
|
||||||
unityContainer.RegisterInstance("false", false);
|
|
||||||
|
|
||||||
var resolveAll = unityContainer.ResolveAll(typeof(bool));
|
|
||||||
var arr = resolveAll.Select(o => o.ToString()).ToArray();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public void GitHub_Issue_54() // https://github.com/unitycontainer/unity/issues/54
|
|
||||||
{
|
|
||||||
using (IUnityContainer container = new UnityContainer())
|
|
||||||
{
|
|
||||||
container.RegisterType(typeof(ITestClass), typeof(TestClass));
|
|
||||||
container.RegisterInstance(new TestClass());
|
|
||||||
var instance = container.Resolve<ITestClass>(); //0
|
|
||||||
Assert.IsNotNull(instance);
|
|
||||||
}
|
|
||||||
|
|
||||||
using (IUnityContainer container = new UnityContainer())
|
|
||||||
{
|
|
||||||
container.RegisterType(typeof(ITestClass), typeof(TestClass));
|
|
||||||
container.RegisterType<TestClass>(new ContainerControlledLifetimeManager());
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var instance = container.Resolve<ITestClass>(); //2
|
|
||||||
Assert.IsNull(instance, "Should threw an exception");
|
|
||||||
}
|
|
||||||
catch (ResolutionFailedException e)
|
|
||||||
{
|
|
||||||
Assert.IsInstanceOfType(e, typeof(ResolutionFailedException));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public void GitHub_Issue_35_ConflictTypeMapping()
|
|
||||||
{
|
|
||||||
IUnityContainer container = new UnityContainer();
|
|
||||||
|
|
||||||
container.RegisterType<ILogger, MockLogger>(new ContainerControlledLifetimeManager());
|
|
||||||
ILogger logger = container.Resolve<ILogger>();
|
|
||||||
|
|
||||||
Assert.IsNotNull(logger);
|
|
||||||
Assert.AreSame(container.Resolve<ILogger>(), logger);
|
|
||||||
|
|
||||||
container.RegisterType<MockLogger>(new TransientLifetimeManager());
|
|
||||||
|
|
||||||
Assert.AreSame(container.Resolve<ILogger>(), logger);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test types
|
|
||||||
public interface ITestClass
|
|
||||||
{ }
|
|
||||||
|
|
||||||
public class TestClass : ITestClass
|
|
||||||
{
|
|
||||||
public TestClass()
|
|
||||||
{ }
|
|
||||||
|
|
||||||
[InjectionConstructor]
|
|
||||||
public TestClass(TestClass x) //1
|
|
||||||
{ }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -3,10 +3,9 @@
|
||||||
using System;
|
using System;
|
||||||
using Microsoft.Practices.Unity.TestSupport;
|
using Microsoft.Practices.Unity.TestSupport;
|
||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
using Unity;
|
|
||||||
using Unity.Injection;
|
using Unity.Injection;
|
||||||
|
|
||||||
namespace Microsoft.Practices.Unity.Tests
|
namespace Unity.Tests.Injection
|
||||||
{
|
{
|
||||||
[TestClass]
|
[TestClass]
|
||||||
public class InjectedMembersFixture
|
public class InjectedMembersFixture
|
|
@ -3,11 +3,9 @@
|
||||||
using System;
|
using System;
|
||||||
using Microsoft.Practices.Unity.TestSupport;
|
using Microsoft.Practices.Unity.TestSupport;
|
||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
using Unity;
|
|
||||||
using Unity.Injection;
|
using Unity.Injection;
|
||||||
using Unity.Tests.TestSupport;
|
|
||||||
|
|
||||||
namespace Microsoft.Practices.Unity.Tests
|
namespace Unity.Tests.Injection
|
||||||
{
|
{
|
||||||
[TestClass]
|
[TestClass]
|
||||||
public class InjectingArraysFixture
|
public class InjectingArraysFixture
|
|
@ -3,10 +3,9 @@
|
||||||
using System;
|
using System;
|
||||||
using Microsoft.Practices.Unity.TestSupport;
|
using Microsoft.Practices.Unity.TestSupport;
|
||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
using Unity;
|
|
||||||
using Unity.Injection;
|
using Unity.Injection;
|
||||||
|
|
||||||
namespace Microsoft.Practices.Unity.Tests
|
namespace Unity.Tests.Injection
|
||||||
{
|
{
|
||||||
[TestClass]
|
[TestClass]
|
||||||
public class InjectionMethodFixture
|
public class InjectionMethodFixture
|
|
@ -4,14 +4,14 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Microsoft.Practices.ObjectBuilder2;
|
using Microsoft.Practices.ObjectBuilder2;
|
||||||
|
using Microsoft.Practices.Unity.Tests;
|
||||||
using Microsoft.Practices.Unity.TestSupport;
|
using Microsoft.Practices.Unity.TestSupport;
|
||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
using Unity;
|
|
||||||
using Unity.Injection;
|
using Unity.Injection;
|
||||||
using Unity.Policy;
|
using Unity.Policy;
|
||||||
using Unity.ResolverPolicy;
|
using Unity.ResolverPolicy;
|
||||||
|
|
||||||
namespace Microsoft.Practices.Unity.Tests
|
namespace Unity.Tests.Injection
|
||||||
{
|
{
|
||||||
// Tests for the DependencyValue class and its derivatives
|
// Tests for the DependencyValue class and its derivatives
|
||||||
[TestClass]
|
[TestClass]
|
|
@ -3,11 +3,10 @@
|
||||||
using System;
|
using System;
|
||||||
using Microsoft.Practices.Unity.TestSupport;
|
using Microsoft.Practices.Unity.TestSupport;
|
||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
using Unity;
|
|
||||||
using Unity.Attributes;
|
using Unity.Attributes;
|
||||||
using Unity.Injection;
|
using Unity.Injection;
|
||||||
|
|
||||||
namespace Microsoft.Practices.Unity.Tests
|
namespace Unity.Tests.Injection
|
||||||
{
|
{
|
||||||
[TestClass]
|
[TestClass]
|
||||||
public class MethodInjectionFixture
|
public class MethodInjectionFixture
|
|
@ -1,7 +1,6 @@
|
||||||
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
|
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using Microsoft.Practices.ObjectBuilder2;
|
|
||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
using Unity;
|
using Unity;
|
||||||
using Unity.Builder;
|
using Unity.Builder;
|
||||||
|
@ -209,11 +208,6 @@ namespace Microsoft.Practices.Unity.Tests
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public object NewBuildUp(INamedType newBuildKey)
|
|
||||||
{
|
|
||||||
return NewBuildupCallback(newBuildKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
public object NewBuildUp(Type type, string name, Action<IBuilderContext> childCustomizationBlock = null)
|
public object NewBuildUp(Type type, string name, Action<IBuilderContext> childCustomizationBlock = null)
|
||||||
{
|
{
|
||||||
return NewBuildupCallback(new NamedTypeBuildKey(type, name));
|
return NewBuildupCallback(new NamedTypeBuildKey(type, name));
|
|
@ -4,11 +4,10 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Microsoft.Practices.Unity.TestSupport;
|
using Microsoft.Practices.Unity.TestSupport;
|
||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
using Unity;
|
|
||||||
using Unity.Attributes;
|
using Unity.Attributes;
|
||||||
using Unity.Lifetime;
|
using Unity.Lifetime;
|
||||||
|
|
||||||
namespace Microsoft.Practices.Unity.Tests
|
namespace Unity.Tests.Lazy
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Summary description for DeferredResolveFixture
|
/// Summary description for DeferredResolveFixture
|
|
@ -5,6 +5,8 @@ using Microsoft.Practices.Unity;
|
||||||
using Microsoft.Practices.Unity.TestSupport;
|
using Microsoft.Practices.Unity.TestSupport;
|
||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
using Unity.Lifetime;
|
using Unity.Lifetime;
|
||||||
|
using Unity.Tests.Container;
|
||||||
|
using Unity.Tests.TestObjects;
|
||||||
|
|
||||||
|
|
||||||
namespace Unity.Tests.Lifetime
|
namespace Unity.Tests.Lifetime
|
||||||
|
@ -292,16 +294,16 @@ namespace Unity.Tests.Lifetime
|
||||||
{
|
{
|
||||||
IUnityContainer uc = new UnityContainer();
|
IUnityContainer uc = new UnityContainer();
|
||||||
|
|
||||||
A aInstance = new A();
|
var aInstance = new EmailService();
|
||||||
uc.RegisterType<A>(new ContainerControlledLifetimeManager())
|
uc.RegisterType(null, typeof(EmailService), null, new ContainerControlledLifetimeManager(), null);
|
||||||
.RegisterType<A>("SetA", new ContainerControlledLifetimeManager())
|
uc.RegisterType<EmailService>("SetA", new ContainerControlledLifetimeManager());
|
||||||
.RegisterInstance<A>(aInstance)
|
uc.RegisterInstance(aInstance);
|
||||||
.RegisterInstance<A>("hello", aInstance)
|
uc.RegisterInstance("hello", aInstance);
|
||||||
.RegisterInstance<A>("hello", aInstance, new ExternallyControlledLifetimeManager());
|
uc.RegisterInstance("hello", aInstance, new ExternallyControlledLifetimeManager());
|
||||||
|
|
||||||
A obj = uc.Resolve<A>();
|
var obj = uc.Resolve<EmailService>();
|
||||||
A obj1 = uc.Resolve<A>("SetA");
|
var obj1 = uc.Resolve<EmailService>("SetA");
|
||||||
A obj2 = uc.Resolve<A>("hello");
|
var obj2 = uc.Resolve<EmailService>("hello");
|
||||||
|
|
||||||
Assert.AreNotSame(obj, obj1);
|
Assert.AreNotSame(obj, obj1);
|
||||||
Assert.AreSame(obj, obj2);
|
Assert.AreSame(obj, obj2);
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
|
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
using Unity;
|
|
||||||
using Unity.Builder;
|
using Unity.Builder;
|
||||||
using Unity.ObjectBuilder.Policies;
|
using Unity.Policy.Mapping;
|
||||||
|
|
||||||
namespace Microsoft.Practices.ObjectBuilder2.Tests
|
namespace Unity.Tests.ObjectBuilder
|
||||||
{
|
{
|
||||||
[TestClass]
|
[TestClass]
|
||||||
public class BuildKeyMappingPolicyTest
|
public class BuildKeyMappingPolicyTest
|
||||||
|
|
|
@ -1,108 +0,0 @@
|
||||||
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using Microsoft.Practices.Unity.TestSupport;
|
|
||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
|
||||||
using Unity;
|
|
||||||
using Unity.Builder;
|
|
||||||
using Unity.Builder.Strategy;
|
|
||||||
using Unity.ObjectBuilder.Policies;
|
|
||||||
using Unity.ObjectBuilder.Strategies;
|
|
||||||
using Unity.Policy;
|
|
||||||
|
|
||||||
namespace Microsoft.Practices.ObjectBuilder2.Tests
|
|
||||||
{
|
|
||||||
[TestClass]
|
|
||||||
public class BuildKeyMappingStrategyTest
|
|
||||||
{
|
|
||||||
[TestMethod]
|
|
||||||
public void CanMapGenericsWithIdenticalGenericParameters()
|
|
||||||
{
|
|
||||||
MockBuilderContext context = new MockBuilderContext();
|
|
||||||
context.Policies.Set<IBuildKeyMappingPolicy>(new GenericTypeBuildKeyMappingPolicy(
|
|
||||||
new NamedTypeBuildKey(typeof(ConcreteType<>))),
|
|
||||||
new NamedTypeBuildKey(typeof(ITestType<>)));
|
|
||||||
BuildKeyMappingStrategy strategy = new BuildKeyMappingStrategy();
|
|
||||||
context.Strategies.Add(strategy);
|
|
||||||
SpyStrategy spy = new SpyStrategy();
|
|
||||||
context.Strategies.Add(spy);
|
|
||||||
context.BuildKey = new NamedTypeBuildKey<ITestType<int>>();
|
|
||||||
context.Strategies.ExecuteBuildUp(context);
|
|
||||||
|
|
||||||
Assert.AreEqual(new NamedTypeBuildKey(typeof(ConcreteType<int>)), spy.BuildKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public void CanMapGenericsWithANonTypeBuildKey()
|
|
||||||
{
|
|
||||||
MockBuilderContext context = new MockBuilderContext();
|
|
||||||
context.Policies.Set<IBuildKeyMappingPolicy>(
|
|
||||||
new GenericTypeBuildKeyMappingPolicy(new NamedTypeBuildKey(typeof(ConcreteType<>), "two")),
|
|
||||||
new NamedTypeBuildKey(typeof(ITestType<>), "one"));
|
|
||||||
|
|
||||||
BuildKeyMappingStrategy strategy = new BuildKeyMappingStrategy();
|
|
||||||
context.Strategies.Add(strategy);
|
|
||||||
SpyStrategy spy = new SpyStrategy();
|
|
||||||
context.Strategies.Add(spy);
|
|
||||||
context.BuildKey = new NamedTypeBuildKey(typeof(ITestType<int>), "one");
|
|
||||||
context.Strategies.ExecuteBuildUp(context);
|
|
||||||
|
|
||||||
AssertExtensions.IsInstanceOfType(spy.BuildKey, typeof(NamedTypeBuildKey));
|
|
||||||
Assert.AreEqual(typeof(ConcreteType<int>), spy.BuildKey.Type);
|
|
||||||
Assert.AreEqual("two", spy.BuildKey.Name);
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public void CanMapInterfacesToConcreteTypes()
|
|
||||||
{
|
|
||||||
MockBuilderContext context = new MockBuilderContext();
|
|
||||||
context.Policies.Set<IBuildKeyMappingPolicy>(new BuildKeyMappingPolicy(new NamedTypeBuildKey<ConcreteType>()),
|
|
||||||
new NamedTypeBuildKey<ITestType>());
|
|
||||||
BuildKeyMappingStrategy strategy = new BuildKeyMappingStrategy();
|
|
||||||
context.Strategies.Add(strategy);
|
|
||||||
SpyStrategy spy = new SpyStrategy();
|
|
||||||
context.Strategies.Add(spy);
|
|
||||||
context.BuildKey = new NamedTypeBuildKey<ITestType>();
|
|
||||||
context.Strategies.ExecuteBuildUp(context);
|
|
||||||
|
|
||||||
Assert.AreEqual(new NamedTypeBuildKey(typeof(ConcreteType)), spy.BuildKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public void MappingStrategyActuallyReturnsTheBuildKeyThePolicySpecifies()
|
|
||||||
{
|
|
||||||
MockBuilderContext context = new MockBuilderContext();
|
|
||||||
NamedTypeBuildKey fromKey = new NamedTypeBuildKey(typeof(ConcreteType), "id");
|
|
||||||
NamedTypeBuildKey toKey = new NamedTypeBuildKey(typeof(ITestType), "id");
|
|
||||||
context.Policies.Set<IBuildKeyMappingPolicy>(new BuildKeyMappingPolicy(toKey), fromKey);
|
|
||||||
BuildKeyMappingStrategy strategy = new BuildKeyMappingStrategy();
|
|
||||||
context.Strategies.Add(strategy);
|
|
||||||
SpyStrategy spy = new SpyStrategy();
|
|
||||||
context.Strategies.Add(spy);
|
|
||||||
context.BuildKey = fromKey;
|
|
||||||
context.Existing = null;
|
|
||||||
context.Strategies.ExecuteBuildUp(context);
|
|
||||||
|
|
||||||
AssertExtensions.IsInstanceOfType(spy.BuildKey, typeof(NamedTypeBuildKey));
|
|
||||||
Assert.AreEqual(toKey, spy.BuildKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
private class ConcreteType : ITestType { }
|
|
||||||
|
|
||||||
private class ConcreteType<T> : ITestType<T> { }
|
|
||||||
|
|
||||||
private interface ITestType { }
|
|
||||||
|
|
||||||
private interface ITestType<T> { }
|
|
||||||
|
|
||||||
private class SpyStrategy : BuilderStrategy
|
|
||||||
{
|
|
||||||
public INamedType BuildKey;
|
|
||||||
|
|
||||||
public override object PreBuildUp(IBuilderContext context)
|
|
||||||
{
|
|
||||||
this.BuildKey = context.BuildKey;
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -5,6 +5,7 @@ using Microsoft.Practices.Unity.TestSupport;
|
||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
using Unity;
|
using Unity;
|
||||||
using Unity.Injection;
|
using Unity.Injection;
|
||||||
|
using Unity.Tests.TestObjects;
|
||||||
|
|
||||||
namespace Microsoft.Practices.Unity.Tests
|
namespace Microsoft.Practices.Unity.Tests
|
||||||
{
|
{
|
|
@ -3,10 +3,10 @@
|
||||||
using Microsoft.Practices.Unity.TestSupport;
|
using Microsoft.Practices.Unity.TestSupport;
|
||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
using Unity.Builder;
|
using Unity.Builder;
|
||||||
using Unity.ObjectBuilder.Strategies;
|
|
||||||
using Unity.Policy;
|
using Unity.Policy;
|
||||||
|
using Unity.Strategies;
|
||||||
|
|
||||||
namespace Microsoft.Practices.ObjectBuilder2.Tests
|
namespace Unity.Tests.ObjectBuilder
|
||||||
{
|
{
|
||||||
[TestClass]
|
[TestClass]
|
||||||
public class BuildPlanStrategyFixture
|
public class BuildPlanStrategyFixture
|
||||||
|
@ -19,7 +19,7 @@ namespace Microsoft.Practices.ObjectBuilder2.Tests
|
||||||
object instance = new object();
|
object instance = new object();
|
||||||
ReturnInstanceBuildPlan plan = new ReturnInstanceBuildPlan(instance);
|
ReturnInstanceBuildPlan plan = new ReturnInstanceBuildPlan(instance);
|
||||||
|
|
||||||
context.Policies.Set<IBuildPlanPolicy>(plan, new NamedTypeBuildKey<object>());
|
context.Policies.Set(typeof(object), null, typeof(IBuildPlanPolicy), plan);
|
||||||
|
|
||||||
object result = context.ExecuteBuildUp(new NamedTypeBuildKey<object>(), null);
|
object result = context.ExecuteBuildUp(new NamedTypeBuildKey<object>(), null);
|
||||||
|
|
||||||
|
@ -33,14 +33,14 @@ namespace Microsoft.Practices.ObjectBuilder2.Tests
|
||||||
MockBuilderContext context = new MockBuilderContext();
|
MockBuilderContext context = new MockBuilderContext();
|
||||||
context.Strategies.Add(new BuildPlanStrategy());
|
context.Strategies.Add(new BuildPlanStrategy());
|
||||||
MockBuildPlanCreatorPolicy policy = new MockBuildPlanCreatorPolicy();
|
MockBuildPlanCreatorPolicy policy = new MockBuildPlanCreatorPolicy();
|
||||||
context.Policies.SetDefault<IBuildPlanCreatorPolicy>(policy);
|
context.Policies.Set(null, null, typeof(IBuildPlanCreatorPolicy),policy);
|
||||||
|
|
||||||
object result = context.ExecuteBuildUp(new NamedTypeBuildKey<object>(), null);
|
object result = context.ExecuteBuildUp(new NamedTypeBuildKey<object>(), null);
|
||||||
|
|
||||||
Assert.IsNotNull(result);
|
Assert.IsNotNull(result);
|
||||||
Assert.IsTrue(policy.PolicyWasCreated);
|
Assert.IsTrue(policy.PolicyWasCreated);
|
||||||
|
|
||||||
IBuildPlanPolicy plan = context.Policies.Get<IBuildPlanPolicy>(new NamedTypeBuildKey(typeof(object)));
|
var plan = context.Policies.GetOrDefault(typeof(IBuildPlanPolicy), new NamedTypeBuildKey(typeof(object)), out _);
|
||||||
Assert.IsNotNull(plan);
|
Assert.IsNotNull(plan);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче