This commit is contained in:
ENikS 2023-03-08 11:07:56 -08:00
Родитель a6789b727c
Коммит 98ad57363b
106 изменённых файлов: 11750 добавлений и 87 удалений

12
.gitattributes поставляемый Normal file
Просмотреть файл

@ -0,0 +1,12 @@
###############################################################################
# Set default behavior to automatically normalize line endings.
###############################################################################
* text=auto
###############################################################################
# Prevent merging of README.md
###############################################################################
README.md merge=ours
.gitmodules merge=ours
*.yml merge=ours

60
.gitignore поставляемый
Просмотреть файл

@ -23,15 +23,13 @@ bld/
[Bb]in/
[Oo]bj/
[Ll]og/
[Ll]ib/
# Visual Studio 2015/2017 cache/options directory
# Visual Studio 2015 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# Visual Studio 2017 auto generated files
Generated\ Files/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
@ -45,29 +43,20 @@ TestResult.xml
[Rr]eleasePS/
dlldata.c
# Benchmark Results
BenchmarkDotNet.Artifacts/
# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
**/Properties/launchSettings.json
# StyleCop
StyleCopReport.xml
# Files built by Visual Studio
*_i.c
*_p.c
*_i.h
*.ilk
*.meta
*.obj
*.iobj
*.pch
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
@ -105,9 +94,6 @@ ipch/
*.vspx
*.sap
# Visual Studio Trace Files
*.e2e
# TFS 2012 Local Workspace
$tf/
@ -128,10 +114,6 @@ _TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json
# Visual Studio code coverage results
*.coverage
*.coveragexml
@ -167,7 +149,7 @@ publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# Note: Comment the next line if you want to checkin your web deploy settings,
# TODO: Comment the next line if you want to checkin your web deploy settings
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
@ -180,11 +162,11 @@ PublishScripts/
# NuGet Packages
*.nupkg
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
**/packages/*
# except build/, which is used as an MSBuild target.
!**/[Pp]ackages/build/
!**/packages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/[Pp]ackages/repositories.config
#!**/packages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets
@ -202,7 +184,6 @@ AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx
# Visual Studio cache files
# files ending in .cache can be ignored
@ -221,10 +202,6 @@ ClientBin/
*.publishsettings
orleans.codegen.cs
# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
@ -239,8 +216,6 @@ _UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
ServiceFabricBackup/
*.rptproj.bak
# SQL Server files
*.mdf
@ -251,7 +226,6 @@ ServiceFabricBackup/
*.rdl.data
*.bim.layout
*.bim_*.settings
*.rptproj.rsuser
# Microsoft Fakes
FakesAssemblies/
@ -263,6 +237,9 @@ FakesAssemblies/
.ntvs_analysis.dat
node_modules/
# Typescript v1 declaration files
typings/
# Visual Studio 6 build log
*.plg
@ -302,9 +279,6 @@ __pycache__/
# tools/**
# !tools/packages.config
# Tabs Studio
*.tss
# Telerik's JustMock configuration file
*.jmconfig
@ -313,18 +287,4 @@ __pycache__/
*.btm.cs
*.odx.cs
*.xsd.cs
# OpenCover UI analysis results
OpenCover/
# Azure Stream Analytics local run output
ASALocalRun/
# MSBuild Binary and Structured Log
*.binlog
# NVidia Nsight GPU debugger configuration file
*.nvuser
# MFractors (Xamarin productivity tool) working folder
.mfractor/
/*.sln

202
LICENSE Normal file
Просмотреть файл

@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2020 .NET Foundation and Contributors
All Rights Reserved
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

Просмотреть файл

@ -1,4 +1,21 @@
# experimental
[![Build status](https://ci.appveyor.com/api/projects/status/l3bwjwm7q10nrdus/branch/master?svg=true)](https://ci.appveyor.com/project/unitycontainer/abstractions/branch/master)
![Regression Tests](https://github.com/unitycontainer/abstractions/workflows/Regression%20Tests/badge.svg?branch=master)
[![License](https://img.shields.io/badge/license-apache%202.0-60C060.svg)](https://github.com/unitycontainer/abstractions/blob/master/LICENSE)
[![NuGet](https://img.shields.io/nuget/dt/Unity.Abstractions.svg)](https://www.nuget.org/packages/Unity.Abstractions)
[![NuGet](https://img.shields.io/nuget/v/Unity.Abstractions.svg)](https://www.nuget.org/packages/Unity.Abstractions)
This repository contains experimental content
# Unity Abstractions
Home for all public interfaces and declarations
## Code of Conduct
This project has adopted the code of conduct defined by the [Contributor Covenant](https://www.contributor-covenant.org/) to clarify expected behavior in our community. For more information, see the [.NET Foundation Code of Conduct](https://www.dotnetfoundation.org/code-of-conduct)
## Contributing
See the [Contributing guide](https://github.com/unitycontainer/unity/blob/master/CONTRIBUTING.md) for more information.
## .NET Foundation
Unity Container is a [.NET Foundation](https://dotnetfoundation.org/projects/unitycontainer) project

1
RELEASE-NOTES.txt Normal file
Просмотреть файл

@ -0,0 +1 @@
This package supports .NET Standard 1.0, 2.0, and .NET 6.0

31
appveyor.yml Normal file
Просмотреть файл

@ -0,0 +1,31 @@
image: Visual Studio 2022
configuration: Release
branches:
only:
- main
- master
install:
- choco install gitversion.portable -pre -y
- ps: gitversion /l console /output buildserver /config .github\gitversion.yml
- ps: $env:Version = $env:GitVersion_MajorMinorPatch
- ps: $env:FileVersion = $env:GitVersion_AssemblySemFileVer
- ps: $env:PackageVersion = $env:GitVersion_SemVer
- ps: $env:AssemblyVersion = $env:GitVersion_AssemblySemVer
- ps: $env:InformationalVersion = $env:GitVersion_InformationalVersion
dotnet_csproj:
patch: false
before_build:
- cmd: dotnet restore
build:
project: package.sln
parallel: true
verbosity: minimal
artifacts:
- path: '**\Unity.*.nupkg'
name: 'Abstractions'

Просмотреть файл

@ -1,9 +1,18 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.30002.166
# Visual Studio Version 17
VisualStudioVersion = 17.5.33414.496
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Unity.Experimental", "src\Unity.Experimental.csproj", "{A25A345C-1402-4979-B692-092EBB876FB2}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Unity.Abstractions", "src\Unity.Abstractions.csproj", "{2A50E743-8817-41DB-BD23-6F9625665EF7}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{5ED62561-0133-4FC3-BDC0-94661AD8B939}"
ProjectSection(SolutionItems) = preProject
appveyor.yml = appveyor.yml
package.props = package.props
RELEASE-NOTES.txt = RELEASE-NOTES.txt
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Abstractions.Tests", "tests\Abstractions.Tests.csproj", "{3A5A8099-7F1A-4D11-86A6-D2FC2FC6B4E5}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -11,15 +20,19 @@ Global
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{A25A345C-1402-4979-B692-092EBB876FB2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A25A345C-1402-4979-B692-092EBB876FB2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A25A345C-1402-4979-B692-092EBB876FB2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A25A345C-1402-4979-B692-092EBB876FB2}.Release|Any CPU.Build.0 = Release|Any CPU
{2A50E743-8817-41DB-BD23-6F9625665EF7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2A50E743-8817-41DB-BD23-6F9625665EF7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2A50E743-8817-41DB-BD23-6F9625665EF7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2A50E743-8817-41DB-BD23-6F9625665EF7}.Release|Any CPU.Build.0 = Release|Any CPU
{3A5A8099-7F1A-4D11-86A6-D2FC2FC6B4E5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3A5A8099-7F1A-4D11-86A6-D2FC2FC6B4E5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3A5A8099-7F1A-4D11-86A6-D2FC2FC6B4E5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3A5A8099-7F1A-4D11-86A6-D2FC2FC6B4E5}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {296C04ED-A84B-493A-B8CC-2D79BC8C4A19}
SolutionGuid = {9E708914-4D89-4B8C-BA81-886B9613BD9A}
EndGlobalSection
EndGlobal

Просмотреть файл

@ -0,0 +1,63 @@
using System;
using Unity.Lifetime;
namespace Unity
{
/// <summary>
/// Information about the types registered in a container.
/// <para>
/// Types registered with container are stored in registry and exposed to outside world
/// through <see cref="IUnityContainer.Registrations"/> enumeration. Each record is
/// represented by an instance of this interface.
/// </para>
/// </summary>
public interface IContainerRegistration
{
/// <summary>
/// Type of the registration.
/// </summary>
/// <remarks>
/// This <see cref="Type"/> is what container stores in its internal registry. When resolving, it will look
/// for this <see cref="Type"/> to satisfy dependencies.
/// </remarks>
/// <value>The type registered with the container</value>
Type RegisteredType { get; }
/// <summary>
/// Name the registered type. Null for default registration.
/// </summary>
/// <remarks>
/// Each registration is uniquely identified by <see cref="RegisteredType"/> and <see cref="Name"/>.
/// Registering the same <see cref="Type"/> with different names will create distinct registrations
/// for each <see cref="RegisteredType"/> and <see cref="Name"/> combinations. Registration with no <see cref="Name"/>
/// (<c>name == null</c>) is called <c>default registration</c>. The container uses these as implicit defaults when required.
/// </remarks>
/// <value>Name of the registration</value>
string Name { get; }
/// <summary>
/// The type that this registration is mapped to.
/// </summary>
/// <remarks>
/// Type <see cref="MappedToType"/> informs container how to build the requested instance. Based on how it was registered, the
/// <see cref="Type"/> could be built from this registration or redirected to mapped registration to satisfy the request.
/// </remarks>
/// <value>The type of object created when registered type is requested</value>
Type MappedToType { get; }
/// <summary>
/// The lifetime manager for this registration.
/// </summary>
/// <remarks>
/// <para>
/// Each Unity registration is assigned a lifetime manager that controls how
/// the container creates, manages, and disposes of created objects. Even if
/// manager is not assigned explicitly, Unity will pick default type
/// and add it to the registration.
/// </para>
/// </remarks>
/// <value>Instance of lifetime manager associated with the registration</value>
/// <seealso cref="Lifetime"/>
LifetimeManager LifetimeManager { get; }
}
}

Просмотреть файл

@ -0,0 +1,284 @@
using System;
using System.Collections.Generic;
using Unity.Injection;
using Unity.Lifetime;
using Unity.Resolution;
namespace Unity
{
/// <summary>
/// <para>Interface defining the behavior of the Unity dependency injection container.</para>
/// <para>This interface defines a compact API that allows registration of types, instances, and
/// factories, resolution of new objects or initialization of existing instances, scope manipulations,
/// and etc.</para>
/// </summary>
[CLSCompliant(true)]
public interface IUnityContainer : IDisposable
{
/// <summary>
/// Register a type or a type mapping with the container.
/// </summary>
/// <param name="registeredType">Registration <see cref="Type"/>. This <see cref="Type"/> will be
/// requested when resolving. Sometimes referred as <c>FromType</c> or <c>ServiceType</c></param>
/// <param name="mappedToType">A <see cref="Type"/> that will actually be returned. Also referred
/// as <c>ToType</c> or <c>ImplementationType</c>.</param>
/// <param name="name">Name of the registration</param>
/// <param name="lifetimeManager">A lifetime manager that controls how instances are created, managed, and disposed of.
/// If <paramref name="lifetimeManager"/> is <c>null</c>, container uses default <see cref="TypeLifetime.Transient"/> lifetime.</param>
/// <param name="injectionMembers">Optional injection configuration objects</param>
/// <remarks>
/// <para>
/// Container stores registrations by <paramref name="registeredType"/> <see cref="Type"/>. When resolving, it will look
/// for this <see cref="Type"/> to satisfy dependencies. Each registration is uniquely identified by <paramref name="registeredType"/>
/// and <paramref name="name"/>. Registering the same <see cref="Type"/> with different names will create distinct registrations
/// for each <see cref="Type"/> and <paramref name="name"/> combinations. Registration with no <paramref name="name"/>
/// (<c>name == null</c>) is called <c>default registration</c>. The container uses these as implicit defaults when required.
/// </para>
/// <para>
/// Type <paramref name="mappedToType"/> will not be registered with the container. It will only be used to inform container how to
/// build the requested instance or where to redirect to satisfy the request. If the type provided in <paramref name="mappedToType"/>
/// is already registered with the container, the registration creates a mapping to the existing registration. It will redirect to that
/// registration when creating an object.
/// </para>
/// <para>
/// If <paramref name="injectionMembers"/> collection is not empty, the mapping will not redirect to other registrations. Instead, it will
/// always build the <see cref="Type"/> according to the rules set by provided <see cref="InjectionMember"/> objects.
/// </para>
/// <para>
/// Registering a <see cref="Type"/> with the same <paramref name="name"/> second time will overwrite previous registration. When
/// overwritten, registration will dispose of lifetime manager it was registered with and if that manager holds a reference to an instance
/// of a disposable object (the object implements <see cref="IDisposable"/>), it will be disposed of as well.
/// </para>
/// <para>
/// During registration, Unity performs only a limited number of checks. To enable slower but more thorough and detailed validation add
/// <c>Diagnostic</c> extension to the container.
/// </para>
/// </remarks>
/// <example>
/// This example registers a default (no name) singleton service. The service will be created with a default constructor, field and property
/// <c>Resolved</c> and <c>Injected</c> are initialized with resolved and injected values respectively, and method <c>Init</c> is called on the
/// created object.
/// <code>
/// c.RegisterType(typeof(IService), // Type to register
/// typeof(Service), // Type to create
/// null, // Default (no name)
/// TypeLifetime.Singleton, // Singleton lifetime
/// Invoke.Constructor(), // Use default ctor
/// Invoke.Method(nameof(Service.Init)), // Call Init(...)
/// Resolve.Field(nameof(Service.Resolved)) // Resolve value for Resolved
/// Inject.Property(nameof(Service.Injected), // Inject Injected
/// "value")); // with constant "value"
/// </code>
/// </example>
/// <seealso cref="Unity.Inject"/>
/// <seealso cref="Unity.Invoke"/>
/// <seealso cref="Unity.Resolve"/>
/// <seealso cref="Unity.TypeLifetime"/>
/// <exception cref="InvalidOperationException">If error occur during registration container will throw an exception.</exception>
/// <returns>The <see cref="IUnityContainer"/> object that this method was called on.</returns>
IUnityContainer RegisterType(Type? registeredType, Type mappedToType, string? name, ITypeLifetimeManager? lifetimeManager, params InjectionMember[] injectionMembers);
/// <summary>
/// Register an instance with the container.
/// </summary>
/// <param name="type">Registration <see cref="Type"/>. This parameter could be either <c>null</c> or any of the
/// interface types the instance implements. If <paramref name="type"/> is <c>null</c> the instance will be registered by its <see cref="Type"/></param>
/// <param name="instance">The Object to be registered</param>
/// <param name="name">Registration name</param>
/// <param name="lifetimeManager">An <see cref="InstanceLifetime"/> manager that controls the lifetime. If no manager is provided
/// (<c>lifetimeManager == null</c>) container uses <see cref="InstanceLifetime.PerContainer"/> lifetime by default</param>
/// <remarks>
/// <para>
/// Instance registration makes objects created outside of the container to be available for dependency injection. Container registers
/// the instance as either <see cref="Type"/> provided in <paramref name="type"/>, or as <see cref="Type"/> of the object itself (<c>instance.GetType()</c>).
/// </para>
/// <para>
/// Instances created outside of container are treated as various types of singletons. There are three different lifetimes an instance supports:
/// <list type="bullet">
/// <item>
/// <term><see cref="InstanceLifetime.External"/></term>
/// <description>- Instance is managed elsewhere. The container holds just a weak reference to the instance. An author is responsible for
/// making sure the instance is not going out of scope and garbage collected while still being used by the container.</description>
/// </item>
/// <item>
/// <term><see cref="InstanceLifetime.Singleton"/></term>
/// <description>- The instance is registered as a global singleton. This type of lifetime registers the instance with the root container
/// and makes it available to all descendants. It does not matter if an instance is registered with root container or any child containers,
/// the registration is always stored at the root.</description>
/// </item>
/// <item>
/// <term><see cref="InstanceLifetime.PerContainer"/></term>
/// <description>- Instance is registered with a particular container and is available within the container and all its descendants.</description>
/// </item>
/// </list>
/// </para>
/// </remarks>
/// <example>
/// This example registers a default (no name) service instance with externally controlled lifetime.
/// <code>
/// c.RegisterInstance(typeof(IService), // Type to register
/// null, // Default (no name)
/// instance, // Instance of Service
/// InstanceLifetime.External); // Externally controlled
/// </code>
/// </example>
/// <seealso cref="Unity.InstanceLifetime"/>
/// <exception cref="InvalidOperationException">If types of registration and the instance are not assignable, method throws an exception</exception>
/// <returns>The <see cref="IUnityContainer"/> object that this method was called on.</returns>
IUnityContainer RegisterInstance(Type? type, string? name, object? instance, IInstanceLifetimeManager? lifetimeManager);
/// <summary>
/// Register <see cref="Type"/> factory with the container
/// </summary>
/// <param name="type">Registration <see cref="Type"/>. A <see cref="Type"/> the factory will create when requested</param>
/// <param name="name">Registration name</param>
/// <param name="factory">Predefined factory delegate</param>
/// <param name="lifetimeManager">The <see cref="FactoryLifetime"/> that controls the lifetime of objects.
/// If <paramref name="lifetimeManager"/> is <c>null</c>, container uses default <see cref="TypeLifetime.Transient"/> lifetime</param>
/// <remarks>
/// <para>
/// This method allows registration of factory function for specific <see cref="Type"/>.
/// </para>
/// <para>
/// This registration is very similar to <see cref="RegisterType(Type, Type, string, ITypeLifetimeManager, InjectionMember[])"/>
/// except when registered <see cref="Type"/> is requested, instead of creating the <see cref="Type"/>, the container
/// invokes registered factory delegate and returns the instance the delegate created.
/// </para>
/// </remarks>
/// <example>
/// This example registers a service factory with transient lifetime.
/// <code>
/// c.RegisterInstance(typeof(IService), // Type to register
/// "Some Service", // Registration name
/// (c,t,n) => new Service(), // Factory
/// null); // Transient
/// </code>
/// </example>
/// <seealso cref="Unity.FactoryLifetime"/>
/// <exception cref="InvalidOperationException">If delegate is <c>null</c> method throws</exception>
/// <returns>The <see cref="IUnityContainer"/> object that this method was called on.</returns>
IUnityContainer RegisterFactory(Type type, string? name, Func<IUnityContainer, Type, string, object> factory, IFactoryLifetimeManager? lifetimeManager);
/// <summary>
/// Checks if <see cref="Type"/> is registered with container
/// </summary>
/// <param name="type"><see cref="Type"/> to look for</param>
/// <param name="name">Name of the registration</param>
/// <remarks>
/// <para>This method checks if <see cref="Type"/> with the specified <paramref name="name"/> is registered with the container.</para>
/// <para>
/// When method verifies if <see cref="Type"/> is registered, it looks not only into the current container
/// by all its predecessors as well. So if this <see cref="Type"/> not registered in the container but
/// contained by one of its parents it will still return <c>True</c>.
/// </para>
/// <para>
/// This method is quite fast. It uses the same algorithm the container employs to obtain registrations
/// and has a very small overhead. It is an order of magnitude faster than querying <see cref="IUnityContainer.Registrations"/>
/// collection.
/// </para>
/// </remarks>
/// <returns><c>True</c> if <see cref="Type"/> is registered or <c>False</c> if no registration found</returns>
bool IsRegistered(Type type, string? name);
/// <summary>
/// Lists all registrations available at this container.
/// </summary>
/// <remarks>
/// <para>
/// This collection contains all registrations from this container.
/// </para>
/// <para>
/// If this is a child container <see cref="IUnityContainer.Registrations"/> will contain all registrations from this container
/// as well as registrations from all predecessor containers. Registrations in child containers override registrations of the
/// same type and name from parent containers.
/// </para>
/// <para>
/// The sort order of returned registrations is not guaranteed in any way.
/// </para>
/// </remarks>
/// <seealso cref="IContainerRegistration"/>
/// <value>Registered with the container types</value>
IEnumerable<IContainerRegistration> Registrations { get; }
/// <summary>
/// Resolve an instance of the requested type from the container.
/// </summary>
/// <param name="type">A <see cref="Type"/> of object to resolve</param>
/// <param name="name">Name of the registration</param>
/// <param name="overrides">Overrides for dependencies</param>
/// <remarks>
/// <para>
/// During resolution Unity checks if <see cref="Type"/> is registered and uses that registration to create an object.
/// If <see cref="Type"/> is not registered it uses reflection to get information about the <see cref="Type"/> and
/// creates a pipeline to instantiate and initialize the <see cref="Type"/> using reflected data.
/// </para>
/// <para>
/// Resolver overrides passed to the method will only override dependencies configured for injection. For example, if
/// some members were marked with attributes to be injected or registered with associated <see cref="InjectionMember"/>
/// objects, only these members will be available for overriding. Override values for members not configured for injection
/// will be ignored.
/// </para>
/// <para>
/// During resolution, Unity performs only a limited number of checks. If any errors occur, error information is very brief.
/// To enable slower but more thorough and detailed validation and expanded error reporting add <c>Diagnostic</c>
/// extension to the container.
/// </para>
/// </remarks>
/// <seealso cref="Unity.Override"/>
/// <exception cref="ResolutionFailedException">Throws if any errors occur during resolution</exception>
/// <returns>The retrieved object.</returns>
object Resolve(Type type, string? name, params ResolverOverride[] overrides);
/// <summary>
/// Run an existing object through the build pipeline and perform injections on it
/// </summary>
/// <param name="type"><see cref="Type"/> of object to perform injection on.</param>
/// <param name="existing">Instance to the object.</param>
/// <param name="name">name to use when looking up the registration and other configurations.</param>
/// <param name="overrides">Any overrides for the resolve calls.</param>
/// <remarks>
/// <para>
/// This method performs all the initializations and injections on an instance of an object you
/// passed in <paramref name="existing"/>.
/// </para>
/// <para>
/// This method is useful when you don't control the construction of an
/// instance (ASP.NET pages or objects created via XAML, for instance)
/// but you still want properties and other injections performed.
/// </para>
/// </remarks>
/// <seealso cref="Unity.Override"/>
/// <exception cref="ResolutionFailedException">Throws if any errors occur during initialization</exception>
/// <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="type"/>).</returns>
object BuildUp(Type type, object existing, string? name, params ResolverOverride[] overrides);
/// <summary>
/// The parent of this container.
/// </summary>
/// <remarks>
/// If the instance of the container is a child container, this property will hold a reference to
/// the container that created this instance.
/// </remarks>
/// <value>The parent container, or null if this container doesn't have one.</value>
IUnityContainer Parent { get; }
/// <summary>
/// Create a child container.
/// </summary>
/// <remarks>
/// Unity allows creating scopes with the help of child container. A child container shares the
/// parent's configuration but can be configured with different settings or lifetime.</remarks>
/// <returns>The new child container.</returns>
IUnityContainer CreateChildContainer();
}
}

Просмотреть файл

@ -0,0 +1,27 @@

namespace Unity
{
/// <summary>
/// Options indicating how dependency should be resolved
/// </summary>
public enum ResolutionOption
{
/// <summary>
/// Required dependency
/// </summary>
/// <remarks>
/// This dependency should be either resolved or error
/// should be reported.
/// </remarks>
Required,
/// <summary>
/// Optional dependency
/// </summary>
/// <remarks>
/// This dependency should be either resolved or default
/// value will be returned.
/// </remarks>
Optional
}
}

Просмотреть файл

@ -0,0 +1,22 @@
using System;
namespace Unity
{
/// <summary>
/// Base class for attributes that can be placed on parameters
/// or properties to specify how to resolve the value for
/// that parameter or property.
/// </summary>
public abstract class DependencyResolutionAttribute : Attribute
{
protected DependencyResolutionAttribute(string? name)
{
Name = name;
}
/// <summary>
/// The name specified in the constructor.
/// </summary>
public string? Name { get; }
}
}

Просмотреть файл

@ -0,0 +1,33 @@
using System;
using System.Diagnostics;
namespace Unity
{
/// <summary>
/// This attribute is used to mark properties and parameters as targets for injection.
/// </summary>
/// <remarks>
/// For properties, this attribute is necessary for injection to happen. For parameters,
/// it's not needed unless you want to specify additional information to control how
/// the parameter is resolved.
/// </remarks>
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Parameter | AttributeTargets.Field)]
public sealed class DependencyAttribute : DependencyResolutionAttribute
{
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
internal static DependencyAttribute Instance = new DependencyAttribute();
/// <summary>
/// Create an instance of <see cref="DependencyAttribute"/> with no name.
/// </summary>
public DependencyAttribute()
: base(null) { }
/// <summary>
/// Create an instance of <see cref="DependencyAttribute"/> with the given name.
/// </summary>
/// <param name="name">Name to use when resolving this dependency.</param>
public DependencyAttribute(string? name)
: base(name) { }
}
}

Просмотреть файл

@ -0,0 +1,13 @@
using System;
namespace Unity
{
/// <summary>
/// This attribute is used to indicate which constructor to choose when
/// the container attempts to build a type.
/// </summary>
[AttributeUsage(AttributeTargets.Constructor)]
public sealed class InjectionConstructorAttribute : Attribute
{
}
}

Просмотреть файл

@ -0,0 +1,13 @@
using System;
namespace Unity
{
/// <summary>
/// This attribute is used to mark methods that should be called when
/// the container is building an object.
/// </summary>
[AttributeUsage(AttributeTargets.Method)]
public sealed class InjectionMethodAttribute : Attribute
{
}
}

Просмотреть файл

@ -0,0 +1,31 @@
using System;
using System.Diagnostics;
namespace Unity
{
/// <summary>
/// An <see cref="DependencyResolutionAttribute"/> used to mark a dependency
/// as optional - the container will try to resolve it, and return null
/// if the resolution fails rather than throw.
/// </summary>
[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Field | AttributeTargets.Property)]
public sealed class OptionalDependencyAttribute : DependencyResolutionAttribute
{
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
internal static OptionalDependencyAttribute Instance = new OptionalDependencyAttribute();
/// <summary>
/// Construct a new <see cref="OptionalDependencyAttribute"/> object.
/// </summary>
public OptionalDependencyAttribute()
: base(null) { }
/// <summary>
/// Construct a new <see cref="OptionalDependencyAttribute"/> object that
/// specifies a named dependency.
/// </summary>
/// <param name="name">Name of the dependency.</param>
public OptionalDependencyAttribute(string? name)
: base(name) { }
}
}

Просмотреть файл

@ -0,0 +1,120 @@
using System;
using System.Reflection;
using Unity.Resolution;
namespace Unity.Injection
{
/// <summary>
/// Base class for generic type parameters.
/// </summary>
public abstract class GenericBase : ParameterValue,
IResolverFactory<Type>,
IResolverFactory<ParameterInfo>
{
#region Fields
private readonly string? _name;
private readonly bool _isArray;
private readonly string _genericParameterName;
#endregion
#region Constructors
/// <summary>
/// Create a new <see cref="GenericParameter"/> instance that specifies
/// that the given named generic parameter should be resolved.
/// </summary>
/// <param name="genericParameterName">The generic parameter name to resolve.</param>
protected GenericBase(string genericParameterName)
: this(genericParameterName, null)
{ }
/// <summary>
/// Create a new <see cref="GenericParameter"/> instance that specifies
/// that the given named generic parameter should be resolved.
/// </summary>
/// <param name="genericParameterName">The generic parameter name to resolve.</param>
/// <param name="resolutionName">Registration name to use when looking up in the container.</param>
protected GenericBase(string genericParameterName, string? resolutionName)
{
if (null == genericParameterName) throw new ArgumentNullException(nameof(genericParameterName));
if (genericParameterName.EndsWith("[]", StringComparison.Ordinal) ||
genericParameterName.EndsWith("()", StringComparison.Ordinal))
{
_genericParameterName = genericParameterName.Replace("[]", string.Empty).Replace("()", string.Empty);
_isArray = true;
}
else
{
_genericParameterName = genericParameterName;
_isArray = false;
}
_name = resolutionName;
}
#endregion
#region Public Properties
/// <summary>
/// Name for the type represented by this <see cref="ParameterValue"/>.
/// This may be an actual type name or a generic argument name.
/// </summary>
public virtual string ParameterTypeName => _genericParameterName;
#endregion
#region Overrides
public override bool Equals(Type? type)
{
if (null == type) return false;
if (!_isArray)
{
return type.GetTypeInfo().IsGenericParameter &&
type.GetTypeInfo().Name == _genericParameterName;
}
return type.IsArray && type.GetElementType()!.GetTypeInfo().IsGenericParameter
&& type.GetElementType()!.GetTypeInfo().Name == _genericParameterName;
}
#endregion
#region IResolverFactory
public virtual ResolveDelegate<TContext> GetResolver<TContext>(Type type)
where TContext : IResolveContext
{
return GetResolver<TContext>(type, _name);
}
public virtual ResolveDelegate<TContext> GetResolver<TContext>(ParameterInfo info)
where TContext : IResolveContext
{
var type = info.ParameterType;
return GetResolver<TContext>(type, _name);
}
#endregion
#region Implementation
protected virtual ResolveDelegate<TContext> GetResolver<TContext>(Type type, string? name)
where TContext : IResolveContext
{
return (ref TContext context) => context.Resolve(type, name);
}
#endregion
}
}

Просмотреть файл

@ -0,0 +1,132 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace Unity.Injection
{
public static class InjectionMatching
{
#region Signature matching
public static bool MatchMemberInfo(this object[] data, MethodBase info)
{
var parameters = info.GetParameters();
if ((data?.Length ?? 0) != parameters.Length) return false;
for (var i = 0; i < (data?.Length ?? 0); i++)
{
if (Matches(data?[i], parameters[i].ParameterType))
continue;
return false;
}
return true;
}
#endregion
#region Data Matching
public static bool Matches(this object? data, Type match)
{
switch (data)
{
case IEquatable<Type> equatable:
return equatable.Equals(match);
case Type type:
return MatchesType(type, match);
default:
return MatchesObject(data, match);
}
}
public static bool MatchesType(this Type type, Type match)
{
if (null == type) return true;
#if NETSTANDARD1_0 || NETCOREAPP1_0
var typeInfo = type.GetTypeInfo();
var matchInfo = match.GetTypeInfo();
if (matchInfo.IsAssignableFrom(typeInfo)) return true;
if ((typeInfo.IsArray || typeof(Array) == type) &&
(matchInfo.IsArray || match == typeof(Array)))
return true;
if (typeInfo.IsGenericType && typeInfo.IsGenericTypeDefinition && matchInfo.IsGenericType &&
typeInfo.GetGenericTypeDefinition() == matchInfo.GetGenericTypeDefinition())
return true;
#else
if (match.IsAssignableFrom(type)) return true;
if ((type.IsArray || typeof(Array) == type) &&
(match.IsArray || match == typeof(Array)))
return true;
if (type.IsGenericType && type.IsGenericTypeDefinition && match.IsGenericType &&
type.GetGenericTypeDefinition() == match.GetGenericTypeDefinition())
return true;
#endif
return false;
}
public static bool MatchesObject(this object? parameter, Type match)
{
var type = parameter is Type ? typeof(Type) : parameter?.GetType();
if (null == type) return true;
#if NETSTANDARD1_0 || NETCOREAPP1_0
var typeInfo = type.GetTypeInfo();
var matchInfo = match.GetTypeInfo();
if (matchInfo.IsAssignableFrom(typeInfo)) return true;
if ((typeInfo.IsArray || typeof(Array) == type) &&
(matchInfo.IsArray || match == typeof(Array)))
return true;
if (typeInfo.IsGenericType && typeInfo.IsGenericTypeDefinition && matchInfo.IsGenericType &&
typeInfo.GetGenericTypeDefinition() == matchInfo.GetGenericTypeDefinition())
return true;
#else
if (match.IsAssignableFrom(type)) return true;
if ((type.IsArray || typeof(Array) == type) &&
(match.IsArray || match == typeof(Array)))
return true;
if (type.IsGenericType && type.IsGenericTypeDefinition && match.IsGenericType &&
type.GetGenericTypeDefinition() == match.GetGenericTypeDefinition())
return true;
#endif
return false;
}
#endregion
#region Error Reporting
public static string Signature(this object[] data)
{
return string.Join(", ", data?.Select(d => d.ToString()) ?? Enumerable.Empty<string>());
}
public static string Signature(this MethodBase selection)
{
var sb = new List<string>();
foreach (var parameter in selection.GetParameters())
sb.Add($"{parameter.ParameterType} {parameter.Name}");
return string.Join(", ", sb);
}
#endregion
}
}

Просмотреть файл

@ -0,0 +1,155 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using Unity.Policy;
using Unity.Resolution;
namespace Unity.Injection
{
/// <summary>
/// Base class for objects that can be used to configure what
/// class members get injected by the container.
/// </summary>
public abstract class InjectionMember
{
/// <summary>
/// Add policies to the <paramref name="policies"/> to configure the
/// container to call this constructor with the appropriate parameter values.
/// </summary>
/// <param name="registeredType">Type of interface being registered. If no interface,
/// this will be null.</param>
/// <param name="mappedToType">Type of concrete type being registered.</param>
/// <param name="name">Name used to resolve the type object.</param>
/// <param name="policies">Policy list to add policies to.</param>
public virtual void AddPolicies<TContext, TPolicySet>(Type registeredType, Type mappedToType, string name, ref TPolicySet policies)
where TContext : IResolveContext
where TPolicySet : IPolicySet
{
}
/// <summary>
/// This injection member instructs engine, when type mapping is present,
/// to build type instead of resolving it
/// </summary>
/// <remarks>
/// When types registered like this:
///
/// Line 1: container.RegisterType{OtherService}(new ContainerControlledLifetimeManager());
/// Line 2: container.RegisterType{IService, OtherService}();
/// Line 3: container.RegisterType{IOtherService, OtherService}(new InjectionConstructor(container));
///
/// It is expected that IService resolves instance registered on line 1. But when IOtherService is resolved
/// it requires different constructor so it should be built instead.
/// </remarks>
public virtual bool BuildRequired => false;
/// <summary>
/// Debugger Display support
/// </summary>
/// <param name="debug">Indicates if member is rendered in Debug mode</param>
/// <returns>String representation on the member</returns>
protected virtual string ToString(bool debug = false) => base.ToString()!;
}
[DebuggerDisplay("{ToString(true)}")]
public abstract class InjectionMember<TMemberInfo, TData> : InjectionMember,
IEquatable<TMemberInfo>
where TMemberInfo : MemberInfo
{
#region Fields
protected const string NoMatchFound = "No member matching data has been found.";
protected TMemberInfo? Selection { get; set; }
#endregion
#region Constructors
protected InjectionMember(string? name, TData data)
{
Name = name;
Data = data;
}
protected InjectionMember(TMemberInfo info, TData data)
{
Selection = info;
Name = info.Name;
Data = data;
}
#endregion
#region Public Members
public string? Name { get; }
public virtual TData Data { get; }
public abstract TMemberInfo MemberInfo(Type type);
public abstract IEnumerable<TMemberInfo> DeclaredMembers(Type type);
public bool IsInitialized => null != Selection;
#endregion
#region Equatable
public virtual bool Equals(TMemberInfo? other)
{
return Selection?.Equals(other) ?? false;
}
public override bool Equals(object? obj)
{
switch (obj)
{
case TMemberInfo info:
return Equals(info);
case IEquatable<TMemberInfo> equatable:
return equatable.Equals(Selection!);
default:
return false;
}
}
public override int GetHashCode()
{
return Selection?.GetHashCode() ?? 0;
}
#endregion
#region Overrides
public override bool BuildRequired => true;
public override void AddPolicies<TContext, TPolicySet>(Type registeredType, Type mappedToType, string name, ref TPolicySet policies)
{
var select = policies.Get<Func<Type, InjectionMember, TMemberInfo>>()
?? SelectMember;
Selection = select(mappedToType, this);
}
public override string ToString() => ToString(false);
#endregion
#region Implementation
protected virtual TMemberInfo SelectMember(Type type, InjectionMember member) => throw new NotImplementedException();
#endregion
}
}

Просмотреть файл

@ -0,0 +1,75 @@
using System;
using System.Reflection;
namespace Unity.Injection
{
public abstract class MemberInfoBase<TMemberInfo> : InjectionMember<TMemberInfo, object>
where TMemberInfo : MemberInfo
{
#region Constructors
protected MemberInfoBase(string name, object data)
: base(name, data)
{
}
#endregion
#region Overrides
public override TMemberInfo MemberInfo(Type type)
{
#if NETSTANDARD1_0 || NETCOREAPP1_0
var declaringType = Selection!.DeclaringType.GetTypeInfo();
if (!declaringType.IsGenericType && !declaringType.ContainsGenericParameters)
return Selection;
#else
if (Selection!.DeclaringType != null &&
!Selection.DeclaringType.IsGenericType &&
!Selection.DeclaringType.ContainsGenericParameters)
return Selection;
#endif
return DeclaredMember(type, Selection.Name);
}
protected override TMemberInfo SelectMember(Type type, InjectionMember _)
{
foreach (var member in DeclaredMembers(type))
{
if (member.Name != Name) continue;
return member;
}
throw new ArgumentException(NoMatchFound);
}
#if NETSTANDARD1_0
public override bool Equals(TMemberInfo? other)
{
return null != other && other.Name == Name;
}
#endif
#endregion
#region Implementation
protected abstract TMemberInfo DeclaredMember(Type type, string name);
protected abstract Type MemberType { get; }
#endregion
#region Debug
protected override string ToString(bool debug = false) => null == Selection
? $"{GetType().Name}: {Name}"
: $"{GetType().Name}: {Selection.DeclaringType}.{Name}";
#endregion
}
}

Просмотреть файл

@ -0,0 +1,100 @@
using System;
using System.Linq;
using System.Reflection;
namespace Unity.Injection
{
public abstract class MethodBase<TMemberInfo> : InjectionMember<TMemberInfo, object[]>
where TMemberInfo : MethodBase
{
#region Constructors
protected MethodBase(string? name, params object[] arguments)
: base(name, arguments)
{
}
protected MethodBase(TMemberInfo info, params object[] arguments)
: base(info, arguments)
{
}
#endregion
#region Overrides
public override TMemberInfo MemberInfo(Type type)
{
var methodHasOpenGenericParameters = Selection!.GetParameters()
.Select(p => p.ParameterType.GetTypeInfo())
.Any(i => i.IsGenericType && i.ContainsGenericParameters);
var info = Selection!.DeclaringType!.GetTypeInfo();
if (!methodHasOpenGenericParameters && !(info.IsGenericType && info.ContainsGenericParameters))
return Selection;
#if NETSTANDARD1_0
var typeInfo = type.GetTypeInfo();
var parameterTypes = Selection!.GetParameters()
.Select(pi => GetClosedParameterType(pi.ParameterType, typeInfo.GenericTypeArguments))
.ToArray();
var member = DeclaredMembers(type).Single(m => m.Name.Equals(Selection.Name) && ParametersMatch(m.GetParameters(), parameterTypes));
if (null != member) return member;
bool ParametersMatch(ParameterInfo[] parameters, Type[] closedConstructorParameterTypes)
{
if ((parameters ?? throw new ArgumentNullException(nameof(parameters))).Length !=
(closedConstructorParameterTypes ?? throw new ArgumentNullException(nameof(closedConstructorParameterTypes))).Length)
{
return false;
}
return !parameters.Where((t, i) => !t.ParameterType.Equals(closedConstructorParameterTypes[i])).Any();
}
Type GetClosedParameterType(Type typeToReflect, Type[] genericArguments)
{
// Prior version of the framework returned both generic type arguments and parameters
// through one mechanism, now they are broken out. May want to consider different reflection
// helpers instead of this case statement.
var tInfo = typeToReflect.GetTypeInfo();
if (tInfo.IsGenericType && tInfo.ContainsGenericParameters)
{
Type[] typeArgs = tInfo.IsGenericTypeDefinition ? tInfo.GenericTypeParameters : tInfo.GenericTypeArguments;
for (int i = 0; i < typeArgs.Length; ++i)
{
typeArgs[i] = (genericArguments ?? throw new ArgumentNullException(nameof(genericArguments)))[typeArgs[i].GenericParameterPosition];
}
return typeToReflect.GetGenericTypeDefinition().MakeGenericType(typeArgs);
}
if (typeToReflect.IsArray)
{
return typeToReflect.GetArrayParameterType(genericArguments);
}
if (tInfo.IsGenericParameter)
{
return genericArguments[typeToReflect.GenericParameterPosition];
}
return typeToReflect;
}
#else
foreach (var member in DeclaredMembers(type))
{
if (member.MetadataToken == Selection.MetadataToken)
return member;
}
#endif
throw new InvalidOperationException($"Error selecting member on type {type}");
}
#endregion
}
}

Просмотреть файл

@ -0,0 +1,65 @@
using System;
using System.Reflection;
namespace Unity.Injection
{
/// <summary>
/// A base class for implementing <see cref="ParameterValue"/> classes
/// that deal in explicit types.
/// </summary>
public abstract class ParameterBase : ParameterValue
{
#region Fields
private readonly Type? _type;
#endregion
#region Constructors
/// <summary>
/// Create a new <see cref="ParameterBase"/> that exposes
/// information about the given <paramref name="parameterType"/>.
/// </summary>
/// <param name="parameterType">Type of the parameter.</param>
protected ParameterBase(Type? parameterType = null)
{
_type = parameterType;
}
#endregion
#region Public Properties
/// <summary>
/// The type of parameter this object represents.
/// </summary>
public virtual Type? ParameterType => _type;
#endregion
#region Overrides
public override bool Equals(Type? type)
{
if (null == _type) return true;
if (null == type) return false;
var cInfo = type.GetTypeInfo();
var info = _type.GetTypeInfo();
if (cInfo.IsGenericType && cInfo.ContainsGenericParameters && info.IsGenericType && info.ContainsGenericParameters)
{
return type!.GetGenericTypeDefinition() == _type.GetGenericTypeDefinition();
}
return cInfo.IsAssignableFrom(info);
}
#endregion
}
}

Просмотреть файл

@ -0,0 +1,18 @@
using System;
namespace Unity.Injection
{
/// <summary>
/// Base type for objects that are used to configure parameters for
/// constructor or method injection, or for getting the value to
/// be injected into a property.
/// </summary>
public abstract class ParameterValue : IEquatable<Type>
{
#region IEquatable
public abstract bool Equals(Type? type);
#endregion
}
}

Просмотреть файл

@ -0,0 +1,76 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace Unity.Injection
{
/// <summary>
/// A class that holds the collection of information
/// for a constructor, so that the container can
/// be configured to call this constructor.
/// </summary>
public class InjectionConstructor : MethodBase<ConstructorInfo>
{
#region Constructors
/// <summary>
/// Create a new instance of <see cref="InjectionConstructor"/> that looks
/// for a constructor with the given set of parameters.
/// </summary>
/// <param name="arguments">The values for the constructor's parameters, that will
/// be used to create objects.</param>
public InjectionConstructor(params object[] arguments)
: base((string?)null, arguments)
{
}
public InjectionConstructor(ConstructorInfo info, params object[] arguments)
: base((string?)null, arguments)
{
Selection = info;
}
#endregion
#region Overrides
protected override ConstructorInfo SelectMember(Type type, InjectionMember _)
{
foreach (var member in DeclaredMembers(type))
{
if (!Data.MatchMemberInfo(member)) continue;
return member;
}
throw new ArgumentException(NoMatchFound);
}
public override IEnumerable<ConstructorInfo> DeclaredMembers(Type type)
{
return type.GetTypeInfo()
.DeclaredConstructors
.Where(ctor => !ctor.IsFamily && !ctor.IsPrivate && !ctor.IsStatic);
}
protected override string ToString(bool debug = false)
{
if (debug)
{
return null == Selection
? $"{GetType().Name}: ctor({Data.Signature()})"
: $"{GetType().Name}: {Selection.DeclaringType}({Selection.Signature()})";
}
else
{
return null == Selection
? $"Invoke.Constructor({Data.Signature()})"
: $"Invoke {Selection.DeclaringType}({Selection.Signature()})";
}
}
#endregion
}
}

Просмотреть файл

@ -0,0 +1,119 @@
using System;
using Unity.Lifetime;
using Unity.Resolution;
namespace Unity.Injection
{
/// <inheritdoc />
/// <summary>
/// A class that lets you specify a factory method the container
/// will use to create the object.
/// </summary>
/// <remarks>This factory allow using predefined <code>Func&lt;IUnityContainer, Type, string, object&gt;</code> to create types.</remarks>
[Obsolete("InjectionFactory has been deprecated and will be removed in next release. Please use IUnityContainer.RegisterFactory(...) method instead.", false)]
public class InjectionFactory : InjectionMember
{
#region Fields
private readonly Func<IUnityContainer, Type, string?, object> _factoryFunc;
#endregion
#region Constructors
/// <summary>
/// Create a new instance of <see cref="InjectionFactory"/> with
/// the given factory function.
/// </summary>
/// <param name="factoryFunc">Factory function.</param>
public InjectionFactory(Func<IUnityContainer, object> factoryFunc)
{
if (null == factoryFunc) throw new ArgumentNullException(nameof(factoryFunc));
_factoryFunc = (c, t, s) => factoryFunc(c);
}
/// <summary>
/// Create a new instance of <see cref="InjectionFactory"/> with
/// the given factory function.
/// </summary>
/// <param name="factoryFunc">Factory function.</param>
public InjectionFactory(Func<IUnityContainer, Type, string?, object> factoryFunc)
{
_factoryFunc = factoryFunc ?? throw new ArgumentNullException(nameof(factoryFunc));
}
#endregion
#region InjectionMember
/// <summary>
/// Add policies to the <paramref name="policies"/> to configure the
/// container to call this constructor with the appropriate parameter values.
/// </summary>
/// <param name="registeredType">Type of interface being registered. If no interface,
/// this will be null. This parameter is ignored in this implementation.</param>
/// <param name="mappedToType">Type of concrete type being registered.</param>
/// <param name="name">Name used to resolve the type object.</param>
/// <param name="policies">Policy list to add policies to.</param>
public override void AddPolicies<TContext, TPolicySet>(Type registeredType, Type mappedToType, string name, ref TPolicySet policies)
{
// Verify
if (null != mappedToType && mappedToType != registeredType)
throw new InvalidOperationException(
"Registration where both MappedToType and InjectionFactory are set is not supported");
// Check if Per Resolve lifetime is required
var lifetime = policies.Get(typeof(LifetimeManager));
if (lifetime is PerResolveLifetimeManager)
{
policies.Set(typeof(ResolveDelegate<TContext>), CreatePerResolveLegacyPolicy());
}
else
{
policies.Set(typeof(ResolveDelegate<TContext>), CreateLegacyPolicy());
}
// Factory methods
ResolveDelegate<TContext> CreateLegacyPolicy()
{
return (ref TContext c) => _factoryFunc(c.Container, c.Type, c.Name);
}
ResolveDelegate<TContext> CreatePerResolveLegacyPolicy()
{
return (ref TContext context) =>
{
var result = _factoryFunc(context.Container, context.Type, context.Name);
var perBuildLifetime = new InternalPerResolveLifetimeManager(result);
context.Set(context.Type, context.Name, typeof(LifetimeManager), perBuildLifetime);
return result;
};
}
}
protected override string ToString(bool debug = false)
{
throw new NotImplementedException();
}
#endregion
#region Nested Types
internal sealed class InternalPerResolveLifetimeManager : PerResolveLifetimeManager
{
public InternalPerResolveLifetimeManager(object obj)
{
value = obj;
InUse = true;
}
}
#endregion
}
}

Просмотреть файл

@ -0,0 +1,79 @@
using System;
using System.Collections.Generic;
using System.Reflection;
namespace Unity.Injection
{
public class InjectionField : MemberInfoBase<FieldInfo>
{
#region Constructors
/// <summary>
/// Configure the container to inject the given field name.
/// </summary>
/// <param name="name">Name of property to inject.</param>
/// <param name="option">Tells Unity if this field is optional.</param>
public InjectionField(string name, ResolutionOption option = ResolutionOption.Required)
: base(name, ResolutionOption.Optional == option ? OptionalDependencyAttribute.Instance
: (object)DependencyAttribute.Instance)
{
}
/// <summary>
/// Configure the container to inject the given field name,
/// using the value supplied.
/// </summary>
/// <param name="name">Name of property to inject.</param>
/// <param name="value">InjectionParameterValue for property.</param>
public InjectionField(string name, object value)
: base(name, value)
{
}
#endregion
#region Overrides
protected override FieldInfo DeclaredMember(Type type, string name)
{
#if NETSTANDARD1_0 || NETCOREAPP1_0
return type.GetTypeInfo().GetDeclaredField(Selection!.Name)!;
#else
return type.GetField(Selection!.Name)!;
#endif
}
public override IEnumerable<FieldInfo> DeclaredMembers(Type type)
{
foreach (var member in type.GetDeclaredFields())
{
if (!member.IsFamily && !member.IsPrivate &&
!member.IsInitOnly && !member.IsStatic)
yield return member;
}
}
protected override Type MemberType => Selection!.FieldType;
protected override string ToString(bool debug = false)
{
if (debug)
{
return base.ToString(debug);
}
else
{
return Data is DependencyResolutionAttribute
? null == Selection
? $"Resolve.Field('{Name}')"
: $"Resolve: '{Selection.DeclaringType}.{Name}'"
: null == Selection
? $"Inject.Field('{Name}', {Data})"
: $"Inject: '{Selection.DeclaringType}.{Name}' with '{Data}'";
}
}
#endregion
}
}

Просмотреть файл

@ -0,0 +1,100 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace Unity.Injection
{
/// <summary>
/// An <see cref="InjectionMember"/> that configures the
/// container to call a method as part of buildup.
/// </summary>
public class InjectionMethod : MethodBase<MethodInfo>
{
#region Constructors
/// <summary>
/// Create a new <see cref="InjectionMethod"/> instance which will configure
/// the container to call the given methods with the given parameters.
/// </summary>
/// <param name="name">Name of the method to call.</param>
/// <param name="arguments">Parameter values for the method.</param>
public InjectionMethod(string name, params object[] arguments)
: base(name, arguments)
{
}
#endregion
#region Overrides
protected override MethodInfo SelectMember(Type type, InjectionMember _)
{
var noData = 0 == (Data?.Length ?? 0);
foreach (var member in DeclaredMembers(type))
{
if (null != Name)
{
if (Name != member.Name) continue; // TODO: redundant check. Remove!
if (noData) return member;
}
if (!Data!.MatchMemberInfo(member)) continue;
return member;
}
throw new ArgumentException(NoMatchFound);
}
public override IEnumerable<MethodInfo> DeclaredMembers(Type type)
{
foreach (var member in type.GetDeclaredMethods())
{
if (!member.IsFamily && !member.IsPrivate &&
!member.IsStatic && member.Name == Name)
yield return member;
}
}
protected override string ToString(bool debug = false)
{
if (debug)
{
return null == Selection
? $"{GetType().Name}: {Name}({Data.Signature()})"
: $"{GetType().Name}: {Selection.DeclaringType}.{Name}({Selection.Signature()})";
}
else
{
return null == Selection
? $"Invoke.Method('{Name}', {Data.Signature()})"
: $"Invoke: {Selection.DeclaringType}.{Name}({Selection.Signature()})";
}
}
#if NETSTANDARD1_0
public override bool Equals(MethodInfo? other)
{
if (null == other || other.Name != Name) return false;
var parameterTypes = other.GetParameters()
.Select(p => p.ParameterType)
.ToArray();
if (Selection!.ContainsGenericParameters)
return Data.Length == parameterTypes.Length;
return Selection.GetParameters()
.Select(p => p.ParameterType)
.SequenceEqual(parameterTypes);
}
#endif
#endregion
}
}

Просмотреть файл

@ -0,0 +1,86 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace Unity.Injection
{
/// <summary>
/// This class stores information about which properties to inject,
/// and will configure the container accordingly.
/// </summary>
public class InjectionProperty : MemberInfoBase<PropertyInfo>
{
#region Constructors
/// <summary>
/// Configure the container to inject the given property name,
/// using the value supplied.
/// </summary>
/// <param name="name">Name of property to inject.</param>
/// <param name="option">Tells Unity if this field is optional.</param>
public InjectionProperty(string name, ResolutionOption option = ResolutionOption.Required)
: base(name, ResolutionOption.Optional == option ? OptionalDependencyAttribute.Instance
: (object)DependencyAttribute.Instance)
{
}
/// <summary>
/// Configure the container to inject the given property name,
/// using the value supplied.
/// </summary>
/// <param name="name">Name of property to inject.</param>
/// <param name="value">InjectionParameterValue for property.</param>
public InjectionProperty(string name, object value)
: base(name, value)
{
}
#endregion
#region Overrides
protected override PropertyInfo DeclaredMember(Type type, string name)
{
return DeclaredMembers(type).FirstOrDefault(p => p.Name == Selection?.Name)!;
}
public override IEnumerable<PropertyInfo> DeclaredMembers(Type type)
{
foreach (var member in type.GetDeclaredProperties())
{
if (!member.CanWrite || 0 != member.GetIndexParameters().Length)
continue;
var setter = member.GetSetMethod(true)!;
if (setter.IsPrivate || setter.IsFamily)
continue;
yield return member;
}
}
protected override Type MemberType => Selection!.PropertyType;
protected override string ToString(bool debug = false)
{
if (debug)
{
return base.ToString(debug);
}
else
{
return Data is DependencyResolutionAttribute
? null == Selection
? $"Resolve.Property('{Name}')"
: $"Resolve: '{Selection.DeclaringType}.{Name}'"
: null == Selection
? $"Inject.Property('{Name}', {Data})"
: $"Inject: '{Selection.DeclaringType}.{Name}' with {Data})";
}
}
#endregion
}
}

Просмотреть файл

@ -0,0 +1,45 @@
using System.Diagnostics;
namespace Unity.Injection
{
/// <summary>
/// A <see cref="ParameterValue"/> that lets you specify that
/// an instance of a generic type parameter should be resolved.
/// </summary>
[DebuggerDisplay("GenericParameter: Type={ParameterTypeName}")]
public class GenericParameter : GenericBase
{
#region Constructors
/// <summary>
/// Create a new <see cref="GenericParameter"/> instance that specifies
/// that the given named generic parameter should be resolved.
/// </summary>
/// <param name="genericParameterName">The generic parameter name to resolve.</param>
public GenericParameter(string genericParameterName)
: base(genericParameterName)
{ }
/// <summary>
/// Create a new <see cref="GenericParameter"/> instance that specifies
/// that the given named generic parameter should be resolved.
/// </summary>
/// <param name="genericParameterName">The generic parameter name to resolve.</param>
/// <param name="name">Registration name to use when looking up in the container.</param>
public GenericParameter(string genericParameterName, string name)
: base(genericParameterName, name)
{ }
#endregion
#region Overrides
public override string ToString()
{
return $"GenericParameter: Type={ParameterTypeName}";
}
#endregion
}
}

Просмотреть файл

@ -0,0 +1,131 @@
using System;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using Unity.Resolution;
namespace Unity.Injection
{
/// <summary>
/// A <see cref="ParameterValue"/> that lets you specify that
/// an array containing the registered instances of a generic type parameter
/// should be resolved.
/// </summary>
[DebuggerDisplay("GenericResolvedArrayParameter: Type={ParameterTypeName}")]
public class GenericResolvedArrayParameter : GenericBase
{
#region Fields
private readonly object[] _values;
private static readonly MethodInfo ResolverMethod =
typeof(GenericResolvedArrayParameter).GetTypeInfo().GetDeclaredMethod(nameof(DoResolve))!;
private delegate object Resolver<TContext>(ref TContext context, object[] values)
where TContext : IResolveContext;
#endregion
#region Constructors
/// <summary>
/// Create a new <see cref="GenericResolvedArrayParameter"/> instance that specifies
/// that the given named generic parameter should be resolved.
/// </summary>
/// <param name="genericParameterName">The generic parameter name to resolve.</param>
/// <param name="elementValues">The values for the elements, that will
/// be converted to <see cref="ParameterValue"/> objects.</param>
public GenericResolvedArrayParameter(string genericParameterName, params object[] elementValues)
: base(genericParameterName)
{
_values = elementValues;
}
#endregion
#region Overrides
/// <summary>
/// Name for the type represented by this <see cref="ParameterValue"/>.
/// This may be an actual type name or a generic argument name.
/// </summary>
public override string ParameterTypeName => base.ParameterTypeName + "[]";
public override bool Equals(Type? type)
{
if (null == type || !type.IsArray || type.GetArrayRank() != 1)
{
return false;
}
Type elementType = type.GetElementType()!;
return elementType.GetTypeInfo().IsGenericParameter && elementType.GetTypeInfo().Name == base.ParameterTypeName;
}
protected override ResolveDelegate<TContext> GetResolver<TContext>(Type type, string? name)
{
Type elementType = type.GetElementType()!;
var resolverMethod = (Resolver<TContext>)ResolverMethod.MakeGenericMethod(typeof(TContext), elementType)
.CreateDelegate(typeof(Resolver<TContext>));
var values = _values.Select(value =>
{
switch (value)
{
case IResolverFactory<Type> factory:
return factory.GetResolver<TContext>(elementType);
case Type _ when typeof(Type) != elementType:
return (ResolveDelegate<TContext>)((ref TContext context) => context.Resolve(elementType, null));
default:
return value;
}
}).ToArray();
return (ref TContext context) => resolverMethod.Invoke(ref context, values);
}
public override string ToString()
{
return $"GenericResolvedArrayParameter: Type={ParameterTypeName}";
}
#endregion
#region Implementation
public static object? DoResolve<TContext, TElement>(ref TContext context, object[] values)
where TContext : IResolveContext
{
var result = new TElement?[values.Length];
for (var i = 0; i < values.Length; i++)
{
result[i] = (TElement?)ResolveValue(ref context, values[i]);
}
return result;
// Interpret factories
object? ResolveValue(ref TContext c, object value)
{
switch (value)
{
case ResolveDelegate<TContext> resolver:
return resolver(ref c);
case IResolve policy:
return policy.Resolve(ref c);
}
return value;
}
}
#endregion
}
}

Просмотреть файл

@ -0,0 +1,88 @@
using System;
using System.Diagnostics;
using Unity.Resolution;
namespace Unity.Injection
{
/// <summary>
/// A class that holds on to the given value and provides
/// the required <see cref="IResolve"/>
/// when the container is configured.
/// </summary>
[DebuggerDisplay("InjectionParameter: Type={ParameterType.Name ?? \"Any\"} Value={_value ?? \"null\"}")]
public class InjectionParameter : ParameterBase, IResolve
{
#region Fields
private readonly object? _value;
#endregion
#region Constructors
/// <summary>
/// Create an instance of <see cref="InjectionParameter"/> that stores
/// the given value, using the runtime type of that value as the
/// type of the parameter.
/// </summary>
/// <param name="value">Value to be injected for this parameter.</param>
public InjectionParameter(object? value)
: base((value ?? throw new ArgumentNullException(nameof(value))).GetType())
{
_value = value;
}
/// <summary>
/// Create an instance of <see cref="InjectionParameter"/> that stores
/// the given value, associated with the given type.
/// </summary>
/// <param name="parameterType">Type of the parameter.</param>
/// <param name="parameterValue">InjectionParameterValue of the parameter</param>
public InjectionParameter(Type parameterType, object? parameterValue)
: base(parameterType)
{
_value = parameterValue;
}
#endregion
#region IResolve
public object? Resolve<TContext>(ref TContext context)
where TContext : IResolveContext
{
return _value;
}
#endregion
#region Overrides
public override string ToString()
{
return $"InjectionParameter: Type={ParameterType?.Name} Value={_value ?? "null"}";
}
#endregion
}
/// <summary>
/// A generic version of <see cref="InjectionParameter"/> that makes it a
/// little easier to specify the type of the parameter.
/// </summary>
/// <typeparam name="TParameter">Type of parameter.</typeparam>
public class InjectionParameter<TParameter> : InjectionParameter
{
/// <summary>
/// Create a new <see cref="InjectionParameter{TParameter}"/>.
/// </summary>
/// <param name="value">Value for the parameter to be injected.</param>
public InjectionParameter(TParameter value)
: base(typeof(TParameter), value)
{
}
}
}

Просмотреть файл

@ -0,0 +1,62 @@
using System;
using System.Diagnostics;
using Unity.Exceptions;
using Unity.Resolution;
namespace Unity.Injection
{
/// <summary>
/// A <see cref="ParameterValue"/> that lets you specify that
/// an instance of a generic type parameter should be resolved, providing the <see langword="null"/>
/// value if resolving fails.
/// </summary>
[DebuggerDisplay("OptionalGenericParameter: Type={ParameterTypeName}")]
public class OptionalGenericParameter : GenericBase
{
#region Constructors
/// <summary>
/// Create a new <see cref="GenericParameter"/> instance that specifies
/// that the given named generic parameter should be resolved.
/// </summary>
/// <param name="genericParameterName">The generic parameter name to resolve.</param>
public OptionalGenericParameter(string genericParameterName)
: base(genericParameterName)
{ }
/// <summary>
/// Create a new <see cref="GenericParameter"/> instance that specifies
/// that the given named generic parameter should be resolved.
/// </summary>
/// <param name="genericParameterName">The generic parameter name to resolve.</param>
/// <param name="name">Registration name to use when looking up in the container.</param>
public OptionalGenericParameter(string genericParameterName, string name)
: base(genericParameterName, name)
{ }
#endregion
#region Overrides
protected override ResolveDelegate<TContext> GetResolver<TContext>(Type type, string? name)
{
return (ref TContext context) =>
{
try { return context.Resolve(type, name); }
catch (Exception ex)
when (!(ex is CircularDependencyException))
{
return null;
}
};
}
public override string ToString()
{
return $"OptionalGenericParameter: Type={ParameterTypeName}";
}
#endregion
}
}

Просмотреть файл

@ -0,0 +1,166 @@
using System;
using System.Diagnostics;
using System.Reflection;
using Unity.Exceptions;
using Unity.Resolution;
namespace Unity.Injection
{
/// <summary>
/// A <see cref="ParameterValue"/> that can be passed to
/// <see cref="IUnityContainer.RegisterType"/> to configure a
/// parameter or property as an optional dependency.
/// </summary>
[DebuggerDisplay("OptionalParameter: Type={ParameterType?.Name ?? \"Any\"} Name={_name ?? \"null\"}")]
public class OptionalParameter : ParameterBase,
IResolverFactory<Type>,
IResolverFactory<ParameterInfo>
{
#region Fields
private readonly string? _name;
#endregion
#region Constructors
/// <summary>
/// Construct a new <see cref="OptionalParameter"/> instance that
/// specifies to optionally resolve whatever <see cref="Type"/> specified
/// at this position
/// </summary>
public OptionalParameter()
{
}
/// <summary>
/// Construct a new <see cref="OptionalParameter"/> object that
/// specifies the given <paramref name="type"/>.
/// </summary>
/// <param name="type">Type of the dependency.</param>
public OptionalParameter(Type type)
: base(type)
{
}
/// <summary>
/// Construct a new <see cref="OptionalParameter"/> object that
/// specifies the given <paramref name="name"/>.
/// </summary>
/// <param name="name">Name for the dependency.</param>
public OptionalParameter(string name)
{
_name = name;
}
/// <summary>
/// Construct a new <see cref="OptionalParameter"/> object that
/// specifies the given <paramref name="type"/> and <paramref name="name"/>.
/// </summary>
/// <param name="type">Type of the dependency.</param>
/// <param name="name">Name for the dependency.</param>
public OptionalParameter(Type type, string? name)
: base(type)
{
_name = name;
}
#endregion
#region IResolverFactory
public ResolveDelegate<TContext> GetResolver<TContext>(Type type)
where TContext : IResolveContext
{
return (ref TContext c) =>
{
try { return c.Resolve(ParameterType ?? type, _name); }
catch (Exception ex)
when (!(ex is CircularDependencyException))
{
return null;
}
};
}
public ResolveDelegate<TContext> GetResolver<TContext>(ParameterInfo info)
where TContext : IResolveContext
{
#if NET40
object value = null;
#else
var value = info.HasDefaultValue ? info.DefaultValue : null;
#endif
#if NETSTANDARD1_0 || NETCOREAPP1_0
var typeInfo = ParameterType?.GetTypeInfo();
if (null == typeInfo || typeInfo.IsGenericType && typeInfo.ContainsGenericParameters ||
ParameterType!.IsArray && ParameterType.GetElementType()!.GetTypeInfo().IsGenericParameter ||
ParameterType.IsGenericParameter)
#else
if (null == ParameterType || ParameterType.IsGenericType && ParameterType.ContainsGenericParameters ||
ParameterType!.IsArray && ParameterType.GetElementType()!.IsGenericParameter ||
ParameterType.IsGenericParameter)
#endif
{
var type = info.ParameterType;
return (ref TContext c) =>
{
try { return c.Resolve(type, _name); }
catch (Exception ex)
when (!(ex is CircularDependencyException))
{
return value;
}
};
}
return (ref TContext c) =>
{
try { return c.Resolve(ParameterType, _name); }
catch (Exception ex)
when (!(ex is CircularDependencyException))
{
return value;
}
};
}
#endregion
#region Overrides
public override string ToString()
{
return $"OptionalParameter: Type={ParameterType?.Name ?? "Any"} Name={_name ?? "null"}";
}
#endregion
}
/// <summary>
/// A generic version of <see cref="OptionalParameter"></see> that lets you
/// specify the type of the dependency using generics syntax.
/// </summary>
/// <typeparam name="T">Type of the dependency.</typeparam>
public class OptionalParameter<T> : OptionalParameter
{
/// <summary>
/// Construct a new <see cref="OptionalParameter{T}"/>.
/// </summary>
public OptionalParameter() : base(typeof(T))
{
}
/// <summary>
/// Construct a new <see cref="OptionalParameter{T}"/> with the given
/// <paramref name="name"/>.
/// </summary>
/// <param name="name">Name of the dependency.</param>
public OptionalParameter(string name) : base(typeof(T), name)
{
}
}
}

Просмотреть файл

@ -0,0 +1,169 @@
using System;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using Unity.Resolution;
namespace Unity.Injection
{
/// <summary>
/// A class that stores a type, and generates a
/// resolver object that resolves all the named instances or the
/// type registered in a container.
/// </summary>
[DebuggerDisplay("ResolvedArrayParameter: Type={ParameterType.Name}")]
public class ResolvedArrayParameter : ParameterBase,
IResolverFactory<Type>,
IResolverFactory<ParameterInfo>
{
#region Fields
private readonly object[] _values;
private readonly Type _elementType;
private static readonly MethodInfo ResolverMethod =
typeof(GenericResolvedArrayParameter).GetTypeInfo().GetDeclaredMethod(nameof(GenericResolvedArrayParameter.DoResolve))!;
private delegate object Resolver<TContext>(ref TContext context, object[] values)
where TContext : IResolveContext;
#endregion
#region Constructors
/// <summary>
/// Construct a new <see cref="ResolvedArrayParameter"/> that
/// resolves to the given element type and collection of element values.
/// </summary>
/// <param name="elementType">The type of elements to resolve.</param>
/// <param name="elementValues">The values for the elements, that will
/// be converted to <see cref="ParameterValue"/> objects.</param>
public ResolvedArrayParameter(Type elementType, params object[] elementValues)
: this(elementType.MakeArrayType(), elementType, elementValues)
{
}
/// <summary>
/// Construct a new <see cref="ResolvedArrayParameter"/> that
/// resolves to the given array and element types and collection of element values.
/// </summary>
/// <param name="arrayParameterType">The type for the array of elements to resolve.</param>
/// <param name="elementType">The type of elements to resolve.</param>
/// <param name="elementValues">The values for the elements, that will
/// be converted to <see cref="ParameterValue"/> objects.</param>
protected ResolvedArrayParameter(Type arrayParameterType, Type elementType, params object[] elementValues)
: base(arrayParameterType)
{
_elementType = elementType ?? throw new ArgumentNullException(nameof(elementType));
_values = elementValues;
// Verify array elements
foreach (var pv in elementValues)
{
#if NETSTANDARD1_0 || NETCOREAPP1_0
var info = _elementType.GetTypeInfo();
if ((pv is IEquatable<Type> equatable && equatable.Equals(elementType)) ||
(pv is Type type && type == _elementType) || info.IsAssignableFrom(pv?.GetType().GetTypeInfo()))
continue;
#else
if ((pv is IEquatable<Type> equatable && equatable.Equals(elementType)) ||
(pv is Type type && type == _elementType) || _elementType.IsAssignableFrom(pv?.GetType()))
continue;
#endif
throw new InvalidOperationException(
$"The type {pv?.GetType()} cannot be assigned to variables of type {elementType}.");
}
}
#endregion
#region IResolverFactory
public ResolveDelegate<TContext> GetResolver<TContext>(Type type)
where TContext : IResolveContext
{
var elementType = !_elementType.IsArray
? _elementType
: _elementType.GetArrayParameterType(type.GetTypeInfo()
.GenericTypeArguments);
var resolverMethod = (Resolver<TContext>)ResolverMethod.MakeGenericMethod(typeof(TContext), elementType)
.CreateDelegate(typeof(Resolver<TContext>));
var values = _values.Select(value =>
{
switch (value)
{
case IResolverFactory<Type> factory:
return factory.GetResolver<TContext>(elementType);
case Type _ when typeof(Type) != elementType:
return (ResolveDelegate<TContext>)((ref TContext context) => context.Resolve(elementType, null));
default:
return value;
}
}).ToArray();
return (ref TContext context) => resolverMethod.Invoke(ref context, values);
}
public ResolveDelegate<TContext> GetResolver<TContext>(ParameterInfo info)
where TContext : IResolveContext
{
var elementType = (info.ParameterType.IsArray ? info.ParameterType.GetElementType() : _elementType)!;
var resolverMethod = (Resolver<TContext>)ResolverMethod.MakeGenericMethod(typeof(TContext), elementType)
.CreateDelegate(typeof(Resolver<TContext>));
var values = _values.Select(value =>
{
switch (value)
{
case IResolverFactory<Type> factory:
return factory.GetResolver<TContext>(elementType);
case Type _ when typeof(Type) != elementType:
return (ResolveDelegate<TContext>)((ref TContext context) => context.Resolve(elementType, null));
default:
return value;
}
}).ToArray();
return (ref TContext context) => resolverMethod.Invoke(ref context, values);
}
#endregion
#region Overrides
public override string ToString()
{
return $"ResolvedArrayParameter: Type={ParameterType?.Name}";
}
#endregion
}
/// <summary>
/// A generic version of <see cref="ResolvedArrayParameter"/> for convenience
/// when creating them by hand.
/// </summary>
/// <typeparam name="TElement">Type of the elements for the array of the parameter.</typeparam>
public class ResolvedArrayParameter<TElement> : ResolvedArrayParameter
{
/// <summary>
/// Construct a new <see cref="ResolvedArrayParameter{TElement}"/> that
/// resolves to the given element generic type with the given element values.
/// </summary>
/// <param name="elementValues">The values for the elements, that will
/// be converted to <see cref="ParameterValue"/> objects.</param>
public ResolvedArrayParameter(params object[] elementValues)
: base(typeof(TElement[]), typeof(TElement), elementValues)
{
}
}
}

Просмотреть файл

@ -0,0 +1,146 @@
using System;
using System.Diagnostics;
using System.Reflection;
using Unity.Resolution;
namespace Unity.Injection
{
/// <summary>
/// A class that stores a name and type, and generates a
/// resolver object that resolves the parameter via the
/// container.
/// </summary>
[DebuggerDisplay("ResolvedParameter: Type={ParameterType?.Name ?? \"Any\"} Name={_name ?? \"null\"}")]
public class ResolvedParameter : ParameterBase,
IResolverFactory<Type>,
IResolverFactory<ParameterInfo>
{
#region Fields
private readonly string? _name;
#endregion
#region Constructors
public ResolvedParameter()
{
}
/// <summary>
/// Construct a new <see cref="ResolvedParameter"/> that
/// resolves to the given type.
/// </summary>
/// <param name="parameterType">Type of this parameter.</param>
public ResolvedParameter(Type parameterType)
: base(parameterType)
{
}
/// <summary>
/// Construct a new <see cref="ResolvedParameter"/> that
/// resolves the given type and name.
/// </summary>
/// <param name="name">Name to use when resolving parameter.</param>
public ResolvedParameter(string name)
{
_name = name;
}
/// <summary>
/// Construct a new <see cref="ResolvedParameter"/> that
/// resolves the given type and name.
/// </summary>
/// <param name="parameterType">Type of this parameter.</param>
/// <param name="name">Name to use when resolving parameter.</param>
public ResolvedParameter(Type parameterType, string? name)
: base(parameterType)
{
_name = name;
}
#endregion
#region IResolverFactory
public ResolveDelegate<TContext> GetResolver<TContext>(Type type)
where TContext : IResolveContext
{
#if NETSTANDARD1_0 || NETCOREAPP1_0
var info = ParameterType?.GetTypeInfo();
if (null == info || info.IsGenericType && info.ContainsGenericParameters ||
ParameterType!.IsArray && ParameterType.GetElementType()!.GetTypeInfo().IsGenericParameter ||
ParameterType.IsGenericParameter)
#else
if (null == ParameterType || ParameterType.IsGenericType && ParameterType.ContainsGenericParameters ||
ParameterType!.IsArray && ParameterType.GetElementType()!.IsGenericParameter ||
ParameterType.IsGenericParameter)
#endif
{
return (ref TContext c) => c.Resolve(type, _name);
}
return (ref TContext c) => c.Resolve(ParameterType, _name);
}
public ResolveDelegate<TContext> GetResolver<TContext>(ParameterInfo info)
where TContext : IResolveContext
{
#if NETSTANDARD1_0 || NETCOREAPP1_0
var parameterInfo = ParameterType?.GetTypeInfo();
if (null == parameterInfo || parameterInfo.IsGenericType && parameterInfo.ContainsGenericParameters ||
ParameterType!.IsArray && ParameterType.GetElementType()!.GetTypeInfo().IsGenericParameter ||
ParameterType.IsGenericParameter)
#else
if (null == ParameterType || ParameterType.IsGenericType && ParameterType.ContainsGenericParameters ||
ParameterType!.IsArray && ParameterType.GetElementType()!.IsGenericParameter ||
ParameterType.IsGenericParameter)
#endif
{
var type = info.ParameterType;
return (ref TContext c) => c.Resolve(type, _name);
}
return (ref TContext c) => c.Resolve(ParameterType, _name);
}
#endregion
#region Overrides
public override string ToString()
{
return $"ResolvedParameter: Type={ParameterType?.Name ?? "Any"} Name={_name ?? "null"}";
}
#endregion
}
/// <summary>
/// A generic version of <see cref="ResolvedParameter"/> for convenience
/// when creating them by hand.
/// </summary>
/// <typeparam name="TParameter">Type of the parameter</typeparam>
public class ResolvedParameter<TParameter> : ResolvedParameter
{
/// <summary>
/// Create a new <see cref="ResolvedParameter{TParameter}"/> for the given
/// generic type and the default name.
/// </summary>
public ResolvedParameter() : base(typeof(TParameter))
{
}
/// <summary>
/// Create a new <see cref="ResolvedParameter{TParameter}"/> for the given
/// generic type and name.
/// </summary>
/// <param name="name">Name to use to resolve this parameter.</param>
public ResolvedParameter(string name) : base(typeof(TParameter), name)
{
}
}
}

Просмотреть файл

@ -0,0 +1,106 @@
using System;
namespace Unity.Resolution
{
/// <summary>
/// Base class for all override objects passed in the
/// <see cref="IUnityContainer.Resolve"/> method.
/// </summary>
public abstract class ResolverOverride
{
#region Fields
protected Type? Target;
protected readonly Type? Type;
protected readonly string? Name;
#endregion
#region Constructors
protected ResolverOverride(string name)
{
Name = name;
}
protected ResolverOverride(Type? target, Type? type, string? name)
{
Target = target;
Type = type;
Name = name;
}
#endregion
#region Type Based Override
/// <summary>
/// Wrap this resolver in one that verifies the type of the object being built.
/// This allows you to narrow any override down to a specific type easily.
/// </summary>
/// <typeparam name="T">Type to constrain the override to.</typeparam>
/// <returns>The new override.</returns>
public ResolverOverride OnType<T>()
{
Target = typeof(T);
return this;
}
/// <summary>
/// Wrap this resolver in one that verifies the type of the object being built.
/// This allows you to narrow any override down to a specific type easily.
/// </summary>
/// <param name="targetType">Type to constrain the override to.</param>
/// <returns>The new override.</returns>
public ResolverOverride OnType(Type targetType)
{
Target = targetType;
return this;
}
#endregion
#region IResolverFactory
public virtual ResolveDelegate<TContext> GetResolver<TContext>(Type type)
where TContext : IResolveContext
{
return this is IResolve policy
? (ResolveDelegate<TContext>)policy.Resolve
: throw new InvalidCastException("Derived type does not implement IResolve policy");
}
#endregion
#region Object
public override int GetHashCode()
{
return ((Target?.GetHashCode() ?? 0 * 37) + (Name?.GetHashCode() ?? 0 * 17)) ^ GetType().GetHashCode();
}
public override bool Equals(object? obj)
{
#pragma warning disable CS8604 // Possible null reference argument.
return this == obj as ResolverOverride;
#pragma warning restore CS8604 // Possible null reference argument.
}
public static bool operator ==(ResolverOverride left, ResolverOverride right)
{
return left?.GetHashCode() == right?.GetHashCode();
}
public static bool operator !=(ResolverOverride left, ResolverOverride right)
{
return !(left == right);
}
#endregion
}
}

Просмотреть файл

@ -0,0 +1,75 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace Unity.Resolution
{
/// <summary>
/// A convenience form of <see cref="ParameterOverride"/> that lets you
/// specify multiple parameter overrides in one shot rather than having
/// to construct multiple objects.
/// </summary>
public class ParameterOverrides : IEnumerable
{
IList<Tuple<string, object>> _values = new List<Tuple<string, object>>();
/// <summary>
/// Add a new override to the collection with the given key and value.
/// </summary>
/// <param name="key">Key - for example, a parameter or property name.</param>
/// <param name="value">InjectionParameterValue - the value to be returned by the override.</param>
public void Add(string key, object value)
{
_values.Add(new Tuple<string, object>(key, value));
}
///// <summary>
///// When implemented in derived classes, this method is called from the <see cref="OverrideCollection{TOverride,TKey,TValue}.Add"/>
///// method to create the actual <see cref="ResolverOverride"/> objects.
///// </summary>
///// <param name="key">Key value to create the resolver.</param>
///// <param name="value">InjectionParameterValue to store in the resolver.</param>
///// <returns>The created <see cref="ResolverOverride"/>.</returns>
//protected override ParameterOverride MakeOverride(string key, object value)
//{
// return new ParameterOverride(key, value);
//}
#region Type Based Override
/// <summary>
/// Wrap this resolver in one that verifies the type of the object being built.
/// This allows you to narrow any override down to a specific type easily.
/// </summary>
/// <typeparam name="T">Type to constrain the override to.</typeparam>
/// <returns>The new override.</returns>
public ResolverOverride[] OnType<T>()
{
return _values.Select(p => new ParameterOverride(p.Item1, p.Item2).OnType<T>())
.ToArray();
}
/// <summary>
/// Wrap this resolver in one that verifies the type of the object being built.
/// This allows you to narrow any override down to a specific type easily.
/// </summary>
/// <param name="targetType">Type to constrain the override to.</param>
/// <returns>The new override.</returns>
public ResolverOverride[] OnType(Type targetType)
{
return new ResolverOverride[0];
}
#endregion
public IEnumerator GetEnumerator()
{
foreach (var tuple in _values)
{
yield return new ParameterOverride(tuple.Item1, tuple.Item2);
}
}
}
}

Просмотреть файл

@ -0,0 +1,181 @@
using System;
namespace Unity.Resolution
{
/// <summary>
/// A <see cref="ResolverOverride"/> class that overrides
/// the value injected whenever there is a dependency of the
/// given type, regardless of where it appears in the object graph.
/// </summary>
public class DependencyOverride : ResolverOverride,
IEquatable<NamedType>,
IResolve
{
#region Fields
protected readonly object? Value;
#endregion
#region Constructors
/// <summary>
/// Create an instance of <see cref="DependencyOverride"/> to override
/// the given contract type with the given value.
/// </summary>
/// <param name="contractType">Type to override</param>
/// <param name="value">Value to override with</param>
public DependencyOverride(Type contractType, object? value)
: base(null, contractType, null)
{
Value = value;
}
/// <summary>
/// Create an instance of <see cref="DependencyOverride"/> to override
/// dependencies matching the given name
/// </summary>
/// <param name="contractName">Name of the registration</param>
/// <param name="value">Value to override with</param>
public DependencyOverride(string contractName, object? value)
: base(null, null, contractName)
{
Value = value;
}
/// <summary>
/// Create an instance of <see cref="DependencyOverride"/> to override
/// dependencies matching the given type and a name
/// </summary>
/// <param name="contractName">Name of the registration</param>
/// <param name="contractType">Type of the registration</param>
/// <param name="value">Value to override with</param>
public DependencyOverride(Type contractType, string contractName, object? value)
: base(null, contractType, contractName)
{
Value = value;
}
/// <summary>
/// Create an instance of <see cref="DependencyOverride"/> to override
/// dependency on specific type matching the given type and a name
/// </summary>
/// <param name="targetType">Target <see cref="Type"/> to override dependency on</param>
/// <param name="contractName">Name of the registration</param>
/// <param name="contractType">Type of the registration</param>
/// <param name="value">Value to override with</param>
public DependencyOverride(Type? targetType, Type contractType, string? contractName, object? value)
: base(targetType, contractType, contractName)
{
Value = value;
}
#endregion
#region IEquatable
public override int GetHashCode()
{
return base.GetHashCode();
}
public override bool Equals(object? other)
{
switch (other)
{
case DependencyOverride dependency:
return (dependency.Type == Type) &&
(dependency.Name == Name);
case NamedType type:
return Equals(type);
default:
return false;
}
}
public bool Equals(NamedType other)
{
return (other.Type == Type) &&
(other.Name == Name);
}
#endregion
#region IResolverPolicy
public object? Resolve<TContext>(ref TContext context)
where TContext : IResolveContext
{
if (Value is IResolve policy)
return policy.Resolve(ref context);
if (Value is IResolverFactory<Type> factory)
{
var resolveDelegate = factory.GetResolver<TContext>(Type!);
return resolveDelegate(ref context);
}
return Value;
}
#endregion
}
/// <summary>
/// A convenience version of <see cref="DependencyOverride"/> that lets you
/// specify the dependency type using generic syntax.
/// </summary>
/// <typeparam name="T">Type of the dependency to override.</typeparam>
public class DependencyOverride<T> : DependencyOverride
{
/// <summary>
/// Create an instance of <see cref="DependencyOverride"/> to override
/// dependencies matching the given type and a name
/// </summary>
/// <remarks>
/// This constructor creates an override that will match with any
/// target type as long as the dependency type and name match. To
/// target specific type use <see cref="ResolverOverride.OnType(Type)"/>
/// method.
/// </remarks>
/// <param name="target">Target type to override dependency on</param>
/// <param name="name">Name of the dependency</param>
/// <param name="value">Override value</param>
public DependencyOverride(Type target, string name, object? value)
: base(target, typeof(T), name, value)
{
}
/// <summary>
/// Create an instance of <see cref="DependencyOverride"/> to override
/// dependencies matching the given type and a name
/// </summary>
/// <remarks>
/// This constructor creates an override that will match with any
/// target type as long as the dependency type and name match. To
/// target specific type use <see cref="ResolverOverride.OnType(Type)"/>
/// method.
/// </remarks>
/// <param name="name">Name of the dependency</param>
/// <param name="value">Override value</param>
public DependencyOverride(string name, object? value)
: base(null, typeof(T), name, value)
{
}
/// <summary>
/// Construct a new <see cref="DependencyOverride{T}"/> object that will
/// override the given dependency, and pass the given value.
/// </summary>
public DependencyOverride(object? value)
: base(null, typeof(T), null, value)
{
}
}
}

Просмотреть файл

@ -0,0 +1,90 @@
using System;
using System.Reflection;
namespace Unity.Resolution
{
/// <summary>
/// A <see cref="ResolverOverride"/> that lets you override
/// the value for a specified field.
/// </summary>
public class FieldOverride : ResolverOverride,
IEquatable<FieldInfo>,
IResolve
{
#region Fields
protected readonly object Value;
#endregion
#region Constructors
/// <summary>
/// Create an instance of <see cref="FieldOverride"/>.
/// </summary>
/// <param name="fieldName">The Field name.</param>
/// <param name="fieldValue">InjectionParameterValue to use for the Field.</param>
public FieldOverride(string fieldName, object fieldValue)
: base(fieldName)
{
Value = fieldValue;
}
#endregion
#region IEquatable
public override int GetHashCode()
{
return base.GetHashCode();
}
public override bool Equals(object? other)
{
switch (other)
{
case FieldInfo info:
return Equals(info);
case FieldOverride field:
return (null == Target || field.Target == Target) &&
(null == Type || field.Type == Type) &&
(null == Name || field.Name == Name);
default:
return base.Equals(other);
}
}
public bool Equals(FieldInfo? other)
{
return null != other &&
(null == Target || other.DeclaringType == Target) &&
(null == Type || other.FieldType == Type) &&
(null == Name || other.Name == Name);
}
#endregion
#region IResolverPolicy
public object? Resolve<TContext>(ref TContext context)
where TContext : IResolveContext
{
if (Value is IResolve policy)
return policy.Resolve(ref context);
if (Value is IResolverFactory<Type> factory)
{
var resolveDelegate = factory.GetResolver<TContext>(Type!);
return resolveDelegate(ref context);
}
return Value;
}
#endregion
}
}

Просмотреть файл

@ -0,0 +1,121 @@
using System;
using System.Reflection;
namespace Unity.Resolution
{
/// <summary>
/// A <see cref="ResolverOverride"/> class that lets you
/// override a named parameter passed to a constructor.
/// </summary>
public class ParameterOverride : ResolverOverride,
IEquatable<ParameterInfo>,
IResolve
{
#region Fields
protected readonly object Value;
#endregion
#region Constructors
/// <summary>
/// Construct a new <see cref="ParameterOverride"/> object that will
/// override the given named constructor parameter, and pass the given
/// value.
/// </summary>
/// <param name="parameterName">Name of the constructor parameter.</param>
/// <param name="parameterValue">InjectionParameterValue to pass for the constructor.</param>
public ParameterOverride(string parameterName, object parameterValue)
: base(null, null, parameterName)
{
Value = parameterValue;
}
/// <summary>
/// Construct a new <see cref="ParameterOverride"/> object that will
/// override the given named constructor parameter, and pass the given
/// value.
/// </summary>
/// <param name="parameterType">Type of the parameter.</param>
/// <param name="parameterValue">Value to pass for the MethodBase.</param>
public ParameterOverride(Type parameterType, object parameterValue)
: base(null, parameterType, null)
{
Value = parameterValue;
}
/// <summary>
/// Construct a new <see cref="ParameterOverride"/> object that will
/// override the given named constructor parameter, and pass the given
/// value.
/// </summary>
/// <param name="parameterType">Type of the parameter.</param>
/// <param name="parameterName">Name of the constructor parameter.</param>
/// <param name="parameterValue">Value to pass for the MethodBase.</param>
public ParameterOverride(Type parameterType, string parameterName, object parameterValue)
: base(null, parameterType, parameterName)
{
Value = parameterValue;
}
#endregion
#region IEquatable
public override int GetHashCode()
{
return base.GetHashCode();
}
public override bool Equals(object? other)
{
switch (other)
{
case ParameterInfo info:
return Equals(info);
case ParameterOverride parameter:
return (null == Target || parameter.Target == Target) &&
(null == Type || parameter.Type == Type) &&
(null == Name || parameter.Name == Name);
default:
return base.Equals(other);
}
}
public bool Equals(ParameterInfo? other)
{
return null != other &&
(null == Target || other.Member.DeclaringType == Target) &&
(null == Type || other.ParameterType == Type) &&
(null == Name || other.Name == Name);
}
#endregion
#region IResolverPolicy
public object? Resolve<TContext>(ref TContext context)
where TContext : IResolveContext
{
if (Value is IResolve policy)
return policy.Resolve(ref context);
if (Value is IResolverFactory<Type> factory)
{
var resolveDelegate = factory.GetResolver<TContext>(Type!);
return resolveDelegate(ref context);
}
return Value;
}
#endregion
}
}

Просмотреть файл

@ -0,0 +1,90 @@
using System;
using System.Reflection;
namespace Unity.Resolution
{
/// <summary>
/// A <see cref="ResolverOverride"/> that lets you override
/// the value for a specified property.
/// </summary>
public class PropertyOverride : ResolverOverride,
IEquatable<PropertyInfo>,
IResolve
{
#region Fields
protected readonly object Value;
#endregion
#region Constructors
/// <summary>
/// Create an instance of <see cref="PropertyOverride"/>.
/// </summary>
/// <param name="propertyName">The property name.</param>
/// <param name="propertyValue">InjectionParameterValue to use for the property.</param>
public PropertyOverride(string propertyName, object propertyValue)
: base(propertyName)
{
Value = propertyValue;
}
#endregion
#region IEquatable
public override int GetHashCode()
{
return base.GetHashCode();
}
public override bool Equals(object? other)
{
switch (other)
{
case PropertyInfo info:
return Equals(info);
case PropertyOverride property:
return (null == Target || property.Target == Target) &&
(null == Type || property.Type == Type) &&
(null == Name || property.Name == Name);
default:
return base.Equals(other);
}
}
public bool Equals(PropertyInfo? other)
{
return null != other &&
(null == Target || other.DeclaringType == Target) &&
(null == Type || other.PropertyType == Type) &&
(null == Name || other.Name == Name);
}
#endregion
#region IResolverPolicy
public object? Resolve<TContext>(ref TContext context)
where TContext : IResolveContext
{
if (Value is IResolve policy)
return policy.Resolve(ref context);
if (Value is IResolverFactory<Type> factory)
{
var resolveDelegate = factory.GetResolver<TContext>(Type!);
return resolveDelegate(ref context);
}
return Value;
}
#endregion
}
}

Просмотреть файл

@ -0,0 +1,12 @@
using System;
namespace Unity.Exceptions
{
internal class CircularDependencyException : Exception
{
public CircularDependencyException(Type type, string name)
: base($"Circular reference: Type: {type}, Name: {name}")
{
}
}
}

Просмотреть файл

@ -0,0 +1,38 @@
using System;
using System.Reflection;
namespace Unity
{
/// <summary>
/// The exception thrown by the Unity container when
/// an attempt to resolve a dependency fails.
/// </summary>
public class ResolutionFailedException : Exception
{
/// <summary>
/// Create a new <see cref="ResolutionFailedException"/> that records
/// the exception for the given type and name.
/// </summary>
/// <param name="type">Type requested from the container.</param>
/// <param name="name">Name requested from the container.</param>
/// <param name="message">Error message</param>
/// <param name="innerException">The actual exception that caused the failure of the build.</param>
public ResolutionFailedException(Type type, string name, string message, Exception? innerException = null)
: base(message, innerException)
{
TypeRequested = (type ?? throw new ArgumentNullException(nameof(type))).GetTypeInfo().Name;
NameRequested = name;
}
/// <summary>
/// The type that was being requested from the container at the time of failure.
/// </summary>
public string TypeRequested { get; private set; }
/// <summary>
/// The name that was being requested from the container at the time of failure.
/// </summary>
public string NameRequested { get; private set; }
}
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,61 @@
using System;
using System.Runtime.CompilerServices;
using Unity.Injection;
namespace Unity
{
public static partial class Inject
{
#region Array
public static ParameterBase Array(Type elementType, params object[] elementValues)
=> new ResolvedArrayParameter(elementType, elementValues);
public static ParameterBase Array<TElement>(params object[] elementValues)
=> new ResolvedArrayParameter(typeof(TElement), elementValues);
#endregion
#region Parameter
#if !NET40
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
public static ParameterBase Parameter(object value) => new InjectionParameter(value);
#if !NET40
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
public static ParameterBase Parameter(Type type, object value)
=> new InjectionParameter(type ?? throw new ArgumentNullException(nameof(type)), value);
#if !NET40
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
public static ParameterBase Parameter<TTarget>(object value) => new InjectionParameter(typeof(TTarget), value);
#endregion
#region Field
#if !NET40
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
public static InjectionMember Field(string name, object value)
=> new InjectionField(name ?? throw new ArgumentNullException(nameof(name)), value);
#endregion
#region Property
#if !NET40
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
public static InjectionMember Property(string name, object value)
=> new InjectionProperty(name ?? throw new ArgumentNullException(nameof(name)), value);
#endregion
}
}

Просмотреть файл

@ -0,0 +1,69 @@
using System;
using System.Reflection;
using System.Runtime.CompilerServices;
using Unity.Injection;
namespace Unity
{
public static partial class Invoke
{
#region Ctor
#if !NET40
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
public static InjectionMember Ctor() => new InjectionConstructor();
#if !NET40
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
public static InjectionMember Ctor(params object[] parameters) => new InjectionConstructor(parameters);
#if !NET40
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
public static InjectionMember Ctor(params Type[] parameters) => new InjectionConstructor(parameters);
#if !NET40
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
public static InjectionMember Ctor(ConstructorInfo info, params object[] parameters) => new InjectionConstructor(info, parameters);
#endregion
#region Constructor
#if !NET40
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
public static InjectionMember Constructor() => new InjectionConstructor();
#if !NET40
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
public static InjectionMember Constructor(params object[] parameters) => new InjectionConstructor(parameters);
#if !NET40
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
public static InjectionMember Constructor(params Type[] parameters) => new InjectionConstructor(parameters);
#if !NET40
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
public static InjectionMember Constructor(ConstructorInfo info, params object[] parameters) => new InjectionConstructor(info, parameters);
#endregion
#region Method
#if !NET40
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
public static InjectionMember Method(string name, params object[] parameters) => new InjectionMethod(name, parameters);
#endregion
}
}

Просмотреть файл

@ -0,0 +1,103 @@
using System;
using System.Runtime.CompilerServices;
using Unity.Resolution;
namespace Unity
{
public static partial class Override
{
#if !NET40
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
public static ResolverOverride Property(string name, object value) => new PropertyOverride(name, value);
#region Field
#if !NET40
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
public static ResolverOverride Field(string name, object value) => new FieldOverride(name, value);
#endregion
#region Parameter
#if !NET40
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
public static ResolverOverride Parameter(object value)
=> new ParameterOverride(value?.GetType() ?? throw new ArgumentNullException(nameof(value)), value);
#if !NET40
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
public static ResolverOverride Parameter(string name, object value)
=> new ParameterOverride(name, value);
#if !NET40
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
public static ResolverOverride Parameter(Type type, object value)
=> new ParameterOverride(type, value);
#if !NET40
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
public static ResolverOverride Parameter(Type type, string name, object value)
=> new ParameterOverride(type, name, value);
#if !NET40
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
public static ResolverOverride Parameter<TType>(object value)
=> new ParameterOverride(typeof(TType), value);
#if !NET40
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
public static ResolverOverride Parameter<TType>(string name, object value)
=> Parameter(typeof(TType), name, value);
#endregion
#region Dependency
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ResolverOverride Dependency(object value)
=> Dependency(value?.GetType() ?? throw new ArgumentNullException(nameof(value)), String.Empty, value);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ResolverOverride Dependency(string name, object value)
=> Dependency(value?.GetType() ?? throw new ArgumentNullException(nameof(value)), name, value);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ResolverOverride Dependency(Type type, object value)
{
return new DependencyOverride(type, value);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ResolverOverride Dependency(Type type, string name, object value)
{
return new DependencyOverride(type, name, value);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ResolverOverride Dependency<TType>(object value)
=> new DependencyOverride(typeof(TType), value);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ResolverOverride Dependency<TType>(string name, object value)
=> new DependencyOverride(typeof(TType), name, value);
#endregion
}
}

Просмотреть файл

@ -0,0 +1,138 @@
using System;
using System.Runtime.CompilerServices;
using Unity.Injection;
namespace Unity
{
public static partial class Resolve
{
#region Dependency
#if !NET40
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
public static ParameterBase Dependency<TTarget>() => new ResolvedParameter(typeof(TTarget), null);
#if !NET40
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
public static ParameterBase Dependency<TTarget>(string name) => new ResolvedParameter(typeof(TTarget), name);
#endregion
#region Parameter
#if !NET40
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
public static ParameterBase Parameter() => new ResolvedParameter();
#if !NET40
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
public static ParameterBase Parameter(string name) => new ResolvedParameter(name);
#if !NET40
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
public static ParameterBase Parameter(Type type) => new ResolvedParameter(type);
#if !NET40
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
public static ParameterBase Parameter<TTarget>() => new ResolvedParameter(typeof(TTarget));
#if !NET40
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
public static ParameterBase Parameter(Type type, string name) => new ResolvedParameter(type, name);
#if !NET40
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
public static ParameterBase Parameter<TTarget>(string name) => new ResolvedParameter(typeof(TTarget), name);
#endregion
#region Generic
#if !NET40
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
public static GenericParameter Generic(string genericParameterName) => new GenericParameter(genericParameterName);
#if !NET40
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
public static GenericParameter Generic(string genericParameterName, string registrationName) => new GenericParameter(genericParameterName, registrationName);
#endregion
#region Optional
#if !NET40
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
public static ParameterBase Optional() => new OptionalParameter();
#if !NET40
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
public static ParameterBase Optional(string name) => new OptionalParameter(name);
#if !NET40
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
public static ParameterBase Optional(Type type) => new OptionalParameter(type);
#if !NET40
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
public static ParameterBase Optional<TTarget>() => new OptionalParameter(typeof(TTarget));
#if !NET40
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
public static ParameterBase Optional(Type type, string name) => new OptionalParameter(type, name);
#if !NET40
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
public static ParameterBase Optional<TTarget>(string name) => new OptionalParameter(typeof(TTarget), name);
#endregion
#region Field
#if !NET40
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
public static InjectionMember Field(string name) => new InjectionField(name);
#if !NET40
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
public static InjectionMember OptionalField(string name) => new InjectionField(name, ResolutionOption.Optional);
#endregion
#region Property
#if !NET40
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
public static InjectionMember Property(string name) => new InjectionProperty(name ?? throw new ArgumentNullException(nameof(name)));
#if !NET40
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
public static InjectionMember OptionalProperty(string name) => new InjectionProperty(name ?? throw new ArgumentNullException(nameof(name)), ResolutionOption.Optional);
#endregion
}
}

Просмотреть файл

@ -0,0 +1,171 @@
using Unity.Lifetime;
namespace Unity
{
public static class FactoryLifetime
{
/// <summary>
/// Singleton lifetime creates globally unique singleton. Any Unity container
/// tree (parent and all the children) is guaranteed to have only one global
/// singleton for the registered type.
/// </summary>
/// <remarks>
/// <para>Registering a type with singleton lifetime always places the registration
/// at the root of the container tree and makes it globally available for all
/// the children of that container. It does not matter if registration takes
/// places at the root of child container the destination is always the root node.</para>
/// <para>Repeating the registration on any of the child nodes with singleton lifetime
/// will always override the root registration.</para>
/// </remarks>
/// <value>A new instance of a <see cref="SingletonLifetimeManager"/> lifetime manager.</value>
public static IFactoryLifetimeManager Singleton => new SingletonLifetimeManager();
/// <summary>
/// Unity returns the same instance each time the Resolve(...) method is called or when
/// the dependency mechanism injects the instance into other classes.
/// </summary>
/// <remarks>
/// Per Container lifetime allows a registration of an existing or resolved object as
/// a scoped singleton in the container it was created or registered. In other words this
/// instance is unique within the container it war registered with. Child or parent
/// containers could have their own instances registered for the same contract.
/// </remarks>
/// <value>A new instance of a <see cref="ContainerControlledLifetimeManager"/> lifetime manager.</value>
public static IFactoryLifetimeManager PerContainer => new ContainerControlledLifetimeManager();
/// <summary>
/// Unity returns a unique value for each child container.
/// </summary>
/// <remarks>
/// <para>
/// The Unity container allows creating hierarchies of child containers. This lifetime
/// creates local singleton for each level of the hierarchy. So, when you resolve a
/// type and this container does not have an instance of that type, the container will
/// create new instance. Next type the type is resolved the same instance will be returned.
/// </para>
/// <para>
/// If a child container is created and requested to resolve the type, the child container
/// will create a new instance and store it for subsequent resolutions. Next time the
/// child container requested to resolve the type, it will return stored instance.
/// </para>
/// <para>If you have multiple children, each will resolve its own instance.</para>
/// </remarks>
/// <value>A new instance of a <see cref="HierarchicalLifetimeManager"/> lifetime manager.</value>
public static IFactoryLifetimeManager Hierarchical => new HierarchicalLifetimeManager();
/// <summary>
/// Unity returns a unique value for each scope.
/// </summary>
/// <remarks>
/// <para>
/// The Unity container allows creating hierarchies of child containers. This lifetime
/// creates local singleton for each level of the hierarchy. So, when you resolve a
/// type and this container does not have an instance of that type, the container will
/// create new instance. Next type the type is resolved the same instance will be returned.
/// </para>
/// <para>
/// If a child container is created and requested to resolve the type, the child container
/// will create a new instance and store it for subsequent resolutions. Next time the
/// child container requested to resolve the type, it will return stored instance.
/// </para>
/// <para>If you have multiple children, each will resolve its own instance.</para>
/// </remarks>
/// <value>A new instance of a <see cref="HierarchicalLifetimeManager"/> lifetime manager.</value>
public static IFactoryLifetimeManager Scoped => new HierarchicalLifetimeManager();
/// <summary>
/// This lifetime keeps a reference to an instance only for the duration of one resolution call
/// </summary>
/// <remarks>
/// This type of lifetime is useful when you need to pass the same instance of the dependency
/// to a different nodes of the resolution graph.
/// </remarks>
/// <example>
/// Consider this scenario:
/// <code>
/// class a {}
///
/// class b
/// {
/// b(a arg1)
/// {...}
/// }
///
/// class c
/// {
/// c(a arg1, b arg2)
/// {...}
/// }
/// </code>
/// <para>
/// When you resolve type `c`, it depends on type `b` and type `a`. Type `b`, in turn,
/// also depends on type `a`, and both types, `c` and `b`, require `a` to be the same instance.
/// </para>
/// <para>
/// If type `a` is a singleton, the logic is easy. But if you require each instance of
/// `c` to have a unique `a`, you could use per resolve lifetime. The instance of `a`
/// will act as a singleton only during that one resolution. Next call to resolve the
/// dependent type will create a new object.
/// </para>
/// <para>
/// In the case of recursion, the singleton behavior is still applies and prevents circular dependency
/// </para>
/// </example>
/// <value>A new instance of a <see cref="PerResolveLifetimeManager"/> lifetime manager.</value>
public static IFactoryLifetimeManager PerResolve => new PerResolveLifetimeManager();
/// <summary>
/// Per thread lifetime means a new instance of the registered <see cref="System.Type"/>
/// will be created once per each thread. In other words, if a Resolve{T}() method is
/// called on a thread the first time, it will return a new object. Each subsequent
/// call to Resolve{T}(), or when the dependency mechanism injects instances of
/// the type into other classes on the same thread, the container will return the
/// same object.
/// </summary>
/// <value>A new instance of a <see cref="PerThreadLifetimeManager"/> lifetime manager.</value>
public static IFactoryLifetimeManager PerThread => new PerThreadLifetimeManager();
/// <summary>
/// This lifetime creates and returns a new instance of the requested type for each call
/// to the Resolve(...) method.
/// </summary>
/// <remarks>
/// Transient lifetime is a default lifetime of the Unity container. As the name implies it
/// lasts very short period of time, actually, no time at all. In the Unity container terms,
/// having transient lifetime is the same as having no lifetime manager at all.
/// </remarks>
/// <value>An instance of a <see cref="TransientLifetimeManager"/> lifetime manager.</value>
public static IFactoryLifetimeManager Transient { get; } = new TransientLifetimeManager();
/// <summary>
/// This lifetime is similar to <see cref="TransientLifetimeManager"/> with exception
/// how the container holds references to created objects.
/// </summary>
/// <remarks>
/// <para>
/// On each call to the Resolve{T}() method a container will create a new objects.
/// If the objects implements <see cref="System.IDisposable"/>, the container will hold a
/// reference to the interface and will dispose the object when the container goes out of scope.
/// </para>
/// <para>
/// This lifetime is particularly useful in session based designs with child containers
/// associated with the session</para>
/// </remarks>
/// <value>A new instance of a <see cref="ContainerControlledTransientManager"/> lifetime manager.</value>
public static IFactoryLifetimeManager PerContainerTransient => new ContainerControlledTransientManager();
/// <summary>
/// This lifetime keeps a weak reference to object it holds.
/// </summary>
/// <remarks>
/// <para>When no object is associated with the manager container creates and returns a new object.
/// It gets and holds a weak reference to the created object. As long as the object still exists and
/// has not been garbage collected the container will return the object when requested.</para>
/// <para>If the object went out of scope and has been garbage collected the container will
/// create and return a new instance.</para>
/// <para>This lifetime manager does not dispose an object when container is disposed</para>
/// </remarks>
/// <value>A new instance of a <see cref="ExternallyControlledLifetimeManager"/> lifetime manager.</value>
public static IFactoryLifetimeManager External => new ExternallyControlledLifetimeManager();
}
}

Просмотреть файл

@ -0,0 +1,50 @@
using Unity.Lifetime;
namespace Unity
{
public static class InstanceLifetime
{
/// <summary>
/// This lifetime stores a weak reference to an instance and returns an instance while it is available.
/// </summary>
/// <remarks>
/// <para>Container gets a hold of a weak reference to the object and as long as the object
/// still exists and has not been garbage collected the container will return the object when
/// requested.</para>
/// <para>If the object went out of scope and has been garbage collected the container will
/// return <see cref="LifetimeManager.NoValue"/>.</para>
/// <para>This lifetime manager does not dispose an object when container is disposed</para>
/// </remarks>
/// <value>A new instance of a <see cref="ExternallyControlledLifetimeManager"/> lifetime manager.</value>
public static IInstanceLifetimeManager External => new ExternallyControlledLifetimeManager();
/// <summary>
/// Singleton lifetime creates globally unique singleton. Any Unity container
/// tree (parent and all the children) is guaranteed to have only one global
/// singleton for the registered type.
/// </summary>
/// <remarks>
/// <para>Registering a type with singleton lifetime always places the registration
/// at the root of the container tree and makes it globally available for all
/// the children of that container. It does not matter if registration takes
/// places at the root of child container the destination is always the root node.</para>
/// <para>Repeating the registration on any of the child nodes with singleton lifetime
/// will always override the root registration.</para>
/// </remarks>
/// <value>A new instance of a <see cref="SingletonLifetimeManager"/> object.</value>
public static IInstanceLifetimeManager Singleton => new SingletonLifetimeManager();
/// <summary>
/// Unity returns the same instance each time the Resolve(...) method is called or when
/// the dependency mechanism injects the instance into other classes.
/// </summary>
/// <remarks>
/// Per Container lifetime allows a registration of an existing or resolved object as
/// a scoped singleton in the container it was created or registered. In other words this
/// instance is unique within the container it war registered with. Child or parent
/// containers could have their own instances registered for the same contract.
/// </remarks>
/// <value>A new instance of a <see cref="ContainerControlledLifetimeManager"/> object.</value>
public static IInstanceLifetimeManager PerContainer => new ContainerControlledLifetimeManager();
}
}

Просмотреть файл

@ -0,0 +1,185 @@
using Unity.Lifetime;
namespace Unity
{
public static class TypeLifetime
{
/// <summary>
/// Singleton lifetime creates globally unique singleton. Any Unity container
/// tree (parent and all the children) is guaranteed to have only one global
/// singleton for the registered type.
/// </summary>
/// <remarks>
/// <para>Registering a type with singleton lifetime always places the registration
/// at the root of the container tree and makes it globally available for all
/// the children of that container. It does not matter if registration takes
/// places at the root of child container the destination is always the root node.</para>
/// <para>Repeating the registration on any of the child nodes with singleton lifetime
/// will always override the root registration.</para>
/// </remarks>
/// <value>A new instance of a <see cref="SingletonLifetimeManager"/> object.</value>
public static ITypeLifetimeManager Singleton => new SingletonLifetimeManager();
/// <summary>
/// Unity returns the same instance each time the Resolve(...) method is called or when
/// the dependency mechanism injects the instance into other classes.
/// </summary>
/// <remarks>
/// Per Container lifetime allows a registration of an existing or resolved object as
/// a scoped singleton in the container it was created or registered. In other words this
/// instance is unique within the container it war registered with. Child or parent
/// containers could have their own instances registered for the same contract.
/// </remarks>
/// <value>A new instance of a <see cref="ContainerControlledLifetimeManager"/> object.</value>
public static ITypeLifetimeManager ContainerControlled => new ContainerControlledLifetimeManager();
/// <summary>
/// Unity returns the same instance each time the Resolve(...) method is called or when
/// the dependency mechanism injects the instance into other classes.
/// </summary>
/// <remarks>
/// Per Container lifetime allows a registration of an existing or resolved object as
/// a scoped singleton in the container it was created or registered. In other words this
/// instance is unique within the container it war registered with. Child or parent
/// containers could have their own instances registered for the same contract.
/// </remarks>
/// <value>A new instance of a <see cref="ContainerControlledLifetimeManager"/> object.</value>
public static ITypeLifetimeManager PerContainer => new ContainerControlledLifetimeManager();
/// <summary>
/// Unity returns a unique value for each child container.
/// </summary>
/// <remarks>
/// <para>
/// The Unity container allows creating hierarchies of child containers. This lifetime
/// creates local singleton for each level of the hierarchy. So, when you resolve a
/// type and this container does not have an instance of that type, the container will
/// create new instance. Next type the type is resolved the same instance will be returned.
/// </para>
/// <para>
/// If a child container is created and requested to resolve the type, the child container
/// will create a new instance and store it for subsequent resolutions. Next time the
/// child container requested to resolve the type, it will return stored instance.
/// </para>
/// <para>If you have multiple children, each will resolve its own instance.</para>
/// </remarks>
/// <value>A new instance of a <see cref="HierarchicalLifetimeManager"/> object.</value>
public static ITypeLifetimeManager Hierarchical => new HierarchicalLifetimeManager();
/// <summary>
/// Unity returns a unique value for each scope.
/// </summary>
/// <remarks>
/// <para>
/// The Unity container allows creating hierarchies of child containers. This lifetime
/// creates local singleton for each level of the hierarchy. So, when you resolve a
/// type and this container does not have an instance of that type, the container will
/// create new instance. Next type the type is resolved the same instance will be returned.
/// </para>
/// <para>
/// If a child container is created and requested to resolve the type, the child container
/// will create a new instance and store it for subsequent resolutions. Next time the
/// child container requested to resolve the type, it will return stored instance.
/// </para>
/// <para>If you have multiple children, each will resolve its own instance.</para>
/// </remarks>
/// <value>A new instance of a <see cref="HierarchicalLifetimeManager"/> object.</value>
public static ITypeLifetimeManager Scoped => new HierarchicalLifetimeManager();
/// <summary>
/// This lifetime keeps a reference to an instance only for the duration of one resolution call
/// </summary>
/// <remarks>
/// This type of lifetime is useful when you need to pass the same instance of the dependency
/// to a different nodes of the resolution graph.
/// </remarks>
/// <example>
/// Consider this scenario:
/// <code>
/// class a {}
///
/// class b
/// {
/// b(a arg1)
/// {...}
/// }
///
/// class c
/// {
/// c(a arg1, b arg2)
/// {...}
/// }
/// </code>
/// <para>
/// When you resolve type `c`, it depends on type `b` and type `a`. Type `b`, in turn,
/// also depends on type `a`, and both types, `c` and `b`, require `a` to be the same instance.
/// </para>
/// <para>
/// If type `a` is a singleton, the logic is easy. But if you require each instance of
/// `c` to have a unique `a`, you could use per resolve lifetime. The instance of `a`
/// will act as a singleton only during that one resolution. Next call to resolve the
/// dependent type will create a new object.
/// </para>
/// <para>
/// In the case of recursion, the singleton behavior is still applies and prevents circular dependency
/// </para>
/// </example>
/// <value>A new instance of a <see cref="PerResolveLifetimeManager"/> object.</value>
public static ITypeLifetimeManager PerResolve => new PerResolveLifetimeManager();
/// <summary>
/// Per thread lifetime means a new instance of the registered <see cref="System.Type"/>
/// will be created once per each thread. In other words, if a Resolve{T}() method is
/// called on a thread the first time, it will return a new object. Each subsequent
/// call to Resolve{T}(), or when the dependency mechanism injects instances of
/// the type into other classes on the same thread, the container will return the
/// same object.
/// </summary>
/// <value>A new instance of a <see cref="PerThreadLifetimeManager"/> object.</value>
public static ITypeLifetimeManager PerThread => new PerThreadLifetimeManager();
/// <summary>
/// This lifetime creates and returns a new instance of the requested type for each call
/// to the Resolve(...) method.
/// </summary>
/// <remarks>
/// Transient lifetime is a default lifetime of the Unity container. As the name implies it
/// lasts very short period of time, actually, no time at all. In the Unity container terms,
/// having transient lifetime is the same as having no lifetime manager at all.
/// </remarks>
/// <value>An instance of a <see cref="TransientLifetimeManager"/> object.</value>
public static ITypeLifetimeManager Transient => TransientLifetimeManager.Instance;
/// <summary>
/// This lifetime is similar to <see cref="TransientLifetimeManager"/> with exception
/// how the container holds references to created objects.
/// </summary>
/// <remarks>
/// <para>
/// On each call to the Resolve{T}() method a container will create a new objects.
/// If the objects implements <see cref="System.IDisposable"/>, the container will hold a
/// reference to the interface and will dispose the object when the container goes out of scope.
/// </para>
/// <para>
/// This lifetime is particularly useful in session based designs with child containers
/// associated with the session
/// </para>
/// </remarks>
/// <value>A new instance of a <see cref="ContainerControlledTransientManager"/> object.</value>
public static ITypeLifetimeManager PerContainerTransient => new ContainerControlledTransientManager();
/// <summary>
/// This lifetime keeps a weak reference to object it holds.
/// </summary>
/// <remarks>
/// <para>When no object is associated with the manager container creates and returns a new object.
/// It gets and holds a weak reference to the created object. As long as the object still exists and
/// has not been garbage collected the container will return the object when requested.</para>
/// <para>If the object went out of scope and has been garbage collected the container will
/// create and return a new instance.</para>
/// <para>This lifetime manager does not dispose an object when container is disposed</para>
/// </remarks>
/// <value>A new instance of a <see cref="WeakReferenceLifetimeManager"/> lifetime manager.</value>
public static ITypeLifetimeManager External => new ExternallyControlledLifetimeManager();
}
}

Просмотреть файл

@ -0,0 +1,24 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading;
#nullable disable warnings
namespace System.Reflection
{
internal static class IntrospectionExtensions
{
public static MethodInfo GetGetMethod(this PropertyInfo info, bool _)
{
return info.GetMethod;
}
public static MethodInfo GetSetMethod(this PropertyInfo info, bool _)
{
return info.SetMethod;
}
}
}
#nullable restore warnings

Просмотреть файл

@ -0,0 +1,59 @@
using System;
using System.Collections.Generic;
using System.Reflection;
namespace Unity
{
/// <summary>
/// Provides extension methods to the <see cref="Type"/> class due to the introduction
/// of <see cref="TypeInfo"/> class.
/// </summary>
internal static class TypeReflectionExtensions
{
public static Type GetArrayParameterType(this Type typeToReflect, Type[] genericArguments)
{
var rank = typeToReflect.GetArrayRank();
var element = typeToReflect.GetElementType()!;
var type = element.IsArray ? element.GetArrayParameterType(genericArguments)
: genericArguments[element.GenericParameterPosition];
return 1 == rank ? type.MakeArrayType() : type.MakeArrayType(rank);
}
public static IEnumerable<FieldInfo> GetDeclaredFields(this Type type)
{
var info = type.GetTypeInfo();
while (null != info)
{
foreach (var member in info.DeclaredFields)
yield return member;
info = info.BaseType?.GetTypeInfo();
}
}
public static IEnumerable<PropertyInfo> GetDeclaredProperties(this Type type)
{
var info = type.GetTypeInfo();
while (null != info)
{
foreach (var member in info.DeclaredProperties)
yield return member;
info = info.BaseType?.GetTypeInfo();
}
}
public static IEnumerable<MethodInfo> GetDeclaredMethods(this Type type)
{
var info = type.GetTypeInfo();
while (null != info)
{
foreach (var member in info.DeclaredMethods)
yield return member;
info = info.BaseType?.GetTypeInfo();
}
}
}
}

Просмотреть файл

@ -0,0 +1,15 @@
namespace Unity.Lifetime
{
/// <summary>
/// This interface marks all lifetime managers compatible with
/// <see cref="IUnityContainer.RegisterFactory" /> registration.
/// </summary>
/// <remarks>
/// This interface is used for design type validation of registration compatibility.
/// Each registration type only takes lifetime managers compatible with it.
/// </remarks>
public interface IFactoryLifetimeManager
{
LifetimeManager CreateLifetimePolicy();
}
}

Просмотреть файл

@ -0,0 +1,15 @@
namespace Unity.Lifetime
{
/// <summary>
/// This interface marks all lifetime managers compatible with
/// <see cref="IUnityContainer.RegisterInstance" /> registration.
/// </summary>
/// <remarks>
/// This interface is used for design type validation of registration compatibility.
/// Each registration type only takes lifetime managers compatible with it.
/// </remarks>
public interface IInstanceLifetimeManager
{
LifetimeManager CreateLifetimePolicy();
}
}

Просмотреть файл

@ -0,0 +1,55 @@
using System;
using System.Collections.Generic;
namespace Unity.Lifetime
{
/// <summary>
/// Represents a lifetime container.
/// </summary>
/// <remarks>
/// A lifetime container tracks the lifetime of an object, and implements
/// IDisposable. When the container is disposed, any objects in the
/// container which implement IDisposable are also disposed.
/// </remarks>
public interface ILifetimeContainer : IEnumerable<object>, IDisposable
{
/// <summary>
/// The container that this context is associated with.
/// </summary>
/// <value>The <see cref="IUnityContainer"/> object.</value>
IUnityContainer Container { get; }
/// <summary>
/// Gets the number of references in the lifetime container
/// </summary>
/// <value>
/// The number of references in the lifetime container
/// </value>
int Count { get; }
/// <summary>
/// Adds an object to the lifetime container.
/// </summary>
/// <param name="item">The item to be added to the lifetime container.</param>
void Add(object item);
/// <summary>
/// Determine if a given object is in the lifetime container.
/// </summary>
/// <param name="item">
/// The item to locate in the lifetime container.
/// </param>
/// <returns>
/// Returns true if the object is contained in the lifetime
/// container; returns false otherwise.
/// </returns>
bool Contains(object item);
/// <summary>
/// Removes an item from the lifetime container. The item is
/// not disposed.
/// </summary>
/// <param name="item">The item to be removed.</param>
void Remove(object item);
}
}

Просмотреть файл

@ -0,0 +1,15 @@
namespace Unity.Lifetime
{
/// <summary>
/// This interface marks all lifetime managers compatible with
/// <see cref="IUnityContainer.RegisterType" /> registration.
/// </summary>
/// <remarks>
/// This interface is used for design type validation of registration compatibility.
/// Each registration type only takes lifetime managers compatible with it.
/// </remarks>
public interface ITypeLifetimeManager
{
LifetimeManager CreateLifetimePolicy();
}
}

Просмотреть файл

@ -0,0 +1,146 @@
using System;
using Unity.Resolution;
namespace Unity.Lifetime
{
/// <summary>
/// Base class for all lifetime managers - classes that control how
/// and when instances are created by the Unity container.
/// </summary>
public abstract class LifetimeManager
{
/// <summary>
/// This value represents Invalid Value. Lifetime manager must return this
/// unless value is set with a valid object. Null is a value and is not equal
/// to NoValue
/// </summary>
public static readonly object NoValue = new InvalidValue();
/// <summary>
/// A <see cref="Boolean"/> indicating if this manager is being used in
/// one of the registrations.
/// </summary>
/// <remarks>
/// The Unity container requires that each registration used its own, unique
/// lifetime manager. This property is being used to track that condition.
/// </remarks>
/// <value>True is this instance already in use, False otherwise.</value>
public virtual bool InUse { get; set; }
#region Constructors
public LifetimeManager()
{
Set = SetValue;
Get = GetValue;
TryGet = TryGetValue;
}
#endregion
#region Optimizers
public virtual Func<ILifetimeContainer?, object> TryGet { get; protected set; }
public virtual Func<ILifetimeContainer?, object> Get { get; protected set; }
public virtual Action<object, ILifetimeContainer?> Set { get; protected set; }
#endregion
#region LifetimeManager Members
/// <summary>
/// Retrieves a value from the backing store associated with this Lifetime policy.
/// </summary>
/// <remarks>
/// This method does not block and does not acquire a lock on synchronization
/// primitives.
/// </remarks>
/// <param name="container">The container this lifetime is associated with</param>
/// <returns>the object desired, or null if no such object is currently stored.</returns>
public virtual object TryGetValue(ILifetimeContainer? container = null) => GetValue(container);
/// <summary>
/// Retrieves a value from the backing store associated with this Lifetime policy.
/// </summary>
/// <param name="container">The container this lifetime is associated with</param>
/// <returns>the object desired, or null if no such object is currently stored.</returns>
public virtual object GetValue(ILifetimeContainer? container = null) => NoValue;
/// <summary>
/// Stores the given value into backing store for retrieval later.
/// </summary>
/// <param name="newValue">The object being stored.</param>
/// <param name="container">The container this lifetime is associated with</param>
public virtual void SetValue(object newValue, ILifetimeContainer? container = null) { }
/// <summary>
/// Remove the given object from backing store.
/// </summary>
/// <param name="container">The container this lifetime belongs to</param>
public virtual void RemoveValue(ILifetimeContainer? container = null) { }
#endregion
#region ILifetimeFactoryPolicy
/// <summary>
/// Creates a new lifetime manager of the same type as this Lifetime Manager
/// </summary>
/// <returns>A new instance of the appropriate lifetime manager</returns>
public LifetimeManager CreateLifetimePolicy() => OnCreateLifetimeManager();
#endregion
#region Implementation
/// <summary>
/// Implementation of <see cref="CreateLifetimePolicy"/> policy.
/// </summary>
/// <returns>A new instance of the same lifetime manager of appropriate type</returns>
protected abstract LifetimeManager OnCreateLifetimeManager();
#endregion
#region Nested Types
public class InvalidValue
{
public override bool Equals(object? obj)
{
return ReferenceEquals(this, obj);
}
public override int GetHashCode()
{
return base.GetHashCode();
}
}
#endregion
#region Internal Use
internal Delegate? PipelineDelegate;
internal virtual object? Pipeline<TContext>(ref TContext context) where TContext : IResolveContext
=> ((ResolveDelegate<TContext>)PipelineDelegate!)(ref context);
#endregion
#region Debugger
#if DEBUG
public string ID { get; } = Guid.NewGuid().ToString();
#endif
#endregion
}
}

Просмотреть файл

@ -0,0 +1,148 @@
using System;
using System.Threading;
namespace Unity.Lifetime
{
/// <summary>
/// Base class for Lifetime managers which need to synchronize calls to
/// <see cref="SynchronizedLifetimeManager.GetValue"/>.
/// </summary>
/// <remarks>
/// <para>
/// The purpose of this class is to provide a basic implementation of the lifetime manager synchronization pattern.
/// </para>
/// <para>
/// Calls to the <see cref="SynchronizedLifetimeManager.GetValue"/> method of a <see cref="SynchronizedLifetimeManager"/>
/// instance acquire a lock, and if the instance has not been initialized with a value yet the lock will only be released
/// when such an initialization takes place by calling the <see cref="SynchronizedLifetimeManager.SetValue"/> method or if
/// the build request which resulted in the call to the GetValue method fails.
/// </para>
/// </remarks>
/// <see cref="LifetimeManager"/>
public abstract class SynchronizedLifetimeManager : LifetimeManager, IDisposable
{
#region Fields
private readonly object _lock = new object();
/// <summary>
/// This field controls how long the monitor will wait to
/// enter the lock. It is <see cref="Timeout.Infinite"/> by default or number of
/// milliseconds from 0 to 2147483647.
/// </summary>
public static int ResolveTimeout = Timeout.Infinite;
#endregion
/// <inheritdoc/>
public override object TryGetValue(ILifetimeContainer? container = null)
{
if (Monitor.TryEnter(_lock))
{
var result = SynchronizedGetValue(container);
Monitor.Exit(_lock);
return result;
}
else
return NoValue;
}
/// <inheritdoc/>
public override object GetValue(ILifetimeContainer? container = null)
{
if (Monitor.TryEnter(_lock, ResolveTimeout))
{
var result = SynchronizedGetValue(container);
if (NoValue != result)
{
Monitor.Exit(_lock);
}
return result;
}
else
throw new TimeoutException($"Failed to enter a monitor");
}
/// <summary>
/// Performs the actual retrieval of a value from the backing store associated
/// with this Lifetime policy.
/// </summary>
/// <param name="container">Instance of the lifetime's container</param>
/// <remarks>This method is invoked by <see cref="SynchronizedLifetimeManager.GetValue"/>
/// after it has acquired its lock.</remarks>
/// <returns>the object desired, or null if no such object is currently stored.</returns>
protected abstract object SynchronizedGetValue(ILifetimeContainer? container);
/// <inheritdoc/>
public override void SetValue(object newValue, ILifetimeContainer? container = null)
{
SynchronizedSetValue(newValue, container);
TryExit();
}
/// <summary>
/// Performs the actual storage of the given value into backing store for retrieval later.
/// </summary>
/// <param name="newValue">The object being stored.</param>
/// <param name="container">Instance of the lifetime's container</param>
/// <remarks>This method is invoked by <see cref="SynchronizedLifetimeManager.SetValue"/>
/// before releasing its lock.</remarks>
protected abstract void SynchronizedSetValue(object newValue, ILifetimeContainer? container);
/// <summary>
/// A method that does whatever is needed to clean up
/// as part of cleaning up after an exception.
/// </summary>
/// <remarks>
/// Don't do anything that could throw in this method,
/// it will cause later recover operations to get skipped
/// and play real havoc with the stack trace.
/// </remarks>
public void Recover()
{
TryExit();
}
protected virtual void TryExit()
{
#if !NET40
// Prevent first chance exception when abandoning a lock that has not been entered
if (!Monitor.IsEntered(_lock)) return;
#endif
try
{
Monitor.Exit(_lock);
}
catch (SynchronizationLockException)
{
// Noop here - we don't hold the lock and that's ok.
}
}
#region IDisposable
/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
/// </summary>
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
/// <summary>
/// Standard Dispose pattern implementation.
/// </summary>
/// <param name="disposing">Always true, since we don't have a finalizer.</param>
protected virtual void Dispose(bool disposing)
{
TryExit();
}
#endregion
}
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,134 @@
using System;
namespace Unity.Lifetime
{
/// <summary>
/// <para>
/// Unity returns the same instance each time the Resolve(...) method is called or when the
/// dependency mechanism injects the instance into other classes.
/// </para>
/// </summary>
/// <remarks>
/// <para>
/// Per Container lifetime allows a registration of an existing or resolved object as
/// a scoped singleton in the container it was created or registered. In other words
/// this instance is unique within the container it war registered with. Child or parent
/// containers could have their own instances registered for the same contract.
/// </para>
/// <para>
/// When the <see cref="ContainerControlledLifetimeManager"/> is disposed,
/// the instance is disposed with it.
/// </para>
/// </remarks>
public class ContainerControlledLifetimeManager : SynchronizedLifetimeManager,
IInstanceLifetimeManager,
IFactoryLifetimeManager,
ITypeLifetimeManager
{
#region Fields
/// <summary>
/// An instance of the object this manager is associated with.
/// </summary>
/// <value>This field holds a strong reference to the associated object.</value>
protected object Value = NoValue;
#endregion
#region Constructor
public ContainerControlledLifetimeManager()
{
Set = base.SetValue;
Get = base.GetValue;
TryGet = base.TryGetValue;
}
#endregion
#region Scope
public object? Scope { get; set; }
#endregion
#region SynchronizedLifetimeManager
/// <inheritdoc/>
public override object GetValue(ILifetimeContainer? container = null)
{
return Get(container);
}
/// <inheritdoc/>
public override void SetValue(object newValue, ILifetimeContainer? container = null)
{
Set(newValue, container);
Set = (o, c) => throw new InvalidOperationException("ContainerControlledLifetimeManager can only be set once");
Get = SynchronizedGetValue;
TryGet = SynchronizedGetValue;
}
/// <inheritdoc/>
protected override object SynchronizedGetValue(ILifetimeContainer? container = null) => Value;
/// <inheritdoc/>
protected override void SynchronizedSetValue(object newValue, ILifetimeContainer? container = null) => Value = newValue;
/// <inheritdoc/>
public override void RemoveValue(ILifetimeContainer? container = null) => Dispose();
#endregion
#region IFactoryLifetimeManager
/// <inheritdoc/>
protected override LifetimeManager OnCreateLifetimeManager()
{
return new ContainerControlledLifetimeManager
{
Scope = Scope
};
}
#endregion
#region IDisposable
/// <inheritdoc/>
protected override void Dispose(bool disposing)
{
try
{
if (NoValue == Value) return;
if (Value is IDisposable disposable)
{
disposable.Dispose();
}
Value = NoValue;
}
finally
{
base.Dispose(disposing);
}
}
#endregion
#region Overrides
/// <summary>
/// This method provides human readable representation of the lifetime
/// </summary>
/// <returns>Name of the lifetime</returns>
public override string ToString() => "Lifetime:PerContainer";
#endregion
}
}

Просмотреть файл

@ -0,0 +1,38 @@
using System;
namespace Unity.Lifetime
{
/// <summary>
/// A special lifetime manager which works like <see cref="TransientLifetimeManager"/>,
/// except container remembers all Disposable objects it created. Once container
/// is disposed all these objects are disposed as well.
/// </summary>
public class ContainerControlledTransientManager : LifetimeManager,
IFactoryLifetimeManager,
ITypeLifetimeManager
{
/// <inheritdoc/>
public override void SetValue(object newValue, ILifetimeContainer? container = null)
{
if (newValue is IDisposable disposable)
container?.Add(disposable);
}
/// <inheritdoc/>
protected override LifetimeManager OnCreateLifetimeManager()
=> new ContainerControlledTransientManager();
/// <inheritdoc/>
public override bool InUse
{
get => false;
set { }
}
/// <summary>
/// This method provides human readable representation of the lifetime
/// </summary>
/// <returns>Name of the lifetime</returns>
public override string ToString() => "Lifetime:PerContainerTransient";
}
}

Просмотреть файл

@ -0,0 +1,58 @@
using System;
namespace Unity.Lifetime
{
/// <summary>
/// A <see cref="LifetimeManager"/> that holds a weak reference to
/// it's managed instance.
/// </summary>
public class ExternallyControlledLifetimeManager : SynchronizedLifetimeManager,
IInstanceLifetimeManager,
ITypeLifetimeManager,
IFactoryLifetimeManager
{
#region Fields
private WeakReference? _value;
#endregion
#region SynchronizedLifetimeManager
/// <inheritdoc/>
protected override object SynchronizedGetValue(ILifetimeContainer? container = null)
{
if (null == _value) return NoValue;
var target = _value.Target;
if (null != target) return target;
_value = null;
return NoValue;
}
/// <inheritdoc/>
protected override void SynchronizedSetValue(object newValue, ILifetimeContainer? container = null)
{
_value = new WeakReference(newValue);
}
/// <inheritdoc/>
public override void RemoveValue(ILifetimeContainer? container = null) => _value = null;
#endregion
#region Overrides
protected override LifetimeManager OnCreateLifetimeManager()
=> new ExternallyControlledLifetimeManager();
public override string ToString() => "Lifetime:External";
#endregion
}
}

Просмотреть файл

@ -0,0 +1,127 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
namespace Unity.Lifetime
{
/// <summary>
/// A special lifetime manager which works like <see cref="ContainerControlledLifetimeManager"/>,
/// except that in the presence of child containers, each child gets it's own instance
/// of the object, instead of sharing one in the common parent.
/// </summary>
/// <remarks>
/// <para>
/// The Unity container allows creating hierarchies of child containers. This lifetime
/// creates local singleton for each level of the hierarchy. So, when you resolve a
/// type and this container does not have an instance of that type, the container will
/// create new instance. Next type the type is resolved the same instance will be returned.
/// </para>
/// <para>
/// If a child container is created and requested to resolve the type, the child container
/// will create a new instance and store it for subsequent resolutions. Next time the
/// child container requested to resolve the type, it will return stored instance.
/// </para>
/// <para>If you have multiple children, each will resolve its own instance.</para>
/// </remarks>
public class HierarchicalLifetimeManager : SynchronizedLifetimeManager,
IFactoryLifetimeManager,
ITypeLifetimeManager
{
#region Fields
private readonly IDictionary<ILifetimeContainer, object> _values =
new ConcurrentDictionary<ILifetimeContainer, object>();
#endregion
#region Overrides
/// <inheritdoc/>
protected override object SynchronizedGetValue(ILifetimeContainer? container = null)
{
return _values.TryGetValue(container ?? throw new ArgumentNullException(nameof(container)),
out object? value) ? value : NoValue;
}
/// <inheritdoc/>
protected override void SynchronizedSetValue(object newValue, ILifetimeContainer? container = null)
{
_values[container ?? throw new ArgumentNullException(nameof(container))] = newValue;
container.Add(new DisposableAction(() => RemoveValue(container)));
}
/// <inheritdoc/>
public override void RemoveValue(ILifetimeContainer? container = null)
{
if (null == container) throw new ArgumentNullException(nameof(container));
if (!_values.TryGetValue(container, out object? value)) return;
_values.Remove(container);
if (value is IDisposable disposable)
{
disposable.Dispose();
}
}
/// <inheritdoc/>
protected override LifetimeManager OnCreateLifetimeManager()
=> new HierarchicalLifetimeManager();
/// <summary>
/// This method provides human readable representation of the lifetime
/// </summary>
/// <returns>Name of the lifetime</returns>
public override string ToString() => "Lifetime:Hierarchical";
#endregion
#region IDisposable
/// <inheritdoc/>
protected override void Dispose(bool disposing)
{
try
{
if (0 == _values.Count) return;
foreach (var disposable in _values.Values
.OfType<IDisposable>()
.ToArray())
{
disposable.Dispose();
}
_values.Clear();
}
finally
{
base.Dispose(disposing);
}
}
#endregion
#region Nested Types
private class DisposableAction : IDisposable
{
private readonly Action _action;
public DisposableAction(Action action)
{
_action = action ?? throw new ArgumentNullException(nameof(action));
}
public void Dispose()
{
_action();
}
}
#endregion
}
}

Просмотреть файл

@ -0,0 +1,40 @@
namespace Unity.Lifetime
{
/// <summary>
/// This is a custom lifetime manager that acts like <see cref="TransientLifetimeManager"/>,
/// but also provides a signal to the default build plan, marking the type so that
/// instances are reused across the build up object graph.
/// </summary>
public class PerResolveLifetimeManager : LifetimeManager,
IInstanceLifetimeManager,
IFactoryLifetimeManager,
ITypeLifetimeManager
{
#region Fields
protected object value = NoValue;
#endregion
#region Overrides
/// <inheritdoc/>
public override object GetValue(ILifetimeContainer? container = null)
{
return value;
}
/// <inheritdoc/>
protected override LifetimeManager OnCreateLifetimeManager()
=> new PerResolveLifetimeManager();
/// <summary>
/// This method provides human readable representation of the lifetime
/// </summary>
/// <returns>Name of the lifetime</returns>
public override string ToString() => "Lifetime:PerResolve";
#endregion
}
}

Просмотреть файл

@ -0,0 +1,68 @@
using System;
using System.Collections.Generic;
namespace Unity.Lifetime
{
/// <summary>
/// A <see cref="LifetimeManager"/> that creates a new instance of
/// the registered <see cref="Type"/> once per each thread.
/// </summary>
/// <remarks>
/// <para>
/// Per thread lifetime means a new instance of the registered <see cref="Type"/>
/// will be created once per each thread. In other words, if a Resolve{T}() method
/// is called on a thread the first time, it will return a new object. Each
/// subsequent call to Resolve{T}(), or when the dependency mechanism injects
/// instances of the type into other classes on the same thread, the container
/// will return the same object.
/// </para>
/// <para>
/// This LifetimeManager does not dispose the instances it holds.
/// </para>
/// </remarks>
public class PerThreadLifetimeManager : LifetimeManager,
IFactoryLifetimeManager,
ITypeLifetimeManager
{
#region Fields
[ThreadStatic]
private static Dictionary<Guid, object>? _values;
private readonly Guid _key = Guid.NewGuid();
#endregion
#region Overrides
/// <inheritdoc/>
public override object GetValue(ILifetimeContainer? container = null)
{
if (null == _values) return NoValue;
return _values.TryGetValue(_key, out var result) ? result : NoValue;
}
/// <inheritdoc/>
public override void SetValue(object newValue, ILifetimeContainer? container = null)
{
// no need for locking, values is TLS
if (_values == null)
_values = new Dictionary<Guid, object>();
_values[_key] = newValue;
}
/// <inheritdoc/>
protected override LifetimeManager OnCreateLifetimeManager()
=> new PerThreadLifetimeManager();
/// <summary>
/// This method provides human readable representation of the lifetime
/// </summary>
/// <returns>Name of the lifetime</returns>
public override string ToString() => "Lifetime:PerThread";
#endregion
}
}

Просмотреть файл

@ -0,0 +1,43 @@

namespace Unity.Lifetime
{
/// <summary>
/// Singleton lifetime creates globally unique singleton. Any Unity container tree
/// (parent and all the children) is guaranteed to have only one global singleton
/// for the registered type.
/// </summary>
/// <remarks>
/// <para>
/// Registering a type with singleton lifetime always places the registration
/// at the root of the container tree and makes it globally available for all
/// the children of that container. It does not matter if registration takes
/// places at the root of child container the destination is always the root node.
/// </para>
/// <para>
/// Repeating the registration on any of the child nodes with singleton lifetime
/// will always override the root registration.
/// </para>
/// <para>
/// When the <see cref="SingletonLifetimeManager"/> is disposed, the instance it holds
/// is disposed with it.</para>
/// </remarks>
public class SingletonLifetimeManager : ContainerControlledLifetimeManager
{
protected override LifetimeManager OnCreateLifetimeManager()
{
return new SingletonLifetimeManager()
{
Scope = Scope
};
}
#region Overrides
/// <summary>
/// This method provides human readable representation of the lifetime
/// </summary>
/// <returns>Name of the lifetime</returns>
public override string ToString() => "Lifetime:Singleton";
#endregion
}
}

Просмотреть файл

@ -0,0 +1,48 @@
namespace Unity.Lifetime
{
/// <summary>
/// An <see cref="LifetimeManager"/> implementation that does nothing,
/// thus ensuring that instances are created new every time.
/// </summary>
/// <remarks>
/// Transient lifetime is a default lifetime of the Unity container. As
/// the name implies it lasts very short period of time, actually, no
/// time at all. In the Unity container terms, having transient lifetime
/// is the same as having no lifetime manager at all.
/// </remarks>
public class TransientLifetimeManager : LifetimeManager,
IFactoryLifetimeManager,
ITypeLifetimeManager
{
#region Fields
/// <summary>
/// Globally unique transient lifetime manager singleton
/// </summary>
/// <remarks>
/// This instance is used for all transient lifetimes
/// </remarks>
/// <value>An instance of a <see cref="TransientLifetimeManager"/> object.</value>
public static readonly TransientLifetimeManager Instance = new TransientLifetimeManager();
#endregion
#region Overrides
/// <inheritdoc/>
public override bool InUse { get => false; set { } }
/// <inheritdoc/>
protected override LifetimeManager OnCreateLifetimeManager()
=> new TransientLifetimeManager();
/// <summary>
/// This method provides human readable representation of the lifetime
/// </summary>
/// <returns>Name of the lifetime</returns>
public override string ToString() => "Lifetime:Transient";
#endregion
}
}

52
src/Policy/IPolicyList.cs Normal file
Просмотреть файл

@ -0,0 +1,52 @@
using System;
namespace Unity.Policy
{
/// <summary>
/// A custom collection over <see cref="Object"/> objects.
/// </summary>
public interface IPolicyList
{
/// <summary>
/// Get default policy for the type
/// </summary>
/// <param name="type">Type of the registration</param>
/// <param name="policyInterface">Type of policy to retrieve</param>
/// <returns>Instance of the policy or null if none found</returns>
object Get(Type type, Type policyInterface);
/// <summary>
/// Get policy
/// </summary>
/// <param name="type">Type of the registration</param>
/// <param name="name">Name of the registration</param>
/// <param name="policyInterface">Type of policy to retrieve</param>
/// <returns>Instance of the policy or null if none found</returns>
object Get(Type type, string? name, Type policyInterface);
/// <summary>
/// Set default policy for the type
/// </summary>
/// <param name="type">Type of the registration</param>
/// <param name="policyInterface">Type of policy to be set</param>
/// <param name="policy">Policy instance to be set</param>
void Set(Type type, Type policyInterface, object policy);
/// <summary>
/// Set policy
/// </summary>
/// <param name="type">Type of the registration</param>
/// <param name="name">Name of the registration</param>
/// <param name="policyInterface">Type of policy to be set</param>
/// <param name="policy">Policy instance to be set</param>
void Set(Type type, string? name, Type policyInterface, object policy);
/// <summary>
/// Remove specific policy from the list
/// </summary>
/// <param name="type">Type of the registration</param>
/// <param name="name">Name of the registration</param>
/// <param name="policyInterface">Type of policy to be removed</param>
void Clear(Type type, string? name, Type policyInterface);
}
}

40
src/Policy/IPolicySet.cs Normal file
Просмотреть файл

@ -0,0 +1,40 @@
using System;
namespace Unity.Policy
{
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>
object 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, object policy);
/// <summary>
/// Remove specific policy from the list
/// </summary>
/// <param name="policyInterface">Type of policy to be removed</param>
void Clear(Type policyInterface);
}
public static class PolicySetExtensions
{
public static T Get<T>(this IPolicySet policySet)
{
return (T)policySet.Get(typeof(T));
}
public static void Set<T>(this IPolicySet policySet, object policy)
{
policySet.Set(typeof(T), policy);
}
}
}

Просмотреть файл

@ -0,0 +1,25 @@
using System;
using System.Runtime.CompilerServices;
using System.Security;
[assembly: CLSCompliant(true)]
[assembly: AllowPartiallyTrustedCallers]
[assembly: InternalsVisibleTo("Unity.Container, PublicKey=" +
"002400000480000094000000060200000024000052534131000400000100010037b16015885a7a" +
"c3c63f3c10b23972ec0dfd6db643eaef45ea2297bdfdc53b1945017fc76fd038dc6e7bf9190024" +
"d5435fa49630fdfd143e3149a1506b895fbcce017df1d4f0eac6f05f6d257be45c7be9a8aa8d3d" +
"4164892dc75e7c379a22da0d986db393fbd09e4ba42398c80a305361553ef90eb3484d9cf12df9" +
"0fc0e6e3")]
[assembly: InternalsVisibleTo("Abstractions.Tests, PublicKey=" +
"002400000480000094000000060200000024000052534131000400000100010037b16015885a7a" +
"c3c63f3c10b23972ec0dfd6db643eaef45ea2297bdfdc53b1945017fc76fd038dc6e7bf9190024" +
"d5435fa49630fdfd143e3149a1506b895fbcce017df1d4f0eac6f05f6d257be45c7be9a8aa8d3d" +
"4164892dc75e7c379a22da0d986db393fbd09e4ba42398c80a305361553ef90eb3484d9cf12df9" +
"0fc0e6e3")]
[assembly: InternalsVisibleTo("Unity.Abstractions.Tests, PublicKey=" +
"002400000480000094000000060200000024000052534131000400000100010037b16015885a7a" +
"c3c63f3c10b23972ec0dfd6db643eaef45ea2297bdfdc53b1945017fc76fd038dc6e7bf9190024" +
"d5435fa49630fdfd143e3149a1506b895fbcce017df1d4f0eac6f05f6d257be45c7be9a8aa8d3d" +
"4164892dc75e7c379a22da0d986db393fbd09e4ba42398c80a305361553ef90eb3484d9cf12df9" +
"0fc0e6e3")]

Просмотреть файл

@ -0,0 +1,22 @@
namespace Unity.Resolution
{
public delegate object? ResolveDelegate<TContext>(ref TContext context)
where TContext : IResolveContext;
/// <summary>
/// A strategy that is used at build plan execution time
/// to resolve a dependent value.
/// </summary>
public interface IResolve
{
/// <summary>
/// GetOrDefault the value
/// </summary>
/// <param name="context">Current build context.</param>
/// <returns>The value for the dependency.</returns>
object? Resolve<TContext>(ref TContext context)
where TContext : IResolveContext;
}
}

Просмотреть файл

@ -0,0 +1,29 @@
using System;
using Unity.Policy;
namespace Unity.Resolution
{
public interface IResolveContext : IPolicyList
{
/// <summary>Reference to container.</summary>
IUnityContainer Container { get; }
/// <summary>
/// Type being resolved.
/// </summary>
Type Type { get; }
/// <summary>
/// Name of the registered type
/// </summary>
string? Name { get; }
/// <summary>
/// Resolve type/object/dependency using current context
/// </summary>
/// <param name="type">Type of requested object</param>
/// <param name="name">Name of registration</param>
/// <returns></returns>
object Resolve(Type type, string? name);
}
}

Просмотреть файл

@ -0,0 +1,48 @@
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
namespace Unity.Resolution
{
public class IResolveContextExpression<TContext>
where TContext : IResolveContext
{
public static readonly MethodInfo ResolveMethod =
typeof(IResolveContext).GetTypeInfo()
.GetDeclaredMethods(nameof(IResolveContext.Resolve))
.First();
#region Constructor
static IResolveContextExpression()
{
var typeInfo = typeof(TContext).GetTypeInfo();
var contextRefType =
typeof(ResolveDelegate<TContext>).GetTypeInfo()
.GetDeclaredMethod("Invoke")!
.GetParameters()[0]
.ParameterType;
Context = Expression.Parameter(contextRefType, "context");
Type = Expression.MakeMemberAccess(Context, typeInfo.GetDeclaredProperty(nameof(IResolveContext.Type))!);
Name = Expression.MakeMemberAccess(Context, typeInfo.GetDeclaredProperty(nameof(IResolveContext.Name))!);
Container = Expression.MakeMemberAccess(Context, typeInfo.GetDeclaredProperty(nameof(IResolveContext.Container))!);
}
#endregion
#region Properties
public static readonly ParameterExpression Context;
public static readonly MemberExpression Type;
public static readonly MemberExpression Name;
public static readonly MemberExpression Container;
#endregion
}
}

Просмотреть файл

@ -0,0 +1,13 @@
using System;
namespace Unity.Resolution
{
public delegate ResolveDelegate<TContext> ResolverFactory<TContext>(Type type)
where TContext : IResolveContext;
public interface IResolverFactory<in TMemberInfo>
{
ResolveDelegate<TContext> GetResolver<TContext>(TMemberInfo info)
where TContext : IResolveContext;
}
}

Просмотреть файл

@ -0,0 +1,39 @@
using System;
namespace Unity.Resolution
{
public struct NamedType
{
public Type Type;
public string Name;
public override int GetHashCode() => GetHashCode(Type, Name);
public static int GetHashCode(Type type, string name) => ((type?.GetHashCode() ?? 0) + 37) ^ ((name?.GetHashCode() ?? 0) + 17);
public static int GetHashCode(int typeHash, int nameHash) => (typeHash + 37) ^ (nameHash + 17);
public override bool Equals(object? obj)
{
if (obj is NamedType other && Type == other.Type && Name == other.Name)
return true;
return false;
}
public static bool operator ==(NamedType obj1, NamedType obj2)
{
return obj1.Type == obj2.Type && obj1.Name == obj2.Name;
}
public static bool operator !=(NamedType obj1, NamedType obj2)
{
return obj1.Type != obj2.Type || obj1.Name != obj2.Name;
}
public override string ToString()
{
return $"Type: {Type?.Name}, Name: {Name}";
}
}
}

Просмотреть файл

@ -0,0 +1,94 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net6.0;netstandard2.0;netstandard1.0</TargetFrameworks>
</PropertyGroup>
<!-- Defaults -->
<PropertyGroup>
<Nullable>enable</Nullable>
<LangVersion>latest</LangVersion>
<RootNamespace>Unity</RootNamespace>
</PropertyGroup>
<!-- Package Info -->
<PropertyGroup>
<PackageId>Unity.Abstractions</PackageId>
<Description>Unity Container Public Abstractions</Description>
<Copyright>Copyright © .NET Foundation and Contributors. All Rights Reserved</Copyright>
<PackageProjectUrl>https://github.com/unitycontainer</PackageProjectUrl>
<RepositoryUrl>https://github.com/unitycontainer/abstractions</RepositoryUrl>
<PackageLicenseUrl>https://github.com/unitycontainer/abstractions/blob/master/LICENSE</PackageLicenseUrl>
<PackageIconUrl>https://avatars1.githubusercontent.com/u/12849707</PackageIconUrl>
<RepositoryType>git</RepositoryType>
<Authors>Unity Open Source Project</Authors>
<Company>Unity Open Source Project</Company>
<PackageTags>Unity Container unitycontainer Microsoft.Practices.Unity IoC</PackageTags>
</PropertyGroup>
<!-- Strong Name Signature -->
<PropertyGroup>
<AssemblyOriginatorKeyFile>package.snk</AssemblyOriginatorKeyFile>
<SignAssembly>true</SignAssembly>
<DelaySign>false</DelaySign>
</PropertyGroup>
<!-- Configurations -->
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<NoWarn>$(NoWarn);NETSDK1138</NoWarn> <!-- Out Of Support -->
<NoWarn>$(NoWarn);NU3005</NoWarn> <!-- Invalid Header in System.xx -->
<DebugType>Portable</DebugType>
<AllowedOutputExtensionsInPackageBuildOutputFolder>$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb</AllowedOutputExtensionsInPackageBuildOutputFolder>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
<NoWarn>$(NoWarn);NETSDK1138</NoWarn> <!-- Out Of Support -->
<NoWarn>$(NoWarn);NU3005</NoWarn> <!-- Invalid Header in System.xx -->
<DebugType>Full</DebugType>
</PropertyGroup>
<!-- Exclusions -->
<ItemGroup Condition="'$(TargetFramework)' != '' AND '$(TargetFramework)' != 'netstandard1.0' ">
<Compile Remove="Lifetime\Managers\ConcurrentDictionary.cs" />
</ItemGroup>
<!-- Symbols -->
<PropertyGroup>
<IncludeSymbols>true</IncludeSymbols>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<EmbedUntrackedSources>true</EmbedUntrackedSources>
<AllowedOutputExtensionsInPackageBuildOutputFolder>$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb</AllowedOutputExtensionsInPackageBuildOutputFolder>
</PropertyGroup>
<ItemGroup>
<None Remove="package.props" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
</ItemGroup>
<!-- Release Notes -->
<Target Name="PreparePackageReleaseNotesFromFile" BeforeTargets="GenerateNuspec">
<ReadLinesFromFile File="../RELEASE-NOTES.txt">
<Output TaskParameter="Lines" ItemName="ReleaseNoteLines" />
</ReadLinesFromFile>
<PropertyGroup>
<PackageReleaseNotes>@(ReleaseNoteLines, '%0a')</PackageReleaseNotes>
</PropertyGroup>
</Target>
</Project>

Просмотреть файл

@ -1,27 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<PackageId>Unity.Experimental</PackageId>
<Description>Unity Container Experimental Package</Description>
<Copyright>Copyright © Unity Container Project 2018</Copyright>
<PackageProjectUrl>https://github.com/unitycontainer</PackageProjectUrl>
<RepositoryUrl>https://github.com/unitycontainer/experimental</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<Authors>Unity Open Source Project</Authors>
<Company>Unity Open Source Project</Company>
<LangVersion>latest</LangVersion>
<Nullable>enable</Nullable>
<TargetFrameworks>net7.0</TargetFrameworks>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<DebugType>Portable</DebugType>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
<DebugType>Full</DebugType>
</PropertyGroup>
</Project>

Двоичные данные
src/package.snk Normal file

Двоичный файл не отображается.

Просмотреть файл

@ -0,0 +1,28 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework Condition=" '$(TargetFramework)' == '' ">net6.0</TargetFramework>
<LangVersion>latest</LangVersion>
<IsPackable>false</IsPackable>
</PropertyGroup>
<!-- Strong Name Signature -->
<PropertyGroup>
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>..\src\package.snk</AssemblyOriginatorKeyFile>
<DelaySign>false</DelaySign>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0" />
<PackageReference Include="MSTest.TestAdapter" Version="3.0.2" />
<PackageReference Include="MSTest.TestFramework" Version="3.0.2" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\src\Unity.Abstractions.csproj" />
</ItemGroup>
</Project>

Просмотреть файл

@ -0,0 +1,62 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Collections.Generic;
using Unity;
using Unity.Injection;
namespace Injection.Extensions
{
[TestClass]
public class RegistrationTests
{
[DataTestMethod]
[DynamicData(nameof(GetInjectArrayVariants), DynamicDataSourceType.Method)]
public void InjectArrayTests(object instance)
{
// Validate
Assert.IsInstanceOfType(instance, typeof(ResolvedArrayParameter));
}
public static IEnumerable<object[]> GetInjectArrayVariants()
{
yield return new object[] { Inject.Array(typeof(string)) };
yield return new object[] { Inject.Array(typeof(string), string.Empty) };
yield return new object[] { Inject.Array<string>(string.Empty) };
}
// TODO: Issue 146
//[DataTestMethod]
//[ExpectedException(typeof(ArgumentNullException))]
//[DynamicData(nameof(GetInjectArrayInvalidVariants), DynamicDataSourceType.Method)]
//public void InjectArrayValidationTests()
//{
// _ = Inject.Array(null);
//}
//public static IEnumerable<object[]> GetInjectArrayInvalidVariants()
//{
// // TODO: Issue #146 yield return new object[] { Inject.Array(null) };
// yield return new object[] { Inject.Array(typeof(string), string.Empty) };
//}
//[DataTestMethod]
//[DynamicData(nameof(GetInjectParameterVariants), DynamicDataSourceType.Method)]
//public void InjectParameterTests(object instance)
//{
// // Validate
// Assert.IsInstanceOfType(instance, typeof(ParameterBase));
//}
//public static IEnumerable<object[]> GetInjectParameterVariants()
//{
// yield return new object[] { Inject.Parameter(new object()) };
//}
//[TestMethod]
//public void InjectFieldTests()
//{ }
//[TestMethod]
//public void InjectPropertyTests()
//{ }
}
}

Просмотреть файл

@ -0,0 +1,100 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;
using Unity.Injection;
namespace Injection.Matching
{
[TestClass]
public class ParametersMatchTests
{
[DataTestMethod]
[DynamicData(nameof(GetMatchesData), DynamicDataSourceType.Method)]
public void MatchesTest(object data, Type match, bool result)
{
// Validate
Assert.AreEqual(result, data.Matches(match));
}
[DataTestMethod]
[DynamicData(nameof(GetTypeMatchesData), DynamicDataSourceType.Method)]
public void MatchesTypeTest(Type type, Type match, bool result)
{
// Validate
Assert.AreEqual(result, type.MatchesType(match));
}
[DataTestMethod]
[DynamicData(nameof(GetObjectMatchesData), DynamicDataSourceType.Method)]
public void MatchesObjectTest(object parameter, Type match, bool result)
{
// Validate
Assert.AreEqual(result, parameter.MatchesObject(match));
}
#region Test Data
public static IEnumerable<object[]> GetMatchesData()
{
yield return new object[] { null, null, true };
yield return new object[] { typeof(object), typeof(object), true };
yield return new object[] { new ResolvedParameter(typeof(object)), typeof(object), true };
}
public static IEnumerable<object[]> GetTypeMatchesData()
{
yield return new object[] { null, null, true };
yield return new object[] { null, typeof(object), true };
yield return new object[] { typeof(object), typeof(object), true };
yield return new object[] { typeof(object), typeof(object[]), false };
yield return new object[] { typeof(object[]), typeof(object), true };
yield return new object[] { typeof(object[]), typeof(object[]), true };
yield return new object[] { typeof(object[]), typeof(Array), true };
yield return new object[] { typeof(Array), typeof(object[]), true };
yield return new object[] { typeof(Array), typeof(Array), true };
yield return new object[] { typeof(string[]), typeof(string[]), true };
yield return new object[] { typeof(string), typeof(string[]), false };
yield return new object[] { typeof(string[]), typeof(string), false };
yield return new object[] { typeof(List<>), typeof(List<>), true };
yield return new object[] { typeof(List<int>), typeof(List<>), false };
yield return new object[] { typeof(List<>), typeof(List<int>), true };
yield return new object[] { typeof(List<int>), typeof(List<int>), true };
}
public static IEnumerable<object[]> GetObjectMatchesData()
{
// Generic
// Array
// TODO: Issue #152 yield return new object[] { new string[0], typeof(int[]), false };
yield return new object[] { new string[0], typeof(int[]), true };
// match.IsAssignableFrom
yield return new object[] { new object[0], typeof(object), true };
yield return new object[] { new object[0], typeof(Array), true };
yield return new object[] { new object[0], typeof(object[]), true };
yield return new object[] { new object[0], typeof(string[]), true };
yield return new object[] { new string[0], typeof(object), true };
yield return new object[] { new string[0], typeof(Array), true };
yield return new object[] { new string[0], typeof(object[]), true };
yield return new object[] { new string[0], typeof(string[]), true };
yield return new object[] { new string[0], typeof(string), false };
yield return new object[] { typeof(object), typeof(object), true };
yield return new object[] { new object(), typeof(object), true };
yield return new object[] { null, null, true };
yield return new object[] { null, typeof(object), true };
yield return new object[] { string.Empty, typeof(string), true };
yield return new object[] { string.Empty, typeof(object), true };
yield return new object[] { string.Empty, typeof(int), false };
}
#endregion
}
}

Просмотреть файл

@ -0,0 +1,43 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;
using System.Reflection;
using Unity.Injection;
namespace Injection.Matching
{
[TestClass]
public class SignatureMatchTests
{
[DataTestMethod]
[DynamicData(nameof(GetSignatureMatchData), DynamicDataSourceType.Method)]
public void SignatureMatchTest(object[] data, MethodBase info, bool result)
{
// Validate
Assert.AreEqual(result, data.MatchMemberInfo(info));
}
#region Test Data
public static IEnumerable<object[]> GetSignatureMatchData()
{
var type = typeof(TestClass);
yield return new object[] { null, type.GetMethod(nameof(TestClass.Test1)), true };
yield return new object[] { null, type.GetMethod(nameof(TestClass.Test2)), false };
yield return new object[] { new object[0], type.GetMethod(nameof(TestClass.Test1)), true };
yield return new object[] { new object[] { typeof(Type) }, type.GetMethod(nameof(TestClass.Test1)), false };
yield return new object[] { new object[0], type.GetMethod(nameof(TestClass.Test2)), false };
yield return new object[] { new object[] { typeof(int) }, type.GetMethod(nameof(TestClass.Test2)), true };
yield return new object[] { new object[] { typeof(Type) }, type.GetMethod(nameof(TestClass.Test2)), false };
}
public class TestClass
{
public void Test1() { }
public void Test2(int i) { }
}
#endregion
}
}

Просмотреть файл

@ -0,0 +1,18 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Collections.Generic;
using System.Reflection;
using Unity.Injection;
namespace Injection.Members
{
[TestClass]
public class ConstructorTests : InjectionBaseTests<ConstructorInfo, object[]>
{
#region Test Data
protected override InjectionMember<ConstructorInfo, object[]> GetDefaultMember() =>
new InjectionConstructor();
#endregion
}
}

Просмотреть файл

@ -0,0 +1,17 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Reflection;
using Unity.Injection;
namespace Injection.Members
{
[TestClass]
public class FieldTests : InjectionInfoBaseTests<FieldInfo>
{
#region Test Data
protected override InjectionMember<FieldInfo, object> GetDefaultMember() =>
new InjectionField("TestField");
#endregion
}
}

Просмотреть файл

@ -0,0 +1,179 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Linq;
using System.Reflection;
using Unity.Injection;
using Unity.Policy;
using Unity.Policy.Tests;
using Unity.Resolution;
namespace Injection.Members
{
public abstract class InjectionBaseTests<TMemberInfo, TData>
where TMemberInfo : MemberInfo
{
[TestMethod]
public virtual void InitializationTest()
{
// Arrange
var member = GetDefaultMember();
var set = new PolicySet();
var cast = set as IPolicySet;
// Validate
Assert.IsNotNull(member);
Assert.IsFalse(member.IsInitialized);
// Act
member.AddPolicies<IResolveContext, IPolicySet>(typeof(TestClass<>), typeof(TestClass<>), null, ref cast);
// Validate
Assert.IsTrue(member.IsInitialized);
}
[TestMethod]
[ExpectedException(typeof(NullReferenceException))] // TODO: wrong exception
public virtual void MemberInfoCold()
{
// Arrange
var member = GetDefaultMember();
_ = member.MemberInfo(typeof(TestClass<object>));
}
[TestMethod]
[ExpectedException(typeof(ArgumentException))]
public virtual void NoMatchAddPolicies()
{
var member = GetDefaultMember();
var set = new PolicySet();
var cast = set as IPolicySet;
// Act
member.AddPolicies<IResolveContext, IPolicySet>(typeof(NoMatchClass), typeof(NoMatchClass), null, ref cast);
}
[Ignore] // TODO: Inconsistent across members
[TestMethod]
[ExpectedException(typeof(InvalidOperationException))]
public virtual void NoMatchMemberInfo()
{
// Arrange
var member = GetDefaultMember();
var set = new PolicySet();
var cast = set as IPolicySet;
// Act
member.AddPolicies<IResolveContext, IPolicySet>(typeof(TestClass<>), typeof(TestClass<>), null, ref cast);
_ = member.MemberInfo(typeof(NoMatchClass));
}
[TestMethod]
public virtual void MemberInfoSimpleTest()
{
// Arrange
var member = GetDefaultMember();
var set = new PolicySet();
var cast = set as IPolicySet;
// Act
member.AddPolicies<IResolveContext, IPolicySet>(typeof(SimpleClass), typeof(SimpleClass), null, ref cast);
var info = member.MemberInfo(typeof(SimpleClass));
// Validate
Assert.IsNotNull(info);
}
[TestMethod]
public virtual void MemberInfoTest()
{
// Arrange
var member = GetDefaultMember();
var set = new PolicySet();
var cast = set as IPolicySet;
// Act
member.AddPolicies<IResolveContext, IPolicySet>(typeof(TestClass<>), typeof(TestClass<>), null, ref cast);
var info = member.MemberInfo(typeof(TestClass<object>));
// Validate
Assert.IsNotNull(info);
Assert.AreEqual(typeof(TestClass<object>), info.DeclaringType);
}
[TestMethod]
public virtual void DeclaredMembersTest()
{
// Act
var member = GetDefaultMember();
var members = member.DeclaredMembers(typeof(TestClass<object>))
.ToArray();
// Validate
Assert.AreEqual(2, members.Length);
}
protected abstract InjectionMember<TMemberInfo, TData> GetDefaultMember();
}
#region Test Data
public class SimpleClass
{
public string TestField;
public SimpleClass() => throw new NotImplementedException();
public string TestProperty { get; set; }
public void TestMethod(string a) => throw new NotImplementedException();
}
public class NoMatchClass
{
private NoMatchClass() { }
}
public class TestClass<T>
{
#region Constructors
static TestClass() { }
public TestClass() { }
private TestClass(string _) { }
protected TestClass(long _) { }
internal TestClass(int _) { }
#endregion
#region Fields
#pragma warning disable CS0169
#pragma warning disable CS0649
public readonly string TestReadonlyField;
internal string TestInternalField;
static string TestStaticField;
public string TestField;
private string TestPrivateField;
protected string TestProtectedField;
#pragma warning restore CS0169
#pragma warning restore CS0649
#endregion
#region Properties
internal string TestInternalProperty { get; set; }
public string TestReadonlyProperty { get; }
static string TestStaticProperty { get; set; }
public string TestProperty { get; set; }
private string TestPrivateProperty { get; set; }
protected string TestProtectedProperty { get; set; }
#endregion
#region Methods
static void TestMethod() { }
public void TestMethod(string _) { }
public void TestMethod(string a, T b, out object c) { c = null; }
private void TestMethod(int _) { }
protected void TestMethod(long _) { }
#endregion
}
#endregion
}

Просмотреть файл

@ -0,0 +1,40 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Linq;
using System.Reflection;
using Unity.Injection;
using Unity.Policy;
using Unity.Policy.Tests;
using Unity.Resolution;
namespace Injection.Members
{
public abstract class InjectionInfoBaseTests<TMemberInfo> : InjectionBaseTests<TMemberInfo, object>
where TMemberInfo : MemberInfo
{
#region Fields
private static PropertyInfo MemberTypeProperty = typeof(MemberInfoBase<TMemberInfo>).GetProperties(BindingFlags.Instance | BindingFlags.NonPublic)
.Where(i => i.Name == "MemberType")
.First();
#endregion
[TestMethod]
public virtual void MemberTypeTest()
{
// Arrange
var member = GetDefaultMember();
var set = new PolicySet();
var cast = set as IPolicySet;
// Act
member.AddPolicies<IResolveContext, IPolicySet>(typeof(TestClass<>), typeof(TestClass<>), null, ref cast);
var value = MemberTypeProperty.GetValue(member);
// Validate
Assert.IsNotNull(value);
Assert.IsInstanceOfType(value, typeof(Type));
}
}
}

Просмотреть файл

@ -0,0 +1,259 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Unity.Injection;
using Unity.Policy;
using Unity.Policy.Tests;
using Unity.Resolution;
namespace Injection.Members
{
[TestClass]
public class InjectionMemberTests
{
#region Fields
public static ConstructorInfo CtorInfo = typeof(PolicySet).GetConstructor(new Type[0]);
public static ConstructorInfo CtorStringInfo = typeof(PolicySet).GetConstructor(new Type[] { typeof(string) });
public static FieldInfo FieldInfo = typeof(PolicySet).GetField(nameof(PolicySet.NameField));
public static PropertyInfo PropertyInfo = typeof(PolicySet).GetProperty(nameof(PolicySet.NameProperty));
public static MethodInfo MethodInfo = typeof(PolicySet).GetMethod(nameof(PolicySet.TestMethod));
private static MethodInfo ToStringMethod = typeof(InjectionMember).GetMethods(BindingFlags.Instance|BindingFlags.NonPublic)
.Where(i => i.Name == nameof(InjectionMember.ToString))
.First();
#endregion
#region InjectionMember
[DataTestMethod]
[DynamicData(nameof(GetNotInitializedMembers), DynamicDataSourceType.Method)]
public virtual void NoAddedPoliciesTest(InjectionMember member, MemberInfo _)
{
// Arrange
var set = new PolicySet();
var cast = set as IPolicySet;
// Act
member.AddPolicies<IResolveContext, IPolicySet>(typeof(IPolicySet), typeof(PolicySet), null, ref cast);
// Validate
Assert.AreEqual(0, set.Count);
}
[DataTestMethod]
[ExpectedException(typeof(ArgumentException))]
[DynamicData(nameof(GetAllInjectionMembers), DynamicDataSourceType.Method)]
public virtual void AddWrongTypeTest(InjectionMember member, MemberInfo _)
{
// Arrange
var set = new PolicySet();
var cast = set as IPolicySet;
// Act
member.AddPolicies<IResolveContext, IPolicySet>(typeof(WrongType), typeof(WrongType), null, ref cast);
}
[DataTestMethod]
[DynamicData(nameof(GetAllInjectionMembers), DynamicDataSourceType.Method)]
public virtual void BuildRequiredTest(InjectionMember member, MemberInfo _)
{
// Validate
Assert.IsTrue(member.BuildRequired);
}
#endregion
#region Object Overrides
[DataTestMethod]
[DynamicData(nameof(GetNotInitializedMembers), DynamicDataSourceType.Method)]
public virtual void HashCodeCold(InjectionMember member, MemberInfo _)
{
// Act
var hash = member.GetHashCode();
// Validate
Assert.AreEqual(0, hash);
}
[DataTestMethod]
[DynamicData(nameof(GetAllInjectionMembers), DynamicDataSourceType.Method)]
public virtual void HashCodeTest(InjectionMember member, MemberInfo _)
{
// Arrange
var set = new PolicySet();
var cast = set as IPolicySet;
member.AddPolicies<IResolveContext, IPolicySet>(typeof(IPolicySet), typeof(PolicySet), null, ref cast);
// Act
var hash = member.GetHashCode();
// Validate
Assert.AreNotEqual(0, hash);
}
[DataTestMethod]
[DynamicData(nameof(GetNotInitializedMembers), DynamicDataSourceType.Method)]
public virtual void ToStringTest(InjectionMember member, MemberInfo _)
{
// Arrange
var set = new PolicySet();
var cast = set as IPolicySet;
// Act
var debugCold = ToStringMethod.Invoke(member, new object[] { true }) as string;
var optimized = ToStringMethod.Invoke(member, new object[] { false }) as string;
// Validate
Assert.IsFalse(string.IsNullOrWhiteSpace(optimized));
Assert.IsFalse(string.IsNullOrWhiteSpace(debugCold));
Assert.IsTrue(debugCold.StartsWith(member.GetType().Name));
// Act
member.AddPolicies<IResolveContext, IPolicySet>(typeof(IPolicySet), typeof(PolicySet), null, ref cast);
var debugInitialzed = ToStringMethod.Invoke(member, new object[] { true }) as string;
var initialized = ToStringMethod.Invoke(member, new object[] { false }) as string;
// Validate
Assert.IsFalse(string.IsNullOrWhiteSpace(debugInitialzed));
Assert.IsFalse(string.IsNullOrWhiteSpace(initialized ));
Assert.AreNotEqual(debugCold, debugInitialzed);
Assert.AreNotEqual(optimized, initialized);
}
#endregion
#region Equitability
[DataTestMethod]
[DynamicData(nameof(GetNotInitializedMembers), DynamicDataSourceType.Method)]
public virtual void EqualsCold(InjectionMember member, MemberInfo info)
{
// Validate
Assert.IsFalse(member.Equals(info));
}
[DataTestMethod]
[DynamicData(nameof(GetAllInjectionMembers), DynamicDataSourceType.Method)]
public virtual void EqualsTest(InjectionMember member, MemberInfo info)
{
// Arrange
var set = new PolicySet();
var cast = set as IPolicySet;
// Act
member.AddPolicies<IResolveContext, IPolicySet>(typeof(IPolicySet), typeof(PolicySet), null, ref cast);
// Validate
Assert.IsTrue(member.Equals(info));
}
[DataTestMethod]
[DynamicData(nameof(GetNotInitializedMembers), DynamicDataSourceType.Method)]
public virtual void EqualsObjectCold(InjectionMember member, MemberInfo info)
{
// Validate
Assert.IsFalse(member.Equals(info));
}
[DataTestMethod]
[DynamicData(nameof(GetAllInjectionMembers), DynamicDataSourceType.Method)]
public virtual void EqualsObjectWrong(InjectionMember member, MemberInfo info)
{
// Arrange
var set = new PolicySet();
var cast = set as IPolicySet;
// Act
member.AddPolicies<IResolveContext, IPolicySet>(typeof(IPolicySet), typeof(PolicySet), null, ref cast);
// Validate
Assert.IsFalse(member.Equals(this));
}
[DataTestMethod]
[DynamicData(nameof(GetAllInjectionMembers), DynamicDataSourceType.Method)]
public virtual void EqualsObjectSame(InjectionMember member, MemberInfo info)
{
// Arrange
var set = new PolicySet();
var cast = set as IPolicySet;
// Act
member.AddPolicies<IResolveContext, IPolicySet>(typeof(IPolicySet), typeof(PolicySet), null, ref cast);
// Validate
Assert.IsTrue(member.Equals(member));
}
[DataTestMethod]
[DynamicData(nameof(GetAllInjectionMembers), DynamicDataSourceType.Method)]
public virtual void EqualsObjectTest(InjectionMember member, MemberInfo info)
{
// Arrange
var set = new PolicySet();
var cast = set as IPolicySet;
// Act
member.AddPolicies<IResolveContext, IPolicySet>(typeof(IPolicySet), typeof(PolicySet), null, ref cast);
// Validate
Assert.IsTrue(member.Equals(info));
}
#endregion
#region Test Data
public static IEnumerable<object[]> GetNotInitializedMembers()
{
yield return new object[] { new InjectionConstructor(), CtorInfo };
yield return new object[] { new InjectionConstructor(typeof(string)), CtorStringInfo };
yield return new object[] { new InjectionMethod(nameof(PolicySet.TestMethod)), MethodInfo };
yield return new object[] { new InjectionMethod(nameof(PolicySet.TestMethod), typeof(Type)), MethodInfo };
yield return new object[] { new InjectionField(nameof(PolicySet.NameField)), FieldInfo };
yield return new object[] { new InjectionField(nameof(PolicySet.NameField), string.Empty), FieldInfo };
yield return new object[] { new InjectionProperty(nameof(PolicySet.NameProperty)), PropertyInfo };
yield return new object[] { new InjectionProperty(nameof(PolicySet.NameProperty), string.Empty), PropertyInfo };
}
public static IEnumerable<object[]> GetAllInjectionMembers()
{
yield return new object[] { new InjectionConstructor() , CtorInfo };
yield return new object[] { new InjectionConstructor(typeof(string)) , CtorStringInfo };
yield return new object[] { new InjectionConstructor(CtorStringInfo, typeof(string)) , CtorStringInfo };
yield return new object[] { new InjectionMethod(nameof(PolicySet.TestMethod)) , MethodInfo };
yield return new object[] { new InjectionMethod(nameof(PolicySet.TestMethod), typeof(Type)) , MethodInfo };
yield return new object[] { new InjectionField(nameof(PolicySet.NameField)) , FieldInfo };
yield return new object[] { new InjectionField(nameof(PolicySet.NameField), string.Empty) , FieldInfo };
yield return new object[] { new InjectionProperty(nameof(PolicySet.NameProperty)) , PropertyInfo };
yield return new object[] { new InjectionProperty(nameof(PolicySet.NameProperty), string.Empty) , PropertyInfo };
}
public class WrongType
{
public WrongType(int a)
{
}
}
#endregion
}
}

Просмотреть файл

@ -0,0 +1,66 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Linq;
using System.Reflection;
using Unity.Injection;
using Unity.Policy;
using Unity.Policy.Tests;
using Unity.Resolution;
namespace Injection.Members
{
[TestClass]
public class MethodTests : InjectionBaseTests<MethodInfo, object[]>
{
[TestMethod]
public virtual void InfoSelectionTest()
{
// Arrange
var member = new InjectionMethod("TestMethod", "test");
var set = new PolicySet();
var cast = set as IPolicySet;
// Act
member.AddPolicies<IResolveContext, IPolicySet>(typeof(MethodTestClass<>), typeof(MethodTestClass<>), null, ref cast);
var info = member.MemberInfo(typeof(MethodTestClass<int>));
// Validate
Assert.IsNotNull(info);
Assert.AreEqual(typeof(string), info.GetParameters().First().ParameterType);
}
[TestMethod]
public virtual void OpenGenericSelectionTest()
{
// Arrange
var member = new InjectionMethod("TestMethod", "test");
var set = new PolicySet();
var cast = set as IPolicySet;
// Act
member.AddPolicies<IResolveContext, IPolicySet>(typeof(MethodTestClass<>), typeof(MethodTestClass<>), null, ref cast);
var info = member.MemberInfo(typeof(MethodTestClass<>));
// Validate
Assert.IsNotNull(info);
Assert.AreEqual(typeof(string), info.GetParameters().First().ParameterType);
}
#region Test Data
protected override InjectionMember<MethodInfo, object[]> GetDefaultMember() =>
new InjectionMethod("TestMethod");
protected class MethodTestClass<T>
{
public void OtherTestMethod(string a) { }
public void Test_Method(TestClass<T> a) { }
public void TestMethod(T a) { }
public void TestMethod(string a) { }
public void TestMethod(string a, out object b) { b = null; }
}
#endregion
}
}

Просмотреть файл

@ -0,0 +1,17 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Reflection;
using Unity.Injection;
namespace Injection.Members
{
[TestClass]
public class PropertyTests : InjectionInfoBaseTests<PropertyInfo>
{
#region Test Data
protected override InjectionMember<PropertyInfo, object> GetDefaultMember() =>
new InjectionProperty("TestProperty");
#endregion
}
}

Просмотреть файл

@ -0,0 +1,192 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;
using System.Linq;
using Unity.Injection;
namespace Injection.Parameters
{
[TestClass]
public class EquatabilityTests
{
#region Fields
public void TestMethod<T, V>(T first, V second) => throw new NotImplementedException();
private static Type TrueType =
typeof(EquatabilityTests).GetMethod(nameof(TestMethod))
.GetParameters()
.First()
.ParameterType;
private static Type FalseType =
typeof(EquatabilityTests).GetMethod(nameof(TestMethod))
.GetParameters()
.Last()
.ParameterType;
private static Type TrueArrayType = TrueType.MakeArrayType();
private static Type FalseArrayType = FalseType.MakeArrayType();
#endregion
#region IEquatable
[DataTestMethod]
[DynamicData(nameof(GetEqualsAnyTypeData), DynamicDataSourceType.Method)]
public virtual void EqualsAnyTypeTest(ParameterValue parameter)
{
// Validate
Assert.IsTrue(parameter.Equals(typeof(int)));
Assert.IsTrue(parameter.Equals(typeof(object)));
Assert.IsTrue(parameter.Equals(typeof(string)));
Assert.IsTrue(parameter.Equals(typeof(List<>)));
Assert.IsTrue(parameter.Equals(typeof(List<string>)));
Assert.IsTrue(parameter.Equals(typeof(string[])));
Assert.IsTrue(parameter.Equals(typeof(object[])));
Assert.IsTrue(parameter.Equals(typeof(int[])));
}
[DataTestMethod]
[DynamicData(nameof(GetEqualsValueTypeData), DynamicDataSourceType.Method)]
public virtual void EqualsValueTypeTest(ParameterValue parameter)
{
// Validate
Assert.IsTrue(parameter.Equals(typeof(int)));
Assert.IsTrue(parameter.Equals(typeof(object)));
Assert.IsFalse(parameter.Equals(typeof(string)));
}
[DataTestMethod]
[DynamicData(nameof(GetEqualsArrayTypeData), DynamicDataSourceType.Method)]
public virtual void EqualsArrayTypeTest(ParameterValue parameter)
{
// Validate
Assert.IsTrue(parameter.Equals(typeof(string[])));
Assert.IsTrue(parameter.Equals(typeof(object[])));
Assert.IsFalse(parameter.Equals(typeof(string[,])));
Assert.IsFalse(parameter.Equals(typeof(int)));
Assert.IsFalse(parameter.Equals(typeof(int[])));
}
[DataTestMethod]
[DynamicData(nameof(GetEqualsGenericTypeData), DynamicDataSourceType.Method)]
public virtual void EqualsGenericTypeTest(ParameterValue parameter)
{
// Validate
Assert.IsTrue(parameter.Equals(typeof(List<>)));
Assert.IsFalse(parameter.Equals(typeof(IEnumerable<>)));
Assert.IsFalse(parameter.Equals(typeof(List<string>)));
}
[DataTestMethod]
[DynamicData(nameof(GetEqualsGenericParameterData), DynamicDataSourceType.Method)]
public virtual void EqualsGenericTest(ParameterValue parameter)
{
// Validate
Assert.IsTrue(parameter.Equals(TrueType));
Assert.IsFalse(parameter.Equals(typeof(string)));
Assert.IsFalse(parameter.Equals(FalseType));
}
[DataTestMethod]
[DynamicData(nameof(GetEqualsGenericArrayParameterData), DynamicDataSourceType.Method)]
public virtual void EqualsGenericArrayTest(ParameterValue parameter)
{
// Validate
Assert.IsTrue(parameter.Equals(TrueArrayType));
Assert.IsFalse(parameter.Equals(typeof(string)));
Assert.IsFalse(parameter.Equals(typeof(string[])));
Assert.IsFalse(parameter.Equals(typeof(string[,])));
Assert.IsFalse(parameter.Equals(FalseArrayType));
}
#endregion
#region Test Data
public static IEnumerable<object[]> GetEqualsAnyTypeData()
{
yield return new object[] { new OptionalParameter(), };
yield return new object[] { new OptionalParameter(string.Empty) };
yield return new object[] { new ResolvedParameter() };
yield return new object[] { new ResolvedParameter(string.Empty) };
}
public static IEnumerable<object[]> GetEqualsValueTypeData()
{
yield return new object[] { new InjectionParameter(0) };
yield return new object[] { new InjectionParameter(typeof(int), 0) };
yield return new object[] { new InjectionParameter<int>(0) };
yield return new object[] { new OptionalParameter(typeof(int)) };
yield return new object[] { new OptionalParameter<int>() };
yield return new object[] { new OptionalParameter(typeof(int), string.Empty) };
yield return new object[] { new OptionalParameter<int>(string.Empty) };
yield return new object[] { new ResolvedParameter(typeof(int)) };
yield return new object[] { new ResolvedParameter<int>() };
yield return new object[] { new ResolvedParameter(typeof(int), string.Empty) };
yield return new object[] { new ResolvedParameter<int>(string.Empty) };
}
public static IEnumerable<object[]> GetEqualsArrayTypeData()
{
yield return new object[] { new OptionalParameter(typeof(string[])) };
yield return new object[] { new OptionalParameter<string[]>() };
yield return new object[] { new OptionalParameter(typeof(string[]), string.Empty) };
yield return new object[] { new OptionalParameter<string[]>(string.Empty) };
yield return new object[] { new ResolvedParameter(typeof(string[])) };
yield return new object[] { new ResolvedParameter<string[]>() };
yield return new object[] { new ResolvedParameter(typeof(string[]), string.Empty) };
yield return new object[] { new ResolvedParameter<string[]>(string.Empty) };
yield return new object[] { new ResolvedArrayParameter(typeof(string)) };
yield return new object[] { new ResolvedArrayParameter<string>() };
yield return new object[] { new ResolvedArrayParameter(typeof(string), "string") };
yield return new object[] { new ResolvedArrayParameter(typeof(string), typeof(string), "string") };
yield return new object[] { new InjectionParameter(new string[0]) };
yield return new object[] { new InjectionParameter(typeof(string[]), new string[0]) };
yield return new object[] { new InjectionParameter<string[]>(new string[0]) };
}
public static IEnumerable<object[]> GetEqualsGenericTypeData()
{
yield return new object[] { new InjectionParameter(typeof(List<>), 0) };
yield return new object[] { new OptionalParameter(typeof(List<>)) };
yield return new object[] { new OptionalParameter(typeof(List<>), string.Empty) };
yield return new object[] { new ResolvedParameter(typeof(List<>)) };
yield return new object[] { new ResolvedParameter(typeof(List<>), string.Empty) };
}
public static IEnumerable<object[]> GetEqualsGenericParameterData()
{
yield return new object[] { new GenericParameter("T") };
yield return new object[] { new GenericParameter("T", string.Empty) };
yield return new object[] { new OptionalGenericParameter("T") };
yield return new object[] { new OptionalGenericParameter("T", string.Empty) };
}
public static IEnumerable<object[]> GetEqualsGenericArrayParameterData()
{
yield return new object[] { new GenericResolvedArrayParameter("T") };
yield return new object[] { new GenericResolvedArrayParameter("T", string.Empty) };
yield return new object[] { new OptionalGenericParameter("T[]") };
yield return new object[] { new OptionalGenericParameter("T[]", string.Empty) };
yield return new object[] { new GenericParameter("T[]") };
yield return new object[] { new GenericParameter("T[]", string.Empty) };
}
#endregion
}
}

Просмотреть файл

@ -0,0 +1,270 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Unity;
using Unity.Injection;
using Unity.Resolution;
namespace Injection.Parameters
{
[TestClass]
public class ResolutionTests
{
#region Fields
private static ParameterInfo FirstInfo =
typeof(TestClass<List<string>>).GetMethod(nameof(TestClass<List<string>>.FirstTestMethod))
.GetParameters()
.First();
private static ParameterInfo ObjectInfo =
typeof(TestClass<List<string>>).GetMethod(nameof(TestClass<List<string>>.TestMethod))
.GetParameters()
.First();
private static ParameterInfo ArrayInfo =
typeof(TestClass<List<string>>).GetMethod(nameof(TestClass<List<string>>.TestMethod))
.GetParameters()
.Last();
private const string StringConst = "test";
private static List<string> ListConst = new List<string> { StringConst };
private static List<string>[] ListArrayConst = new [] { ListConst };
private static IResolveContext Context = new DictionaryContext
{
{ typeof(object), ListArrayConst },
{ typeof(List<string>), ListConst },
{ typeof(IList<string>), ListConst },
{ typeof(List<string>[]), ListArrayConst },
};
#endregion
#region IResolve
[DataTestMethod]
[DynamicData(nameof(GetIResolvers), DynamicDataSourceType.Method)]
public void IResolveTest(IResolve resolver)
{
// Act
var value = resolver.Resolve(ref Context);
// Validate
Assert.IsNotNull(value);
Assert.AreSame(StringConst, value);
}
#endregion
#region IResolverFactory<Type>
[DataTestMethod]
[DynamicData(nameof(GetResolveFactories), DynamicDataSourceType.Method)]
public void TypeFactoryTest(IResolverFactory<Type> factory)
{
// Act
var resolver = factory.GetResolver<IResolveContext>(FirstInfo.ParameterType);
// Validate
Assert.IsNotNull(resolver);
var value = resolver(ref Context) as List<string>;
Assert.IsNotNull(value);
Assert.AreSame(ListConst, value);
}
[DataTestMethod]
[DynamicData(nameof(GetAllResolveFactories), DynamicDataSourceType.Method)]
public void TypeArrayTest(IResolverFactory<Type> factory)
{
// Act
var resolver = factory.GetResolver<IResolveContext>(ArrayInfo.ParameterType);
// Validate
Assert.IsNotNull(resolver);
var value = resolver(ref Context) as List<string>[];
Assert.IsNotNull(value);
Assert.AreSame(ListArrayConst[0], value[0]);
}
[Ignore] // TODO: Issue #148
[DataTestMethod]
[DynamicData(nameof(GetAllResolveFactories), DynamicDataSourceType.Method)]
public void TypeObjectTest(IResolverFactory<Type> factory)
{
// Act
var resolver = factory.GetResolver<IResolveContext>(ObjectInfo.ParameterType);
// Validate
Assert.IsNotNull(resolver);
var array = resolver(ref Context) as List<string>[];
Assert.IsNotNull(array);
Assert.IsTrue(0 < array.Length);
Assert.AreEqual(ListArrayConst[0], array[0]);
}
#endregion
#region IResolverFactory<ParameterInfo>
[DataTestMethod]
[DynamicData(nameof(GetResolveFactories), DynamicDataSourceType.Method)]
public void InfoFactoryTest(IResolverFactory<ParameterInfo> factory)
{
// Act
var resolver = factory.GetResolver<IResolveContext>(FirstInfo);
// Validate
Assert.IsNotNull(resolver);
var value = resolver(ref Context) as List<string>;
Assert.IsNotNull(value);
Assert.AreSame(ListConst, value);
}
[DataTestMethod]
[DynamicData(nameof(GetAllResolveFactories), DynamicDataSourceType.Method)]
public void InfoArrayTest(IResolverFactory<ParameterInfo> factory)
{
// Act
var resolver = factory.GetResolver<IResolveContext>(ArrayInfo);
// Validate
Assert.IsNotNull(resolver);
var value = resolver(ref Context) as List<string>[];
Assert.IsNotNull(value);
Assert.AreSame(ListArrayConst[0], value[0]);
}
[Ignore] // TODO: Issue #148
[DataTestMethod]
[DynamicData(nameof(GetAllResolveFactories), DynamicDataSourceType.Method)]
public void InfoObjectTest(IResolverFactory<ParameterInfo> factory)
{
// Act
var resolver = factory.GetResolver<IResolveContext>(ObjectInfo);
// Validate
Assert.IsNotNull(resolver);
var value = resolver(ref Context) as List<string>[];
Assert.IsNotNull(value);
Assert.AreSame(ListArrayConst[0], value[0]);
}
#endregion
#region Test Data
public static IEnumerable<object[]> GetIResolvers()
{
yield return new object[] { new InjectionParameter(StringConst) };
yield return new object[] { new InjectionParameter(typeof(string), StringConst) };
}
public static IEnumerable<object[]> GetResolveFactories()
{
yield return new object[] { new ResolvedParameter() };
yield return new object[] { new ResolvedParameter(typeof(List<string>)) };
yield return new object[] { new ResolvedParameter<List<string>>() };
yield return new object[] { new ResolvedParameter(string.Empty) };
yield return new object[] { new ResolvedParameter(typeof(List<string>), string.Empty) };
yield return new object[] { new ResolvedParameter<List<string>>(string.Empty) };
yield return new object[] { new OptionalParameter() };
yield return new object[] { new OptionalParameter(typeof(List<string>)) };
yield return new object[] { new OptionalParameter<List<string>>() };
yield return new object[] { new OptionalParameter(string.Empty) };
yield return new object[] { new OptionalParameter(typeof(List<string>), string.Empty) };
yield return new object[] { new OptionalParameter<List<string>>(string.Empty) };
yield return new object[] { new GenericParameter("T") };
yield return new object[] { new GenericParameter("T", string.Empty) };
yield return new object[] { new OptionalGenericParameter("T") };
yield return new object[] { new OptionalGenericParameter("T", string.Empty) };
}
public static IEnumerable<object[]> GetAllResolveFactories()
{
yield return new object[] { new ResolvedArrayParameter(typeof(List<string>), ListConst, // Constant
new InjectionParameter(ListConst), // IResolve
// TODO: typeof(IList<string>), // Type
new ResolvedParameter(typeof(List<string>))) }; // Factory
yield return new object[] { new GenericResolvedArrayParameter("T", ListConst, // Constant
new InjectionParameter(ListConst), // IResolve
typeof(IList<string>), // Type
new ResolvedParameter(typeof(List<string>))) }; // Factory
yield return new object[] { new ResolvedArrayParameter(typeof(List<string>), typeof(List<string>), ListConst,
new ResolvedParameter(typeof(List<string>))) };
yield return new object[] { new ResolvedParameter() };
yield return new object[] { new ResolvedParameter(typeof(List<string>[])) };
yield return new object[] { new ResolvedParameter<List<string>[]>() };
yield return new object[] { new ResolvedParameter(string.Empty) };
yield return new object[] { new ResolvedParameter(typeof(List<string>[]), string.Empty) };
yield return new object[] { new ResolvedParameter<List<string>[]>(string.Empty) };
yield return new object[] { new OptionalParameter() };
yield return new object[] { new OptionalParameter(typeof(List<string>[])) };
yield return new object[] { new OptionalParameter<List<string>[]>() };
yield return new object[] { new OptionalParameter(string.Empty) };
yield return new object[] { new OptionalParameter(typeof(List<string>[]), string.Empty) };
yield return new object[] { new OptionalParameter<List<string>[]>(string.Empty) };
yield return new object[] { new GenericParameter("T[]") };
yield return new object[] { new GenericParameter("T[]", string.Empty) };
yield return new object[] { new OptionalGenericParameter("T[]") };
yield return new object[] { new OptionalGenericParameter("T[]", string.Empty) };
}
public class DictionaryContext : Dictionary<Type, object>, IResolveContext
{
public IUnityContainer Container => throw new NotImplementedException();
public Type Type => throw new NotImplementedException();
public string Name => throw new NotImplementedException();
public void Clear(Type type, string name, Type policyInterface) => throw new NotImplementedException();
public object Get(Type type, Type policyInterface) => throw new NotImplementedException();
public object Get(Type type, string name, Type policyInterface) => throw new NotImplementedException();
public object Resolve(Type type, string name)
{
return this[type];
}
public void Set(Type type, Type policyInterface, object policy) => throw new NotImplementedException();
public void Set(Type type, string name, Type policyInterface, object policy) => throw new NotImplementedException();
}
public class TestClass<T>
{
public void FirstTestMethod(T first) => throw new NotImplementedException();
public void TestMethod(object second, T[] last) => throw new NotImplementedException();
}
#endregion
}
}

Просмотреть файл

@ -0,0 +1,228 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Unity;
using Unity.Exceptions;
using Unity.Injection;
using Unity.Resolution;
using static Injection.Parameters.ResolutionTests;
namespace Injection.Parameters
{
[TestClass]
public class ValidationTests
{
#region Fields
private const string DefaultValue = "default";
public void TestMethod(string first, string last = DefaultValue) => throw new NotImplementedException();
private static ParameterInfo NoDefaultInfo =
typeof(ValidationTests).GetMethod(nameof(TestMethod))
.GetParameters()
.First();
private static ParameterInfo DefaultInfo =
typeof(ValidationTests).GetMethod(nameof(TestMethod))
.GetParameters()
.Last();
#endregion
[TestMethod]
[ExpectedException(typeof(ArgumentNullException))]
public void InjectionParameterCtorTest()
{
new InjectionParameter(null);
}
[TestMethod]
[ExpectedException(typeof(ArgumentNullException))]
public void GenericParameterCtorTest()
{
new GenericParameter(null);
}
// Issue https://github.com/unitycontainer/abstractions/issues/146
[Ignore]
[TestMethod]
public void ResolvedArrayParameterCtorTest()
{
new ResolvedArrayParameter(null, typeof(string));
}
[Ignore]
[TestMethod]
[ExpectedException(typeof(ArgumentNullException))]
public void ResolvedArrayParameterElementTest()
{
new ResolvedArrayParameter(typeof(string), null);
}
[DataTestMethod]
[DynamicData(nameof(GetSupportedParameters), DynamicDataSourceType.Method)]
public void ToStringTest(ParameterValue parameter)
{
var name = parameter.GetType().Name;
Assert.IsTrue(parameter.ToString().StartsWith(name));
}
[Ignore] // TODO: validate
[DataTestMethod]
[ExpectedException(typeof(ArgumentNullException))]
[DynamicData(nameof(GetSupportedParameters), DynamicDataSourceType.Method)]
public void EqualsValidationTest(ParameterValue parameter)
{
Assert.IsTrue(parameter.Equals(null));
}
#region Exceptions
[DataTestMethod]
[DynamicData(nameof(GetOptionalParametersData), DynamicDataSourceType.Method)]
public void OptionalExceptionTest(IResolverFactory<Type> factory)
{
var context = new DictionaryContext() as IResolveContext;
var resolver = factory.GetResolver<IResolveContext>(typeof(string));
// Validate
Assert.IsNotNull(resolver);
Assert.IsNull(resolver(ref context));
}
[DataTestMethod]
[ExpectedException(typeof(CircularDependencyException))]
[DynamicData(nameof(GetOptionalParametersData), DynamicDataSourceType.Method)]
public void OptionalCircularExceptionTest(IResolverFactory<Type> factory)
{
var context = new CircularExceptionContect() as IResolveContext;
var resolver = factory.GetResolver<IResolveContext>(typeof(string));
// Validate
Assert.IsNotNull(resolver);
_ = resolver(ref context);
}
[DataTestMethod]
[ExpectedException(typeof(CircularDependencyException))]
[DynamicData(nameof(GetOptionalParametersData), DynamicDataSourceType.Method)]
public void OptionalCircularExceptionInfoTest(IResolverFactory<ParameterInfo> factory)
{
var context = new CircularExceptionContect() as IResolveContext;
var resolver = factory.GetResolver<IResolveContext>(NoDefaultInfo);
// Validate
Assert.IsNotNull(resolver);
_ = resolver(ref context);
}
#endregion
#region Default Value
[DataTestMethod]
[DynamicData(nameof(Getissues147Data), DynamicDataSourceType.Method)]
// TODO: issues 147: [DynamicData(nameof(GetOptionalParametersData), DynamicDataSourceType.Method)]
public void OptionalDefaultTest(IResolverFactory<ParameterInfo> factory)
{
var context = new DictionaryContext() as IResolveContext;
var resolver = factory.GetResolver<IResolveContext>(DefaultInfo);
// Validate
Assert.IsNotNull(resolver);
var value = resolver(ref context);
Assert.AreEqual(DefaultValue, value);
}
[DataTestMethod]
[DynamicData(nameof(Getissues147Data), DynamicDataSourceType.Method)]
// TODO: issues 147: [DynamicData(nameof(GetOptionalParametersData), DynamicDataSourceType.Method)]
public void OptionalNoDefaultTest(IResolverFactory<ParameterInfo> factory)
{
var context = new DictionaryContext() as IResolveContext;
var resolver = factory.GetResolver<IResolveContext>(NoDefaultInfo);
// Validate
Assert.IsNotNull(resolver);
Assert.IsNull(resolver(ref context));
}
// TODO: issues 147:
public static IEnumerable<object[]> Getissues147Data()
{
yield return new object[] { new OptionalParameter() };
yield return new object[] { new OptionalParameter(typeof(string)) };
yield return new object[] { new OptionalParameter(string.Empty) };
yield return new object[] { new OptionalParameter(typeof(string), string.Empty) };
}
#endregion
#region Test Data
public static IEnumerable<object[]> GetSupportedParameters()
{
yield return new object[] { new InjectionParameter(string.Empty) };
yield return new object[] { new InjectionParameter(typeof(string), null) };
yield return new object[] { new OptionalParameter() };
yield return new object[] { new ResolvedParameter() };
yield return new object[] { new ResolvedArrayParameter(typeof(string)) };
yield return new object[] { new GenericParameter("T[]") };
yield return new object[] { new OptionalGenericParameter("T") };
yield return new object[] { new OptionalGenericParameter("T", string.Empty) };
yield return new object[] { new GenericResolvedArrayParameter("T[]") };
}
public static IEnumerable<object[]> GetOptionalParametersData()
{
yield return new object[] { new OptionalGenericParameter("T") };
yield return new object[] { new OptionalGenericParameter("T", string.Empty) };
yield return new object[] { new OptionalParameter() };
yield return new object[] { new OptionalParameter(typeof(string)) };
yield return new object[] { new OptionalParameter(string.Empty) };
yield return new object[] { new OptionalParameter(typeof(string), string.Empty) };
}
public class CircularExceptionContect : IResolveContext
{
public IUnityContainer Container => throw new NotImplementedException();
public Type Type => throw new NotImplementedException();
public string Name => throw new NotImplementedException();
public void Clear(Type type, string name, Type policyInterface) => throw new NotImplementedException();
public object Get(Type type, Type policyInterface) => throw new NotImplementedException();
public object Get(Type type, string name, Type policyInterface) => throw new NotImplementedException();
public object Resolve(Type type, string name)
{
throw new CircularDependencyException(type, name);
}
public void Set(Type type, Type policyInterface, object policy) => throw new NotImplementedException();
public void Set(Type type, string name, Type policyInterface, object policy) => throw new NotImplementedException();
}
#endregion
}
}

Просмотреть файл

@ -0,0 +1,115 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Unity.Policy.Tests;
using Unity.Resolution;
namespace Resolution.Overrides
{
[TestClass]
public class MemberEqualityTests
{
#region Fields
public static object OverrideValue { get; } = new object();
public static FieldInfo FieldInfo = typeof(PolicySet).GetField(nameof(PolicySet.NameField));
public static PropertyInfo PropertyInfo = typeof(PolicySet).GetProperty(nameof(PolicySet.NameProperty));
public static NamedType NamedType = new NamedType { Type = typeof(object), Name = string.Empty };
public static ParameterInfo ParameterInfo = typeof(PolicySet).GetConstructor(new Type[] { typeof(string) })
.GetParameters()
.First();
#endregion
[TestMethod]
public void EqualsNull()
{
// Field
var field = new FieldOverride(string.Empty, OverrideValue);
Assert.IsFalse(field.Equals((object)null));
Assert.IsFalse(field.Equals((FieldInfo)null));
// Property
var property = new PropertyOverride(string.Empty, OverrideValue);
Assert.IsFalse(property.Equals((object)null));
Assert.IsFalse(property.Equals((PropertyInfo)null));
// Parameter
var parameter = new ParameterOverride(string.Empty, OverrideValue);
Assert.IsFalse(parameter.Equals((object)null));
Assert.IsFalse(parameter.Equals((ParameterInfo)null));
// Dependency
Assert.IsFalse(new DependencyOverride(typeof(object), OverrideValue).Equals(null));
}
[DataTestMethod]
[DynamicData(nameof(GetTestResolvers), DynamicDataSourceType.Method)]
public void EqualsTest(ResolverOverride instance, object other, bool result)
{
// Validate
Assert.AreEqual(result, instance.Equals(other));
}
#region Test Data
public static IEnumerable<object[]> GetTestResolvers()
{
yield return new object[] { new FieldOverride(string.Empty, OverrideValue), OverrideValue, false };
yield return new object[] { new FieldOverride(string.Empty, OverrideValue), FieldInfo, false };
yield return new object[] { new FieldOverride(null, OverrideValue), FieldInfo, true }; // TODO: Issue #156
yield return new object[] { new FieldOverride(nameof(PolicySet.NameField), OverrideValue), FieldInfo, true };
yield return new object[] { new FieldOverride(nameof(PolicySet.NameField), OverrideValue).OnType<FieldInfo>(), FieldInfo, false };
yield return new object[] { new FieldOverride(nameof(PolicySet.NameField), OverrideValue).OnType<PolicySet>(), FieldInfo, true };
yield return new object[] { new FieldOverride(nameof(PolicySet.NameField), OverrideValue).OnType<PolicySet>(),
new FieldOverride(nameof(PolicySet.NameField), OverrideValue).OnType<PolicySet>(), true };
yield return new object[] { new PropertyOverride(string.Empty, OverrideValue), OverrideValue, false };
yield return new object[] { new PropertyOverride(null, OverrideValue), PropertyInfo, true }; // TODO: Issue #156
yield return new object[] { new PropertyOverride(string.Empty, OverrideValue), PropertyInfo, false };
yield return new object[] { new PropertyOverride(nameof(PolicySet.NameProperty), OverrideValue), PropertyInfo, true };
yield return new object[] { new PropertyOverride(nameof(PolicySet.NameProperty), OverrideValue).OnType<FieldInfo>(), PropertyInfo, false };
yield return new object[] { new PropertyOverride(nameof(PolicySet.NameProperty), OverrideValue).OnType<PolicySet>(),
new PropertyOverride(nameof(PolicySet.NameProperty), OverrideValue).OnType<PolicySet>(), true };
yield return new object[] { new DependencyOverride(typeof(object), OverrideValue), OverrideValue, false };
yield return new object[] { new DependencyOverride(string.Empty, OverrideValue), NamedType, false };
yield return new object[] { new DependencyOverride(typeof(object), string.Empty, OverrideValue), NamedType, true };
yield return new object[] { new DependencyOverride(typeof(object), typeof(object), string.Empty, OverrideValue), NamedType, true };
yield return new object[] { new DependencyOverride(typeof(object), typeof(object), string.Empty, OverrideValue),
new DependencyOverride(typeof(object), typeof(object), string.Empty, OverrideValue), true };
yield return new object[] { new DependencyOverride(typeof(object), typeof(string), string.Empty, OverrideValue),
new DependencyOverride(typeof(object), typeof(object), string.Empty, OverrideValue), false };
yield return new object[] { new DependencyOverride(typeof(object), typeof(object), string.Empty, OverrideValue), // TODO: Issue #157
new DependencyOverride(typeof(string), typeof(object), string.Empty, OverrideValue), true };
yield return new object[] { new DependencyOverride<object>(OverrideValue), new NamedType { Type = typeof(object) }, true }; // TODO: Issue #158
yield return new object[] { new ParameterOverride(string.Empty, OverrideValue), OverrideValue, false };
yield return new object[] { new ParameterOverride(typeof(string), OverrideValue), OverrideValue, false };
yield return new object[] { new ParameterOverride(typeof(string), string.Empty, OverrideValue), OverrideValue, false };
yield return new object[] { new ParameterOverride((string)null, OverrideValue), ParameterInfo, true };
yield return new object[] { new ParameterOverride(string.Empty, OverrideValue), ParameterInfo, false };
yield return new object[] { new ParameterOverride(ParameterInfo.Name, OverrideValue), ParameterInfo, true };
yield return new object[] { new ParameterOverride(ParameterInfo.Name, OverrideValue).OnType<PolicySet>(), ParameterInfo, true };
yield return new object[] { new ParameterOverride(typeof(string), OverrideValue), ParameterInfo, true };
yield return new object[] { new ParameterOverride(typeof(string), ParameterInfo.Name, OverrideValue), ParameterInfo, true };
yield return new object[] { new ParameterOverride(ParameterInfo.Name, OverrideValue),
new ParameterOverride(ParameterInfo.Name, OverrideValue), true };
yield return new object[] { new ParameterOverride(typeof(string), OverrideValue),
new ParameterOverride(typeof(string), OverrideValue), true };
yield return new object[] { new ParameterOverride(typeof(string), ParameterInfo.Name, OverrideValue),
new ParameterOverride(typeof(string), ParameterInfo.Name, OverrideValue), true };
yield return new object[] { new ParameterOverride(typeof(object), ParameterInfo.Name, OverrideValue),
new ParameterOverride(typeof(string), ParameterInfo.Name, OverrideValue), false };
yield return new object[] { new ParameterOverride(typeof(string), ParameterInfo.Name, OverrideValue),
new ParameterOverride(typeof(string), string.Empty, OverrideValue), false };
yield return new object[] { new ParameterOverride(typeof(string), ParameterInfo.Name, OverrideValue).OnType<PolicySet>(),
new ParameterOverride(typeof(string), ParameterInfo.Name, OverrideValue).OnType<PolicySet>(), true };
}
#endregion
}
}

Просмотреть файл

@ -0,0 +1,216 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;
using Unity;
using Unity.Resolution;
namespace Resolution.Overrides
{
[TestClass]
public class ResolverOverrideTests
{
#region Fields
public static object OverrideValue { get; } = new object();
public static object ValueOverride { get; } = new TestResolver();
public static object FactoryOverride { get; } = new TestResolverFactory();
#endregion
#region Resolver
[DataTestMethod]
[DynamicData(nameof(GetAllResolvers), DynamicDataSourceType.Method)]
public virtual void ResolveTest(ResolverOverride instance)
{
// Arrange
var context = new TestContext() as IResolveContext;
// Act
var resolver = instance.GetResolver<IResolveContext>(typeof(ResolverOverrideTests));
Assert.IsNotNull(resolver);
// Validate
var value = resolver(ref context);
Assert.AreSame(OverrideValue, value);
}
[DataTestMethod]
[DynamicData(nameof(GetOverriddenResolvers), DynamicDataSourceType.Method)]
public virtual void ResolveWithOverrideTest(ResolverOverride instance)
{
var context = new TestContext() as IResolveContext;
var resolver = instance.GetResolver<IResolveContext>(typeof(ResolverOverrideTests));
Assert.IsNotNull(resolver);
var value = resolver(ref context);
Assert.AreSame(context, value);
}
#endregion
#region Object
[DataTestMethod]
[DynamicData(nameof(GetAllResolvers), DynamicDataSourceType.Method)]
public void GetHashCodeTest(ResolverOverride instance)
{
// Produces same result every time
var typed = instance.GetHashCode();
Assert.AreEqual(typed, instance.GetHashCode());
var once = instance.OnType<ResolverOverrideTests>().GetHashCode();
Assert.AreEqual(once, instance.GetHashCode());
var twice = instance.OnType(typeof(object)).GetHashCode();
Assert.AreEqual(twice, instance.GetHashCode());
// But different value
Assert.AreNotEqual(typed, once);
Assert.AreNotEqual(typed, twice);
Assert.AreNotEqual(twice, once);
}
[DataTestMethod]
[DynamicData(nameof(GetAllResolvers), DynamicDataSourceType.Method)]
public void EqualsTest(ResolverOverride resolver)
{
// Act
var result = resolver.Equals((object)resolver);
// Validate
Assert.IsTrue(result);
}
[DataTestMethod]
[DynamicData(nameof(GetAllResolvers), DynamicDataSourceType.Method)]
public void EqualsWrongTest(ResolverOverride resolver)
{
// Validate
Assert.IsFalse(resolver.Equals(this));
}
[DataTestMethod]
[DynamicData(nameof(GetAllResolvers), DynamicDataSourceType.Method)]
public void EqualsOperatorTest(ResolverOverride resolver)
{
// Validate
Assert.IsFalse(null == resolver);
Assert.IsFalse(resolver == null);
Assert.IsTrue(null != resolver);
Assert.IsTrue(resolver != null);
}
#endregion
#region Test Data
public static IEnumerable<object[]> GetAllResolvers()
{
yield return new object[] { new FieldOverride(string.Empty, OverrideValue) };
yield return new object[] { new PropertyOverride(string.Empty, OverrideValue) };
yield return new object[] { new DependencyOverride( typeof(object), OverrideValue) };
yield return new object[] { new DependencyOverride( string.Empty, OverrideValue) };
yield return new object[] { new DependencyOverride( typeof(object), string.Empty, OverrideValue) };
yield return new object[] { new DependencyOverride(typeof(ResolverOverride), typeof(object), string.Empty, OverrideValue) };
yield return new object[] { new ParameterOverride( string.Empty, OverrideValue) };
yield return new object[] { new ParameterOverride(typeof(object), OverrideValue) };
yield return new object[] { new ParameterOverride(typeof(object), string.Empty, OverrideValue) };
}
public static IEnumerable<object[]> GetOverriddenResolvers()
{
yield return new object[] { new FieldOverride(string.Empty, ValueOverride) };
yield return new object[] { new FieldOverride(string.Empty, FactoryOverride) };
yield return new object[] { new PropertyOverride(string.Empty, ValueOverride) };
yield return new object[] { new PropertyOverride(string.Empty, FactoryOverride) };
yield return new object[] { new DependencyOverride(typeof(object), ValueOverride) };
yield return new object[] { new DependencyOverride(string.Empty, ValueOverride) };
yield return new object[] { new DependencyOverride(typeof(object), FactoryOverride) };
yield return new object[] { new DependencyOverride(string.Empty, FactoryOverride) };
yield return new object[] { new DependencyOverride(typeof(object), string.Empty, ValueOverride) };
yield return new object[] { new DependencyOverride(typeof(object), string.Empty, FactoryOverride) };
yield return new object[] { new DependencyOverride(typeof(ResolverOverride), typeof(object), string.Empty, ValueOverride) };
yield return new object[] { new DependencyOverride(typeof(ResolverOverride), typeof(object), string.Empty, FactoryOverride) };
yield return new object[] { new ParameterOverride(string.Empty, ValueOverride) };
yield return new object[] { new ParameterOverride(string.Empty, FactoryOverride) };
yield return new object[] { new ParameterOverride(typeof(object), ValueOverride) };
yield return new object[] { new ParameterOverride(typeof(object), FactoryOverride) };
yield return new object[] { new ParameterOverride(typeof(object), string.Empty, ValueOverride) };
yield return new object[] { new ParameterOverride(typeof(object), string.Empty, FactoryOverride) };
}
public class TestResolverFactory : IResolverFactory<Type>
{
public ResolveDelegate<TContext> GetResolver<TContext>(Type info) where TContext : IResolveContext
{
return (ref TContext context) => context;
}
}
public class TestResolver : IResolve
{
public object Resolve<TContext>(ref TContext context)
where TContext : IResolveContext
{
return context;
}
}
public class TestContext : IResolveContext
{
public IUnityContainer Container => throw new NotImplementedException();
public Type Type => throw new NotImplementedException();
public string Name => throw new NotImplementedException();
public void Clear(Type type, string name, Type policyInterface)
{
throw new NotImplementedException();
}
public object Get(Type type, Type policyInterface)
{
throw new NotImplementedException();
}
public object Get(Type type, string name, Type policyInterface)
{
throw new NotImplementedException();
}
public object Resolve(Type type, string name)
{
throw new NotImplementedException();
}
public void Set(Type type, Type policyInterface, object policy)
{
throw new NotImplementedException();
}
public void Set(Type type, string name, Type policyInterface, object policy)
{
throw new NotImplementedException();
}
}
#endregion
}
}

Просмотреть файл

@ -0,0 +1,48 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Reflection;
using Unity;
using Unity.Lifetime;
namespace Lifetime.Extensions
{
[TestClass]
public class RegistrationTests
{
[TestMethod]
public void FactoryLifetimeTest()
{
var members = typeof(FactoryLifetime).GetProperties(BindingFlags.Public | BindingFlags.Static);
foreach (var property in members)
{
var manager = property.GetValue(null);
Assert.IsInstanceOfType(manager, typeof(IFactoryLifetimeManager));
}
}
[TestMethod]
public void InstanceLifetimeTest()
{
var members = typeof(InstanceLifetime).GetProperties(BindingFlags.Public | BindingFlags.Static);
foreach (var property in members)
{
var manager = property.GetValue(null);
Assert.IsInstanceOfType(manager, typeof(IInstanceLifetimeManager));
}
}
[TestMethod]
public void TypeLifetimeTest()
{
var members = typeof(TypeLifetime).GetProperties(BindingFlags.Public | BindingFlags.Static);
foreach (var property in members)
{
var manager = property.GetValue(null);
Assert.IsInstanceOfType(manager, typeof(ITypeLifetimeManager));
}
}
}
}

Просмотреть файл

@ -0,0 +1,36 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using Unity.Lifetime;
namespace Lifetime.Managers
{
[TestClass]
public class ContainerControlled : Synchronized
{
protected override LifetimeManager GetManager() => new ContainerControlledLifetimeManager();
[TestMethod]
public override void TryGetSetOtherContainerTest()
{
base.TryGetSetOtherContainerTest();
// Validate
Assert.AreSame(TestObject, TestManager.TryGetValue(OtherContainer));
Assert.AreSame(TestObject, TestManager.GetValue(OtherContainer));
}
[TestMethod]
[ExpectedException(typeof(InvalidOperationException))]
public override void SetValueTwiceTest()
{
base.SetValueTwiceTest();
}
[TestMethod]
[ExpectedException(typeof(InvalidOperationException))]
public override void SetDifferentValuesTwiceTest()
{
base.SetDifferentValuesTwiceTest();
}
}
}

Просмотреть файл

@ -0,0 +1,157 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Threading;
using Unity.Lifetime;
namespace Lifetime.Managers
{
[TestClass]
public class ContainerTransient : LifetimeManagerTests
{
protected override LifetimeManager GetManager() => new ContainerControlledTransientManager();
[TestMethod]
public override void InUseTest()
{
Assert.IsFalse(TestManager.InUse);
TestManager.InUse = true;
Assert.IsFalse(TestManager.InUse);
}
[TestMethod]
public override void TryGetValueTest()
{
// Validate
Assert.AreSame(LifetimeManager.NoValue, TestManager.TryGetValue(LifetimeContainer));
// Act
TestManager.SetValue(TestObject, LifetimeContainer);
// Validate
Assert.AreSame(LifetimeManager.NoValue, TestManager.TryGetValue(LifetimeContainer));
}
[TestMethod]
public override void GetValueTest()
{
// Validate
Assert.AreSame(LifetimeManager.NoValue, TestManager.GetValue(LifetimeContainer));
// Act
TestManager.SetValue(TestObject, LifetimeContainer);
// Validate
Assert.AreSame(LifetimeManager.NoValue, TestManager.GetValue(LifetimeContainer));
}
[TestMethod]
public override void TryGetSetNoContainerTest()
{
// Validate
Assert.AreSame(LifetimeManager.NoValue, TestManager.TryGetValue());
Assert.AreSame(LifetimeManager.NoValue, TestManager.GetValue());
// Act
TestManager.SetValue(TestObject);
// Validate
Assert.AreSame(LifetimeManager.NoValue, TestManager.TryGetValue());
Assert.AreSame(LifetimeManager.NoValue, TestManager.GetValue());
}
[TestMethod]
public override void TryGetSetOtherContainerTest()
{
// Validate
Assert.AreSame(LifetimeManager.NoValue, TestManager.TryGetValue(LifetimeContainer));
Assert.AreSame(LifetimeManager.NoValue, TestManager.GetValue(LifetimeContainer));
// Act
TestManager.SetValue(TestObject, LifetimeContainer);
// Validate
Assert.AreSame(LifetimeManager.NoValue, TestManager.TryGetValue(LifetimeContainer));
Assert.AreSame(LifetimeManager.NoValue, TestManager.GetValue(LifetimeContainer));
// Validate
Assert.AreSame(LifetimeManager.NoValue, TestManager.TryGetValue(OtherContainer));
Assert.AreSame(LifetimeManager.NoValue, TestManager.GetValue(OtherContainer));
// Act
TestManager.SetValue(TestObject, OtherContainer);
// Validate
Assert.AreSame(LifetimeManager.NoValue, TestManager.TryGetValue(LifetimeContainer));
Assert.AreSame(LifetimeManager.NoValue, TestManager.GetValue(LifetimeContainer));
}
[TestMethod]
public override void ValuesFromDifferentThreads()
{
TestManager.SetValue(TestObject, LifetimeContainer);
object value1 = null;
object value2 = null;
object value3 = null;
object value4 = null;
Thread thread1 = new Thread(delegate ()
{
value1 = TestManager.TryGetValue(LifetimeContainer);
value2 = TestManager.GetValue(LifetimeContainer);
})
{ Name = "1" };
Thread thread2 = new Thread(delegate ()
{
value3 = TestManager.TryGetValue(LifetimeContainer);
value4 = TestManager.GetValue(LifetimeContainer);
})
{ Name = "2" };
thread1.Start();
thread2.Start();
thread2.Join();
thread1.Join();
Assert.AreSame(LifetimeManager.NoValue, TestManager.TryGetValue(LifetimeContainer));
Assert.AreSame(LifetimeManager.NoValue, TestManager.GetValue(LifetimeContainer));
Assert.AreSame(LifetimeManager.NoValue, value1);
Assert.AreSame(LifetimeManager.NoValue, value2);
Assert.AreSame(LifetimeManager.NoValue, value3);
Assert.AreSame(LifetimeManager.NoValue, value4);
}
[TestMethod]
public virtual void IsDisposedTest()
{
// Arrange
var disposable = new FakeDisposable();
Assert.IsNotNull(disposable);
// Act
TestManager.SetValue(disposable);
TestManager.SetValue(disposable, LifetimeContainer);
Assert.AreEqual(1, LifetimeContainer.Count);
}
public class FakeDisposable : IDisposable
{
public bool Disposed { get; private set; }
public void Dispose()
{
Disposed = true;
}
}
}
}

Просмотреть файл

@ -0,0 +1,54 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using Unity.Lifetime;
namespace Lifetime.Managers
{
[TestClass]
public class ExternallyControlled : Synchronized
{
protected override LifetimeManager GetManager() => new ExternallyControlledLifetimeManager();
[TestMethod]
public override void TryGetSetOtherContainerTest()
{
base.TryGetSetOtherContainerTest();
// Validate
Assert.AreSame(TestObject, TestManager.TryGetValue(OtherContainer));
Assert.AreSame(TestObject, TestManager.GetValue(OtherContainer));
}
[TestMethod]
public override void SetValueTwiceTest()
{
base.SetValueTwiceTest();
}
[TestMethod]
public override void SetDifferentValuesTwiceTest()
{
base.SetDifferentValuesTwiceTest();
}
[TestMethod]
public override void IsDisposedTest()
{
// Arrange
var manager = TestManager as IDisposable;
var disposable = TestObject as FakeDisposable;
if (null == manager) return;
TestManager.SetValue(TestObject, LifetimeContainer);
Assert.IsNotNull(disposable);
Assert.IsNotNull(manager);
Assert.IsFalse(disposable.Disposed);
// Act
manager.Dispose();
Assert.IsFalse(disposable.Disposed);
}
}
}

Просмотреть файл

@ -0,0 +1,36 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using Unity.Lifetime;
namespace Lifetime.Managers
{
[TestClass]
public class GlobalSingleton : Synchronized
{
protected override LifetimeManager GetManager() => new SingletonLifetimeManager();
[TestMethod]
public override void TryGetSetOtherContainerTest()
{
base.TryGetSetOtherContainerTest();
// Validate
Assert.AreSame(TestObject, TestManager.TryGetValue(OtherContainer));
Assert.AreSame(TestObject, TestManager.GetValue(OtherContainer));
}
[TestMethod]
[ExpectedException(typeof(InvalidOperationException))]
public override void SetValueTwiceTest()
{
base.SetValueTwiceTest();
}
[TestMethod]
[ExpectedException(typeof(InvalidOperationException))]
public override void SetDifferentValuesTwiceTest()
{
base.SetDifferentValuesTwiceTest();
}
}
}

Просмотреть файл

@ -0,0 +1,48 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using Unity.Lifetime;
namespace Lifetime.Managers
{
[TestClass]
public class Hierarchical : Synchronized
{
protected override LifetimeManager GetManager() => new HierarchicalLifetimeManager();
[TestMethod]
[ExpectedException(typeof(ArgumentNullException))]
public override void TryGetSetNoContainerTest()
{
base.TryGetSetNoContainerTest();
}
[TestMethod]
public override void TryGetSetOtherContainerTest()
{
base.TryGetSetOtherContainerTest();
// Validate
Assert.AreSame(LifetimeManager.NoValue, TestManager.TryGetValue(OtherContainer));
Assert.AreSame(LifetimeManager.NoValue, TestManager.GetValue(OtherContainer));
// Act
TestManager.SetValue(TestObject, OtherContainer);
// Validate
Assert.AreSame(TestObject, TestManager.TryGetValue(OtherContainer));
Assert.AreSame(TestObject, TestManager.GetValue(OtherContainer));
}
[TestMethod]
public override void SetValueTwiceTest()
{
base.SetValueTwiceTest();
}
[TestMethod]
public override void SetDifferentValuesTwiceTest()
{
base.SetDifferentValuesTwiceTest();
}
}
}

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше