This commit is contained in:
Родитель
a6789b727c
Коммит
98ad57363b
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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.
|
21
README.md
21
README.md
|
@ -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
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
This package supports .NET Standard 1.0, 2.0, and .NET 6.0
|
|
@ -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'
|
29
package.sln
29
package.sln
|
@ -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<IUnityContainer, Type, string, object></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
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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>
|
Двоичный файл не отображается.
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче