[
  {
    "path": ".gitattributes",
    "content": "###############################################################################\n# Set default behavior to automatically normalize line endings.\n###############################################################################\n* text=auto\n\n###############################################################################\n# Set default behavior for command prompt diff.\n#\n# This is need for earlier builds of msysgit that does not have it on by\n# default for csharp files.\n# Note: This is only used by command line\n###############################################################################\n#*.cs     diff=csharp\n\n###############################################################################\n# Set the merge driver for project and solution files\n#\n# Merging from the command prompt will add diff markers to the files if there\n# are conflicts (Merging from VS is not affected by the settings below, in VS\n# the diff markers are never inserted). Diff markers may cause the following \n# file extensions to fail to load in VS. An alternative would be to treat\n# these files as binary and thus will always conflict and require user\n# intervention with every merge. To do so, just uncomment the entries below\n###############################################################################\n#*.sln       merge=binary\n#*.csproj    merge=binary\n#*.vbproj    merge=binary\n#*.vcxproj   merge=binary\n#*.vcproj    merge=binary\n#*.dbproj    merge=binary\n#*.fsproj    merge=binary\n#*.lsproj    merge=binary\n#*.wixproj   merge=binary\n#*.modelproj merge=binary\n#*.sqlproj   merge=binary\n#*.wwaproj   merge=binary\n\n###############################################################################\n# behavior for image files\n#\n# image files are treated as binary by default.\n###############################################################################\n#*.jpg   binary\n#*.png   binary\n#*.gif   binary\n\n###############################################################################\n# diff behavior for common document formats\n# \n# Convert binary document formats to text before diffing them. This feature\n# is only available from the command line. Turn it on by uncommenting the \n# entries below.\n###############################################################################\n#*.doc   diff=astextplain\n#*.DOC   diff=astextplain\n#*.docx  diff=astextplain\n#*.DOCX  diff=astextplain\n#*.dot   diff=astextplain\n#*.DOT   diff=astextplain\n#*.pdf   diff=astextplain\n#*.PDF   diff=astextplain\n#*.rtf   diff=astextplain\n#*.RTF   diff=astextplain\n"
  },
  {
    "path": ".github/dependabot.yml",
    "content": "version: 2\nenable-beta-ecosystems: true\nupdates:\n  - package-ecosystem: \"github-actions\"\n    directory: \"/\"\n    schedule:\n      interval: \"weekly\"\n"
  },
  {
    "path": ".github/workflows/codeql-analysis.yml",
    "content": "# For most projects, this workflow file will not need changing; you simply need\n# to commit it to your repository.\n#\n# You may wish to alter this file to override the set of languages analyzed,\n# or to provide custom queries or build logic.\n#\n# ******** NOTE ********\n# We have attempted to detect the languages in your repository. Please check\n# the `language` matrix defined below to confirm you have the correct set of\n# supported CodeQL languages.\n#\nname: \"CodeQL\"\n\non:\n  push:\n    branches: [ master, dev ]\n    paths-ignore:\n      - '**.md'\n      - 'docs/**'\n      - 'appveyor*'\n  pull_request:\n    # The branches below must be a subset of the branches above\n    branches: [ master ]\n  schedule:\n    - cron: '0 1 * * 2'\n\njobs:\n  analyze:\n    name: Analyze\n    runs-on: ubuntu-latest\n    permissions:\n      actions: read\n      contents: read\n      security-events: write\n\n    strategy:\n      fail-fast: false\n      matrix:\n        language: [ 'csharp' ]\n        # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]\n        # Learn more about CodeQL language support at https://git.io/codeql-language-support\n\n    steps:\n    - name: Checkout repository\n      uses: actions/checkout@v5\n      \n    - uses: actions/setup-dotnet@v5\n      with:\n        dotnet-version: |\n          8.0.x\n\n    # Initializes the CodeQL tools for scanning.\n    - name: Initialize CodeQL\n      uses: github/codeql-action/init@v4\n      with:\n        languages: ${{ matrix.language }}\n        # If you wish to specify custom queries, you can do so here or in a config file.\n        # By default, queries listed here will override any specified in a config file.\n        # Prefix the list here with \"+\" to use these queries and those in the config file.\n        # queries: ./path/to/local/query, your-org/your-repo/queries@main\n\n    # Autobuild attempts to build any compiled languages  (C/C++, C#, or Java).\n    # If this step fails, then you should remove it and run the build manually (see below)\n    - name: Autobuild\n      uses: github/codeql-action/autobuild@v4\n\n    # ℹ️ Command-line programs to run using the OS shell.\n    # 📚 https://git.io/JvXDl\n\n    # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines\n    #    and modify them (or add more) to build your code if your project\n    #    uses a compiled language\n\n    #- run: |\n    #   make bootstrap\n    #   make release\n\n    - name: Perform CodeQL Analysis\n      uses: github/codeql-action/analyze@v4\n"
  },
  {
    "path": ".github/workflows/docs.yml",
    "content": "name: Deploy to GitHub Pages\n\non:\n  push:\n    branches: [ master ]\n    paths:\n      - 'docs/**'\n      - '.github/workflows/docs.yml'\n\n  workflow_dispatch:\n\ndefaults:\n  run:\n    working-directory: docs\n\njobs:\n  deploy:\n    name: Deploy to GitHub Pages\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v5\n      - uses: actions/setup-node@v6\n        with:\n          node-version: 20\n          cache: yarn\n          cache-dependency-path: ./docs/yarn.lock\n\n      - name: Install dependencies\n        run: yarn install --frozen-lockfile\n      - name: Build website\n        run: yarn build\n\n      - name: Deploy to GitHub Pages\n        uses: peaceiris/actions-gh-pages@v4\n        with:\n          github_token: ${{ secrets.GITHUB_TOKEN }}\n          publish_dir: ./docs/build"
  },
  {
    "path": ".github/workflows/linux-macOS-CI.yml",
    "content": "name: Build on Linux and macOS\non:\n  push:\n    branches: [ master, dev ]\n    paths-ignore:\n      - '**.md'\n      - 'docs/**'\n      - 'appveyor*'\n  pull_request:\n    types: [opened, synchronize, reopened]\n\nenv:\n  DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true\n  DOTNET_CLI_TELEMETRY_OPTOUT: true\n\njobs:\n  build-test:\n    name: Build & test\n    runs-on: ${{ matrix.os }}\n    strategy:\n      matrix:\n        os: [ macos-latest, ubuntu-latest ]\n    steps:\n      - uses: actions/checkout@v5\n      - uses: actions/setup-dotnet@v5\n        with:\n          dotnet-version: | \n            8.0.x\n            9.0.x\n            10.0.x\n      - name: Restore\n        run: dotnet restore\n      - name: Test\n        run: |\n          dotnet test test/stashbox.tests.csproj -c Release -f net8.0 --no-restore\n          dotnet test test/stashbox.tests.csproj -c Release -f net9.0 --no-restore\n          dotnet test test/stashbox.tests.csproj -c Release -f net10.0 --no-restore"
  },
  {
    "path": ".github/workflows/sonar-analysis.yml",
    "content": "name: SonarCloud Analysis\non:\n  push:\n    branches: [ master, dev ]\n    paths-ignore:\n      - '**.md'\n      - 'docs/**'\n      - 'appveyor*'\n  pull_request:\n    types: [opened, synchronize, reopened]\n\nenv:\n  DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true\n  DOTNET_CLI_TELEMETRY_OPTOUT: true\n\njobs:\n  analysis:\n    name: Run analysis & code coverage\n    runs-on: windows-latest\n    steps:\n      - name: Set up JDK 17\n        uses: actions/setup-java@v5\n        with:\n          java-version: 17\n          distribution: temurin\n      - uses: actions/checkout@v5\n        with:\n          fetch-depth: 0\n      - uses: actions/setup-dotnet@v5\n        with:\n          dotnet-version: |\n            8.0.x\n      - name: Cache SonarCloud packages\n        uses: actions/cache@v5\n        with:\n          path: ~\\sonar\\cache\n          key: ${{ runner.os }}-sonar\n          restore-keys: ${{ runner.os }}-sonar\n      - name: Cache SonarCloud scanner\n        id: cache-sonar-scanner\n        uses: actions/cache@v5\n        with:\n          path: .\\.sonar\\scanner\n          key: ${{ runner.os }}-sonar-scanner\n          restore-keys: ${{ runner.os }}-sonar-scanner\n      - name: Install SonarCloud scanner\n        if: steps.cache-sonar-scanner.outputs.cache-hit != 'true'\n        shell: powershell\n        run: |\n          New-Item -Path .\\.sonar\\scanner -ItemType Directory\n          dotnet tool update dotnet-sonarscanner --tool-path .\\.sonar\\scanner\n      - name: Build and analyze\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n          SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}\n        shell: powershell\n        run: |\n          .\\.sonar\\scanner\\dotnet-sonarscanner begin /k:\"z4kn4fein_stashbox\" /v:\"${{ github.run_number }}\" /o:\"z4kn4fein\" /d:sonar.token=\"${{ secrets.SONAR_TOKEN }}\" /d:sonar.host.url=\"https://sonarcloud.io\" /d:sonar.coverage.exclusions=\"test/**,src/Utils/**,src/Expressions/Compile/**\" /d:sonar.exclusions=\"test/**,src/Utils/**,src/Expressions/Compile/**\" /d:sonar.cs.opencover.reportsPaths=\"**/TestResults/**/coverage.opencover.xml\" -d:sonar.cs.vstest.reportsPaths=\"**/TestResults/*.trx\"\n          dotnet test test\\stashbox.tests.csproj -c Release -f net8.0 --logger trx --collect:\"XPlat Code Coverage\" -- DataCollectionRunSettings.DataCollectors.DataCollector.Configuration.Format=opencover\n          .\\.sonar\\scanner\\dotnet-sonarscanner end /d:sonar.token=\"${{ secrets.SONAR_TOKEN }}\""
  },
  {
    "path": ".github/workflows/stale.yml",
    "content": "# This workflow warns and then closes issues and PRs that have had no activity for a specified amount of time.\n#\n# You can adjust the behavior by modifying this file.\n# For more information, see:\n# https://github.com/actions/stale\nname: Mark stale issues and pull requests\n\non:\n  schedule:\n  - cron: '0 1 * * *'\n\njobs:\n  stale:\n\n    runs-on: ubuntu-latest\n    permissions:\n      issues: write\n      pull-requests: write\n\n    steps:\n    - uses: actions/stale@v10\n      with:\n        repo-token: ${{ secrets.GITHUB_TOKEN }}\n        stale-issue-message: 'This issue is marked stale because it has been open for 90 days with no activity.'\n        stale-pr-message: 'This PR is marked stale because it has been open for 90 days with no activity.'\n        close-issue-message: 'This issue was closed due to no activity.'\n        close-pr-message: 'This PR was closed due to no activity.'\n        days-before-issue-stale: 90\n        days-before-pr-stale: 90\n        days-before-issue-close: 10\n        days-before-pr-close: 10\n"
  },
  {
    "path": ".gitignore",
    "content": "## Ignore Visual Studio temporary files, build results, and\n## files generated by popular Visual Studio add-ons.\n\n# User-specific files\n*.suo\n*.user\n*.userosscache\n*.sln.docstates\n\n# User-specific files (MonoDevelop/Xamarin Studio)\n*.userprefs\n\n# Build results\n[Dd]ebug/\n[Dd]ebugPublic/\n[Rr]elease/\n[Rr]eleases/\nx64/\nx86/\nbuild/\nbld/\n[Bb]in/\n[Oo]bj/\n\n# Visual Studo 2015 cache/options directory\n.vs/\n\n# MSTest test Results\n[Tt]est[Rr]esult*/\n[Bb]uild[Ll]og.*\n\n# NUNIT\n*.VisualState.xml\nTestResult.xml\n\n# Build Results of an ATL Project\n[Dd]ebugPS/\n[Rr]eleasePS/\ndlldata.c\n\n*_i.c\n*_p.c\n*_i.h\n*.ilk\n*.meta\n*.obj\n*.pch\n*.pdb\n*.pgc\n*.pgd\n*.rsp\n*.sbr\n*.tlb\n*.tli\n*.tlh\n*.tmp\n*.tmp_proj\n*.log\n*.vspscc\n*.vssscc\n.builds\n*.pidb\n*.svclog\n*.scc\n\n# Chutzpah Test files\n_Chutzpah*\n\n# Visual C++ cache files\nipch/\n*.aps\n*.ncb\n*.opensdf\n*.sdf\n*.cachefile\n\n# Visual Studio profiler\n*.psess\n*.vsp\n*.vspx\n\n# TFS 2012 Local Workspace\n$tf/\n\n# Guidance Automation Toolkit\n*.gpState\n\n# ReSharper is a .NET coding add-in\n_ReSharper*/\n*.[Rr]e[Ss]harper\n*.DotSettings.user\n\n# JustCode is a .NET coding addin-in\n.JustCode\n\n# TeamCity is a build add-in\n_TeamCity*\n\n# DotCover is a Code Coverage Tool\n*.dotCover\n\n# NCrunch\n_NCrunch_*\n.*crunch*.local.xml\n\n# MightyMoose\n*.mm.*\nAutoTest.Net/\n\n# Web workbench (sass)\n.sass-cache/\n\n# Installshield output folder\n[Ee]xpress/\n\n# DocProject is a documentation generator add-in\nDocProject/buildhelp/\nDocProject/Help/*.HxT\nDocProject/Help/*.HxC\nDocProject/Help/*.hhc\nDocProject/Help/*.hhk\nDocProject/Help/*.hhp\nDocProject/Help/Html2\nDocProject/Help/html\n\n# Click-Once directory\npublish/\n\n# Publish Web Output\n*.[Pp]ublish.xml\n*.azurePubxml\n# TODO: Comment the next line if you want to checkin your web deploy settings \n# but database connection strings (with potential passwords) will be unencrypted\n*.pubxml\n*.publishproj\n\n# NuGet Packages\n*.nupkg\n# The packages folder can be ignored because of Package Restore\n**/packages/*\n# except build/, which is used as an MSBuild target.\n!**/packages/build/\n# Uncomment if necessary however generally it will be regenerated when needed\n#!**/packages/repositories.config\n\n# Windows Azure Build Output\ncsx/\n*.build.csdef\n\n# Windows Store app package directory\nAppPackages/\n\n# Others\n*.[Cc]ache\nClientBin/\n[Ss]tyle[Cc]op.*\n~$*\n*~\n*.dbmdl\n*.dbproj.schemaview\n*.pfx\n*.publishsettings\nnode_modules/\nbower_components/\n\n# RIA/Silverlight projects\nGenerated_Code/\n\n# Backup & report files from converting an old project file\n# to a newer Visual Studio version. Backup files are not needed,\n# because we have git ;-)\n_UpgradeReport_Files/\nBackup*/\nUpgradeLog*.XML\nUpgradeLog*.htm\n\n# SQL Server files\n*.mdf\n*.ldf\n\n# Business Intelligence projects\n*.rdl.data\n*.bim.layout\n*.bim_*.settings\n\n# Microsoft Fakes\nFakesAssemblies/\n\n# Node.js Tools for Visual Studio\n.ntvs_analysis.dat\n\n# Visual Studio 6 build log\n*.plg\n\n# Visual Studio 6 workspace options file\n*.opt\n\ntools\n\ncoverageresults\ncoverage.xml\n\nproject.lock.json\n\n.sonarqube\n\n.idea"
  },
  {
    "path": ".version",
    "content": "5.20.0"
  },
  {
    "path": "CHANGELOG.md",
    "content": "Visit the [Github Releases](https://github.com/z4kn4fein/stashbox/releases) page of the repository for a complete changelog."
  },
  {
    "path": "LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2026 Peter Csajtai\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n"
  },
  {
    "path": "README.md",
    "content": "# Stashbox\n[![Appveyor Build Status](https://img.shields.io/appveyor/build/pcsajtai/stashbox?logo=appveyor&logoColor=white)](https://ci.appveyor.com/project/pcsajtai/stashbox/branch/master) \n[![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/z4kn4fein/stashbox/linux-macOS-CI.yml?logo=GitHub&branch=master)](https://github.com/z4kn4fein/stashbox/actions/workflows/linux-macOS-CI.yml)\n[![NuGet Downloads](https://img.shields.io/nuget/dt/Stashbox?label=nuget)](https://www.nuget.org/packages/Stashbox)\n[![Sonar Tests](https://img.shields.io/sonar/tests/z4kn4fein_stashbox?compact_message&logo=sonarcloud&server=https%3A%2F%2Fsonarcloud.io)](https://sonarcloud.io/project/overview?id=z4kn4fein_stashbox) \n[![Sonar Coverage](https://img.shields.io/sonar/coverage/z4kn4fein_stashbox?logo=SonarCloud&server=https%3A%2F%2Fsonarcloud.io)](https://sonarcloud.io/project/overview?id=z4kn4fein_stashbox) \n[![Sonar Quality Gate](https://img.shields.io/sonar/quality_gate/z4kn4fein_stashbox?logo=sonarcloud&server=https%3A%2F%2Fsonarcloud.io)](https://sonarcloud.io/project/overview?id=z4kn4fein_stashbox) \n[![Sourcelink](https://img.shields.io/badge/sourcelink-enabled-brightgreen.svg)](https://github.com/dotnet/sourcelink)\n\nStashbox is a lightweight, fast, and portable dependency injection framework for .NET-based solutions. It encourages the building of loosely coupled applications and simplifies the construction of hierarchical object structures. It can be integrated easily with .NET Core, Generic Host, ASP.NET, Xamarin, and many other applications.\n\n- [Documentation](https://z4kn4fein.github.io/stashbox)\n- [Release notes](https://github.com/z4kn4fein/stashbox/blob/master/CHANGELOG.md)\n- [ASP.NET Core sample](https://github.com/z4kn4fein/stashbox-extensions-dependencyinjection/tree/master/sample)\n\nGithub (stable) | NuGet (stable) | NuGet (pre-release)\n--- | --- | ---\n[![Github release](https://img.shields.io/github/release/z4kn4fein/stashbox.svg)](https://github.com/z4kn4fein/stashbox/releases) | [![NuGet Version](https://img.shields.io/nuget/v/Stashbox)](https://www.nuget.org/packages/Stashbox) | [![Nuget pre-release](https://img.shields.io/nuget/vpre/Stashbox)](https://www.nuget.org/packages/Stashbox/)\n\n## Core Attributes\n - 🚀 Fast, thread-safe, and lock-free operations.\n - ⚡️ Easy-to-use Fluent configuration API.\n - ♻️ Small memory footprint.\n - 🔄 Tracks the dependency tree for cycles. \n - 🚨 Detects and warns about misconfigurations.\n - 🔥 Gives fast feedback on registration/resolution issues.\n\n## Supported Platforms\n - .NET 5+\n - .NET Standard 2.0+\n - .NET Framework 4.5+\n - Mono\n - Universal Windows Platform\n - Xamarin (Android/iOS/Mac)\n - Unity\n\n## Contact & Support\n- Create an [issue](https://github.com/z4kn4fein/stashbox/issues) for bug reports and feature requests.\n- Start a [discussion](https://github.com/z4kn4fein/stashbox/discussions) for your questions and ideas.\n- Add a ⭐️ to support the project!\n\n## Extensions\n- ASP.NET Core\n    - [Stashbox.Extensions.DependencyInjection](https://github.com/z4kn4fein/stashbox-extensions-dependencyinjection)\n    - [Stashbox.Extensions.Hosting](https://github.com/z4kn4fein/stashbox-extensions-dependencyinjection#net-generic-host)\n    - [Stashbox.AspNetCore.Hosting](https://github.com/z4kn4fein/stashbox-extensions-dependencyinjection)\n    - [Stashbox.AspNetCore.Multitenant](https://github.com/z4kn4fein/stashbox-extensions-dependencyinjection#multitenant)\n    - [Stashbox.AspNetCore.Testing](https://github.com/z4kn4fein/stashbox-extensions-dependencyinjection#testing)\n- ASP.NET\n    - [Stashbox.Web.WebApi](https://github.com/z4kn4fein/stashbox-extensions/tree/main/src/stashbox-web-webapi)\n    - [Stashbox.Web.Mvc](https://github.com/z4kn4fein/stashbox-extensions/tree/main/src/stashbox-web-mvc)\n    - [Stashbox.AspNet.SignalR](https://github.com/z4kn4fein/stashbox-extensions/tree/main/src/stashbox-signalr)\n- OWIN\n    - [Stashbox.Owin](https://github.com/z4kn4fein/stashbox-extensions/tree/main/src/stashbox-owin)\n    - [Stashbox.AspNet.WebApi.Owin](https://github.com/z4kn4fein/stashbox-extensions/tree/main/src/stashbox-webapi-owin)\n    - [Stashbox.AspNet.SignalR.Owin](https://github.com/z4kn4fein/stashbox-extensions/tree/main/src/stashbox-signalr-owin)\n- WCF\n    - [Stashbox.Extension.Wcf](https://github.com/devworker55/stashbox-extension-wcf)\n- Hangfire\n    - [Stashbox.Hangfire](https://github.com/z4kn4fein/stashbox-extensions/tree/main/src/stashbox-hangfire)\n- Mocking\n    - [Stashbox.Mocking](https://github.com/z4kn4fein/stashbox-mocking) (Moq, FakeItEasy, NSubstitute, RhinoMocks)\n \n## Benchmarks\n - [Performance](https://github.com/danielpalme/IocPerformance)\n    \n<br>\n\n*Powered by [Jetbrains'](https://www.jetbrains.com/?from=Stashbox) [Open Source License](https://www.jetbrains.com/community/opensource/?from=Stashbox)*\n\n[![Jetbrains](https://raw.githubusercontent.com/z4kn4fein/stashbox/master/assets/jetbrains.svg)](https://www.jetbrains.com/?from=Stashbox)\n"
  },
  {
    "path": "appveyor-release.yml",
    "content": "deploy:\n- provider: NuGet\n  api_key:\n    secure: RY9paWaFrCFasUjkcr9JU0d8U+9885/yViaEnXQ+gBeHUnh61S+VbuvUONcbqV5J\n\n- provider: NuGet\n  server: https://nuget.pkg.github.com/z4kn4fein/index.json\n  artifact: /.nupkg/\n  skip_symbols: true\n  username: z4kn4fein\n  api_key:\n    secure: TaIug8cHioxT2qDznFpGtDinZiDi+20pEMQZUVAATWCvGLG9Y5LrjaxDUQtGyt38\n\n- provider: GitHub\n  tag: $(build_version)\n  release: Stashbox v$(build_version)\n  auth_token:\n    secure: TaIug8cHioxT2qDznFpGtDinZiDi+20pEMQZUVAATWCvGLG9Y5LrjaxDUQtGyt38\n  artifact: /.*\\.nupkg|.*\\.snupkg/\n\nenvironment:\n  build_version: ''\n\nimage: Visual Studio 2022\n\nconfiguration: Release\n\ninstall:\n- ps: |\n    $env:build_version = Get-Content \".version\"\n    Update-AppveyorBuild -Version \"$env:build_version-$env:appveyor_build_number\"\n    dotnet tool install -g InheritDocTool\n    \n    Invoke-WebRequest 'https://dot.net/v1/dotnet-install.ps1' -OutFile dotnet-install.ps1\n    ./dotnet-install.ps1 -Channel 10.0\n\ndotnet_csproj:\n  patch: true\n  file: 'src\\stashbox.csproj'\n  version: $(build_version)\n  package_version: $(build_version)\n  assembly_version: $(build_version)\n  file_version: $(build_version)\n  informational_version: $(build_version)\n\nbefore_build:\n- dotnet restore stashbox.sln\n\nbuild_script:\n- dotnet build -c %configuration% /p:ContinuousIntegrationBuild=true stashbox.sln\n\ntest_script:\n- dotnet test test\\stashbox.tests.csproj -f net10.0 -c %configuration% --no-build\n\nafter_build:\n- dotnet pack -c %configuration% /p:IncludeSymbols=true /p:PackageOutputPath=..\\artifacts src\\stashbox.csproj\n\nartifacts:\n  - path: artifacts\\Stashbox.*.nupkg\n    name: NuGet Packages\n  - path: artifacts\\Stashbox.*.snupkg\n    name: NuGet Symbol Packages\n\nnotifications:\n- provider: Email\n  to:\n  - peter.csajtai@outlook.com\n  on_build_success: false\n  on_build_failure: true\n  on_build_status_changed: true\n\n- provider: Slack\n  auth_token:\n    secure: /KAOQIEOWc7w1EUl6J01qNam+f+ujntrwh53yJ0zg4qRWsdfWbkjKP2UG7tQDW7/hSVJHqF7Hz/IPdS6Cp5ilsfgH6xYroLB/sawQ/pdC5k=\n  channel: '#ci'\n"
  },
  {
    "path": "appveyor.yml",
    "content": "environment:\n  github_auth_token:\n    secure: z/dKTRVRPmpItPTM/lYdX7dBJk3roDLV98Uj1XzpDqqV868xhHX8dnyKwPAJooUj\n  build_version: ''\n\nskip_tags: true\n\nskip_commits:\n  files:\n    - docs/\n    - .github/\n    - '**/*.md'\n\nimage: Visual Studio 2022\n\nconfiguration: Release\n\ninstall:\n- ps: |\n    $env:build_version = Get-Content \".version\"\n    Update-AppveyorBuild -Version \"$env:build_version-preview-$env:appveyor_build_number\"\n    \n    Invoke-WebRequest 'https://dot.net/v1/dotnet-install.ps1' -OutFile dotnet-install.ps1\n    ./dotnet-install.ps1 -Channel 8.0\n    ./dotnet-install.ps1 -Channel 9.0\n    ./dotnet-install.ps1 -Channel 10.0\n\ndotnet_csproj:\n  patch: true\n  file: 'src\\stashbox.csproj'\n  version: $(build_version)\n  package_version: $(appveyor_build_version)\n  assembly_version: $(build_version)\n  file_version: $(build_version)\n  informational_version: $(build_version)\n\nbefore_build:\n- dotnet restore stashbox.sln\n\nbuild_script:\n- dotnet build -c %configuration% /p:ContinuousIntegrationBuild=true stashbox.sln\n\nafter_build:\n- dotnet pack -c %configuration% /p:IncludeSymbols=true /p:PackageOutputPath=..\\artifacts src\\stashbox.csproj\n\ntest_script:\n- dotnet test test\\stashbox.tests.csproj -f net8.0 -c %configuration% --no-build\n- dotnet test test\\stashbox.tests.csproj -f net9.0 -c %configuration% --no-build\n- dotnet test test\\stashbox.tests.csproj -f net10.0 -c %configuration% --no-build\n\nartifacts:\n  - path: artifacts\\Stashbox.*.nupkg\n    name: NuGet Packages\n  - path: artifacts\\Stashbox.*.snupkg\n    name: NuGet Symbol Packages\n\nnotifications:\n- provider: Email\n  to:\n  - peter.csajtai@outlook.com\n  on_build_success: false\n  on_build_failure: true\n  on_build_status_changed: true\n\n- provider: Slack\n  auth_token:\n    secure: /KAOQIEOWc7w1EUl6J01qNam+f+ujntrwh53yJ0zg4qRWsdfWbkjKP2UG7tQDW7/hSVJHqF7Hz/IPdS6Cp5ilsfgH6xYroLB/sawQ/pdC5k=\n  channel: '#ci'"
  },
  {
    "path": "docs/.gitignore",
    "content": "# Dependencies\n/node_modules\n\n# Production\n/build\n\n# Generated files\n.docusaurus\n.cache-loader\n\n# Misc\n.DS_Store\n.env.local\n.env.development.local\n.env.test.local\n.env.production.local\n\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n"
  },
  {
    "path": "docs/babel.config.js",
    "content": "module.exports = {\n  presets: [require.resolve('@docusaurus/core/lib/babel/preset')],\n};\n"
  },
  {
    "path": "docs/docs/advanced/child-containers.md",
    "content": "import CodeDescPanel from '@site/src/components/CodeDescPanel';\n\n# Child containers\n\nWith child containers, you can build up parent-child relationships between containers. This means you can have a different subset of services present in a child than in the parent container. \n\nWhen a dependency is missing from the child container during a resolution request, the parent will be asked to resolve the missing service. If it's found there, the parent will return only the service's registration, and the resolution request will jump back to the child. Also, child registrations with the same [service type](/docs/getting-started/glossary#service-type--implementation-type) will override the parent's services.\n\nResolving `IEnumerable<T>` and [decorators](/docs/advanced/decorators) also considers parent containers by default. However, this behavior can be controlled with the [`ResolutionBehavior`](#resolution-behavior) parameter. \n\n:::info\nChild containers are the foundation of the [ASP.NET Core multi-tenant extension](https://github.com/z4kn4fein/stashbox-extensions-dependencyinjection#multitenant).\n:::\n\n## Example\n\nHere is an example case:\n```cs\ninterface IDependency {}\n\nclass B : IDependency {}\nclass C : IDependency {}\n\nclass A \n{\n    public A(IDependency dependency)\n    { }\n}\n\nusing (var container = new StashboxContainer())\n{\n    // register 'A' into the parent container.\n    container.Register<A>();\n\n    // register 'B' as a dependency into the parent container.\n    container.Register<IDependency, B>();\n\n    var child = container.CreateChildContainer()\n    \n    // register 'C' as a dependency into the child container.\n    child.Register<IDependency, C>();\n    \n    // 'A' is resolved from the parent and gets\n    // 'C' as IDependency because the resolution\n    // request was initiated on the child.\n    A fromChild = child.Resolve<A>();\n\n    // 'A' gets 'B' as IDependency because the \n    // resolution request was initiated on the parent.\n    A fromParent = container.Resolve<A>();\n} // using will dispose the parent along with the child.\n```\nLet's see what's happening when we request `A` from the *child*:\n1. `A` not found in the *child*, go up to the *parent* and check there.\n2. `A` found in the *parent*, resolve.\n3. `A` depends on `IDependency`, go back to the *child* and search `IDependency` implementations.\n4. `C` found in the *child*, it does not have any dependencies, instantiate.\n5. Inject the new `C` instance into `A`.\n6. All dependencies are resolved; return `A`.\n\nWhen we make the same request on the parent, everything will go as usual because we have all dependencies in place. `B` will be injected into `A`.\n\n:::info\nYou can [re-configure](/docs/configuration/container-configuration) child containers with the `.Configure()` method. It doesn't affect the parent container's configuration.\n:::\n\n## Accessing child containers\n\nYou can identify child containers with the `identifier` parameter of `CreateChildContainer()`. Later, you can retrieve the given child container by passing its ID to `GetChildContainer()`.\n\n```cs\nusing var container = new StashboxContainer();\ncontainer.CreateChildContainer(\"child\");\n// ...\n\nvar child = container.GetChildContainer(\"child\");\n```\n\nAlso, each child container created by a container is available through the `IStashboxContainer.ChildContainers` propert.\n\n```cs\nusing var container = new StashboxContainer();\ncontainer.CreateChildContainer(\"child1\");\ncontainer.CreateChildContainer(\"child2\");\n// ...\n\nforeach (var child in container.ChildContainers)\n{\n    var id = child.Key;\n    var childContainer = child.Value;\n}\n```\n\n## Resolution behavior\n\nYou can control which level of the container hierarchy can participate in the service resolution with the `ResolutionBehavior` parameter. \n\nPossible values:\n- `Default`: The default behavior, it's used when the parameter is not specified. Its value is `Parent | Current`, so both the current container (which initiated the resolution request) and its parents can participate in the resolution request's service selection.\n- `Parent`: Indicates that parent containers (including all indirect ancestors) can participate in the resolution request's service selection.\n- `Current`: Indicates that the current container (which initiated the resolution request) can participate in the service selection.\n- `ParentDependency`: Indicates that parent containers (including all indirect ancestors) can only provide dependencies for services that are already selected for resolution.\n- `PreferEnumerableInCurrent`: Upon enumerable resolution, when both `Current` and `Parent` behaviors are enabled, and the current container has the appropriate services, the resolution will prefer those and ignore the parent containers. When the current container doesn't have the requested services, the parent containers will serve the request.\n\n```csharp\ninterface IService {}\n\nclass A : IService {}\nclass B : IService {}\n\nusing (var container = new StashboxContainer())\n{\n    // register 'A' into the parent container.\n    container.Register<IService, A>();\n\n    var child = container.CreateChildContainer()\n    \n    // register 'B' into the child container.\n    child.Register<IService, B>();\n    \n    // 'A' is resolved because only parent\n    // can participate in the resolution request.\n    IService withParent = child.Resolve<IService>(ResolutionBehavior.Parent);\n\n    // Only 'B' is in the collection because\n    // only the caller container can take part\n    // in the resolution request.\n    IEnumerable<IService> allWithCurrent = child.Resolve<IEnumerable<IService>>(ResolutionBehavior.Current);\n    \n    // Both 'A' and 'B' is in the collection\n    // because both the parent and the caller container\n    // participates in the resolution request.\n    IEnumerable<IService> all = child.Resolve<IEnumerable<IService>>(ResolutionBehavior.Current | ResolutionBehavior.Parent);\n} // using will dispose the parent along with the child.\n```\n\n## Re-building singletons\nBy default, singletons are instantiated and stored only in those containers that registered them. However, you can enable the re-instantiation of singletons in child containers with the `.WithReBuildSingletonsInChildContainer()` [container configuration option](/docs/configuration/container-configuration#re-build-singletons-in-child-containers). \n\nIf it's enabled, all singletons will be re-created in those containers that initiated the resolution request. By this, re-built singletons can use overridden dependencies from child containers. \n\nRe-building in child containers does not affect the singletons instantiated in the parent container.\n\n```cs\ninterface IDependency {}\n\nclass B : IDependency {}\nclass C : IDependency {}\n\nclass A \n{\n    public A(IDependency dependency)\n    { }\n}\n\nusing (var container = new StashboxContainer(options => options.WithReBuildSingletonsInChildContainer()))\n{\n    // register 'A' as a singleton into the parent container.\n    container.RegisterSingleton<A>();\n\n    // register 'B' as a dependency into the parent container.\n    container.Register<IDependency, B>();\n\n    // 'A' gets 'B' as IDependency and will be stored\n    // in the parent container as a singleton.\n    A fromParent = container.Resolve<A>();\n\n    var child = container.CreateChildContainer();\n    \n    // register 'C' as a dependency into the child container.\n    child.Register<IDependency, C>();\n\n    // a new 'A' singleton will be created in\n    // the child container with 'C' as IDependency.\n    A fromChild = child.Resolve<A>();\n} // using will dispose the parent along with the child.\n```\n\n## Nested child containers\n\n<CodeDescPanel>\n<div>\n\nYou can build up a hierarchical tree structure from containers by creating more child containers with the `.CreateChildContainer()` method.\n\n</div>\n<div>\n\n```cs\nusing var container = new StashboxContainer();\n\nvar child1 = container.CreateChildContainer();\nvar child2 = child1.CreateChildContainer();\n```\n\n</div>\n</CodeDescPanel>\n\n## Dispose\n\nBy default, the parent container's disposal also disposes its child containers. You can control this behavior with the `CreateChildContainer()` method's `attachToParent` boolean parameter.\n\n```cs\nusing (var container = new StashboxContainer())\n{\n    using (var child1 = container.CreateChildContainer(attachToParent: false))\n    {\n    } // child1 will be disposed only once here.\n    \n    var child2 = container.CreateChildContainer();\n    var child3 = container.CreateChildContainer();\n} // using will dispose the parent along with child2 and child3.\n```\n\nYou can safely dispose a child even if it's attached to its parent, in this case the parent's disposal will not dispose the already disposed child.\n\n```cs\nusing (var container = new StashboxContainer())\n{\n    using (var child1 = container.CreateChildContainer())\n    {\n    } // child1 will be disposed only once here.\n    \n    var child2 = container.CreateChildContainer();\n} // using will dispose only the parent and child2.\n```"
  },
  {
    "path": "docs/docs/advanced/decorators.md",
    "content": "import CodeDescPanel from '@site/src/components/CodeDescPanel';\nimport Tabs from '@theme/Tabs'; \nimport TabItem from '@theme/TabItem';\n\n# Decorators\nStashbox supports decorator [service registration](/docs/getting-started/glossary#service-registration--registered-service) to take advantage of the [Decorator pattern](https://en.wikipedia.org/wiki/Decorator_pattern). This pattern is used to extend the functionality of a class without changing its implementation. This is also what the [Open–closed principle](https://en.wikipedia.org/wiki/Open%E2%80%93closed_principle) stands for; services should be open for extension but closed for modification.\n\n## Simple use-case\nWe define an `IEventProcessor` service used to process `Event` entities. Then we'll decorate this service with additional validation capabilities:\n```cs\nclass Event { }\nclass UpdateEvent : Event { }\n\ninterface IEventProcessor\n{\n    void ProcessEvent(Event @event);\n}\n\ninterface IEventValidator\n{\n    bool IsValid(Event @event);\n}\n\nclass EventValidator : IEventValidator\n{\n    public bool IsValid(Event @event) { /* do the actual validation. */ }\n}\n\nclass GeneralEventProcessor : IEventProcessor\n{\n    public void ProcessEvent(Event @event)\n    {\n        // suppose this method is processing the given event.\n        this.DoTheActualProcessing(@event);\n    }\n}\n\nclass ValidatorProcessor : IEventProcessor\n{\n    private readonly IEventProcessor nextProcessor;\n    private readonly IEventValidator eventValidator;\n    public ValidatorProcessor(IEventProcessor eventProcessor, IEventValidator eventValidator)\n    {\n        this.nextProcessor = eventProcessor;\n        this.eventValidator = eventValidator;\n    }\n\n    public void ProcessEvent(Event @event)\n    {\n        // validate the event first.\n        if (!this.eventValidator.IsValid(@event))\n            throw new InvalidEventException();\n\n        // if everything is ok, call the next processor.\n        this.nextProcessor.ProcessEvent(@event);\n    }\n}\n\nusing var container = new StashboxContainer();\n\ncontainer.Register<IEventValidator, EventValidator>();\ncontainer.Register<IEventProcessor, GeneralEventProcessor>();\ncontainer.RegisterDecorator<IEventProcessor, ValidatorProcessor>();\n\n// new ValidatorProcessor(new GeneralEventProcessor(), new EventValidator())\nvar eventProcessor = container.Resolve<IEventProcessor>();\n\n// process the event.\neventProcessor.ProcessEvent(new UpdateEvent());\n```\nThe `GeneralEventProcessor` is an implementation of `IEventProcessor` and does the actual event processing logic. It does not have any other responsibilities. Rather than putting the event validation's burden onto its shoulder, we create a different service for validation purposes. Instead of injecting the validator into the `GeneralEventProcessor` directly, we let another `IEventProcessor` decorate it like an *event processing pipeline* that validates the event as a first step.\n\n## Multiple decorators\n\n<CodeDescPanel>\n<div>\n\nYou have the option to register multiple decorators for a service to extend its functionality.\n\nThe decoration order will be the same as the registration order of the decorators. The first registered decorator will decorate the service itself. Then, all the subsequent decorators will wrap the already decorated service.\n\n</div>\n<div>\n\n```cs\ncontainer.Register<IEventProcessor, GeneralProcessor>();\ncontainer.RegisterDecorator<IEventProcessor, LoggerProcessor>();\ncontainer.RegisterDecorator<IEventProcessor, ValidatorProcessor>();\n\n// new ValidatorProcessor(new LoggerProcessor(new GeneralProcessor()));\nvar processor = container.Resolve<IEventProcessor>(); \n```\n\n</div>\n</CodeDescPanel>\n\n## Conditional decoration\n\nWith [conditional resolution](/docs/guides/service-resolution#conditional-resolution) you can control which decorator should be selected to decorate a given service.\n\n<Tabs>\n<TabItem value=\"Decoretee\" label=\"Decoretee\">\n\nYou have the option to set which decorator should be selected for a given implementation. For a single type filter, you can use the `.WhenDecoratedServiceIs()` configuration option. To select more types, you can use the more generic `.When()` option. \n\n```cs\ncontainer.Register<IEventProcessor, GeneralProcessor>();\ncontainer.Register<IEventProcessor, CustomProcessor>();\n\ncontainer.RegisterDecorator<IEventProcessor, LoggerProcessor>(options => options\n    // select when CustomProcessor or GeneralProcessor is resolved.\n    .WhenDecoratedServiceIs<CustomProcessor>()\n    .WhenDecoratedServiceIs<GeneralProcessor>());\n\ncontainer.RegisterDecorator<IEventProcessor, ValidatorProcessor>(options => options\n    // select only when GeneralProcessor is resolved.\n    .WhenDecoratedServiceIs<GeneralProcessor>());\n\n// [\n//    new ValidatorProcessor(new LoggerProcessor(new GeneralProcessor())),\n//    new LoggerProcessor(new CustomProcessor())\n// ]\nvar processors = container.ResolveAll<IEventProcessor>();\n```\n\n</TabItem>\n<TabItem value=\"Named\" label=\"Named\">\n\nYou can filter for service names to control the decorator selection.\n```cs\ncontainer.Register<IEventProcessor, GeneralProcessor>(\"General\");\ncontainer.Register<IEventProcessor, CustomProcessor>(\"Custom\");\n\ncontainer.RegisterDecorator<IEventProcessor, LoggerProcessor>(options => options\n    // select when CustomProcessor or GeneralProcessor is resolved.\n    .WhenDecoratedServiceIs(\"General\")\n    .WhenDecoratedServiceIs(\"Custom\"));\n\ncontainer.RegisterDecorator<IEventProcessor, ValidatorProcessor>(options => options\n    // select only when GeneralProcessor is resolved.\n    .WhenDecoratedServiceIs(\"General\"));\n\n// new ValidatorProcessor(new LoggerProcessor(new GeneralProcessor()))\nvar general = container.Resolve<IEventProcessor>(\"General\");\n\n// new LoggerProcessor(new CustomProcessor())\nvar custom = container.Resolve<IEventProcessor>(\"Custom\");\n```\n\n</TabItem>\n<TabItem value=\"Attribute\" label=\"Attribute\">\n\nYou can use your custom attributes to control the decorator selection. With **class attributes**, you can mark your classes for decoration.\n```cs\nclass LogAttribute : Attribute { }\nclass ValidateAttribute : Attribute { }\n\n[Log, Validate]\nclass GeneralProcessor : IEventProcessor { }\n\n[Log]\nclass CustomProcessor : IEventProcessor { }\n\ncontainer.Register<IEventProcessor, GeneralProcessor>();\ncontainer.Register<IEventProcessor, CustomProcessor>();\n\ncontainer.RegisterDecorator<IEventProcessor, LoggerProcessor>(options => options\n    // select when the resolving class has 'LogAttribute'.\n    .WhenDecoratedServiceHas<LogAttribute>());\n\ncontainer.RegisterDecorator<IEventProcessor, ValidatorProcessor>(options => options\n    // select when the resolving class has 'ValidateAttribute'.\n    .WhenDecoratedServiceHas<ValidateAttribute>());\n\n// [\n//    new ValidatorProcessor(new LoggerProcessor(new GeneralProcessor())),\n//    new LoggerProcessor(new CustomProcessor())\n// ]\nvar processors = container.ResolveAll<IEventProcessor>();\n```\n\nYou can also mark your dependencies for decoration with **property / field / parameter attributes**. \n\n```cs\nclass LogAttribute : Attribute { }\nclass ValidateAttribute : Attribute { }\n\nclass ProcessorExecutor\n{\n    public ProcessorExecutor([Log, Validate]IEventProcessor eventProcessor)\n    { }\n}\n\ncontainer.Register<ProcessorExecutor>();\ncontainer.Register<IEventProcessor, GeneralProcessor>();\n\ncontainer.RegisterDecorator<IEventProcessor, LoggerProcessor>(options => options\n    // select when the resolving dependency has 'LogAttribute'.\n    .WhenHas<LogAttribute>());\n\ncontainer.RegisterDecorator<IEventProcessor, ValidatorProcessor>(options => options\n    // select when the resolving dependency has 'ValidateAttribute'.\n    .WhenHas<ValidateAttribute>());\n\n// new ProcessorExecutor(new ValidatorProcessor(new LoggerProcessor(new GeneralProcessor())))\nvar executor = container.ResolveAll<ProcessorExecutor>();\n```\n\n</TabItem>\n</Tabs>\n\n## Generic decorators\nStashbox supports the registration of open-generic decorators, which allows the extension of open-generic services. \nInspection of [generic parameter constraints](/docs/advanced/generics#generic-constraints) and [variance handling](/docs/advanced/generics#variance) is supported on generic decorators also.\n\n```cs\ninterface IEventProcessor<TEvent>\n{\n    void ProcessEvent(TEvent @event);\n}\n\nclass GeneralEventProcessor<TEvent> : IEventProcessor<TEvent>\n{\n    public void ProcessEvent(TEvent @event) { /* suppose this method is processing the given event.*/ }\n}\n\nclass ValidatorProcessor<TEvent> : IEventProcessor<TEvent>\n{\n    private readonly IEventProcessor<TEvent> nextProcessor;\n\n    public ValidatorProcessor(IEventProcessor<TEvent> eventProcessor)\n    {\n        this.nextProcessor = eventProcessor;\n    }\n\n    public void ProcessEvent(TEvent @event)\n    {\n        // validate the event first.\n        if (!this.IsValid(@event))\n            throw new InvalidEventException();\n\n        // if everything is ok, call the next processor.\n        this.nextProcessor.ProcessEvent(@event);\n    }\n}\n\nusing var container = new StashboxContainer();\ncontainer.Register(typeof(IEventProcessor<>), typeof(GeneralEventProcessor<>));\ncontainer.RegisterDecorator(typeof(IEventProcessor<>), typeof(ValidatorProcessor<>));\n\n// new ValidatorProcessor<UpdateEvent>(new GeneralEventProcessor<UpdateEvent>())\nvar eventProcessor = container.Resolve<IEventProcessor<UpdateEvent>>();\n\n// process the event.\neventProcessor.ProcessEvent(new UpdateEvent());\n```\n\n## Composite pattern\n\nThe [Composite pattern](https://en.wikipedia.org/wiki/Composite_pattern) allows a group of objects to be treated the same way as a single instance of the same type. It's useful when you want to use the functionality of multiple instances behind the same interface. You can achieve this by registering a decorator that takes a collection of the same service as a dependency. \n\n```cs\npublic class CompositeValidator<TEvent> : IEventValidator<TEvent>\n{\n    private readonly IEnumerable<IEventValidator<TEvent>> validators;\n\n    public CompositeValidator(IEnumerable<IEventValidator<TEvent>> validators)\n    {\n        this.validators = validators;\n    }\n\n    public bool IsValid(TEvent @event)\n    {\n        return this.validators.All(validator => validator.IsValid(@event));\n    }\n}\n\ncontainer.Register(typeof(IEventValidator<>), typeof(EventValidator<>));\ncontainer.Register(typeof(IEventValidator<>), typeof(AnotherEventValidator<>));\ncontainer.RegisterDecorator(typeof(IEventValidator<>), typeof(CompositeValidator<>));\n```\n\n## Decorating multiple services\nYou have the option to organize similar decorating functionalities for different interfaces into the same decorator class. \nIn this example, we would like to validate a given `Event` right before publishing and also before processing. \n\n```cs\npublic class EventValidator<TEvent> : IEventProcessor<T>, IEventPublisher<TEvent>\n{\n    private readonly IEventProcessor<TEvent> processor;\n    private readonly IEventPublisher<TEvent> publisher;\n    private readonly IEventValidator<TEvent> validator;\n\n    public CompositeValidator(IEventProcessor<TEvent> processor, \n        IEventPublisher<TEvent> publisher, \n        IEventValidator<TEvent> validator)\n    {\n        this.processor = processor;\n        this.publisher = publisher;\n        this.validator = validator;\n    }\n\n    public void ProcessEvent(TEvent @event)\n    {\n        // validate the event first.\n        if (!this.validator.IsValid(@event))\n            throw new InvalidEventException();\n\n        // if everything is ok, call the processor.\n        this.processor.ProcessEvent(@event);\n    }\n\n    public void PublishEvent(TEvent @event)\n    {\n        // validate the event first.\n        if (!this.validator.IsValid(@event))\n            throw new InvalidEventException();\n\n        // if everything is ok, call the publisher.\n        this.publisher.PublishEvent(@event);\n    }\n}\n\ncontainer.Register(typeof(IEventProcessor<>), typeof(EventProcessor<>));\ncontainer.Register(typeof(IEventPublisher<>), typeof(EventPublisher<>));\ncontainer.Register(typeof(IEventValidator<>), typeof(EventValidator<>));\n\n// without specifying the interface type, the container binds this registration to all of its implemented types\ncontainer.RegisterDecorator(typeof(EventValidator<>));\n```\n\n:::info\nYou can also use the [Binding to multiple services](/docs/guides/advanced-registration#binding-to-multiple-services) options.\n:::\n\n## Lifetime\n\n<CodeDescPanel>\n<div>\n\nJust as other registrations, decorators also can have their lifetime. It means, in addition to the service's lifetime, all decorator's lifetime will be applied to the wrapped service.\n\n:::note\nWhen you don't set a decorator's lifetime, it'll implicitly inherit the decorated service's lifetime.\n:::\n\n</div>\n<div>\n\n```cs\ncontainer.Register<IEventProcessor, GeneralEventProcessor>();\n// singleton decorator will change the transient \n// decorated service's lifetime to singleton.\ncontainer.RegisterDecorator<IEventProcessor, ValidatorProcessor>(options => \n    options.WithLifetime(Lifetimes.Singleton));\n// Singleton[new ValidatorProcessor()](Transien[new GeneralEventProcessor()]) \nvar processor = container.Resolve<IEventProcessor>(); \n```\n\n</div>\n</CodeDescPanel>\n\n## Wrappers\n\n<CodeDescPanel>\n<div>\n\nDecorators are also applied to wrapped services. It means, in addition to the decoration, you can wrap your services in supported [wrappers](/docs/advanced/wrappers-resolvers#wrappers).\n\n</div>\n<div>\n\n```cs\ncontainer.Register<IEventProcessor, GeneralEventProcessor>();\ncontainer.RegisterDecorator<IEventProcessor, ValidatorProcessor>();\n// () => new ValidatorProcessor(new GeneralEventProcessor())\nvar processor = container.Resolve<Func<IEventProcessor>>();\n```\n\n</div>\n</CodeDescPanel>\n\n## Interception\nFrom the combination of Stashbox's decorator support and [Castle DynamicProxy's](http://www.castleproject.org/projects/dynamicproxy/) proxy generator, we can take advantage of the [Aspect-Oriented Programming's](https://en.wikipedia.org/wiki/Aspect-oriented_programming) benefits. The following example defines a `LoggingInterceptor` that will log additional messages related to the called service methods.\n\n```cs\npublic class LoggingInterceptor : IInterceptor \n{\n    private readonly ILogger logger;\n\n    public LoggingInterceptor(ILogger logger)\n    {\n        this.logger = logger;\n    }\n\n    public void Intercept(IInvocation invocation)\n    {\n        var stopwatch = new Stopwatch();\n        stopwatch.Start();\n\n        // log before we invoke the intercepted method.\n        this.logger.Log($\"Method begin: {invocation.GetConcreteMethod().Name}\");\n\n        // call the intercepted method.\n        invocation.Proceed();\n\n        // log after we invoked the intercepted method and print how long it ran.\n        this.logger.Log($\"Method end: {invocation.GetConcreteMethod().Name}, execution duration: {stopwatch.ElapsedMiliseconds} ms\");\n    }\n}\n\n// create a DefaultProxyBuilder from the DynamicProxy library.\nvar proxyBuilder = new DefaultProxyBuilder();\n\n// build a proxy for the IEventProcessor interface.\nvar eventProcessorProxy = proxyBuilder.CreateInterfaceProxyTypeWithTargetInterface(\n    typeof(IEventProcessor), \n    new Type[0], \n    ProxyGenerationOptions.Default);\n\n// register the logger for LoggingInterceptor.\ncontainer.Register<ILogger, ConsoleLogger>();\n\n// register the service that we will intercept.\ncontainer.Register<IEventProcessor, GeneralEventProcessor>();\n\n// register the interceptor.\ncontainer.Register<IInterceptor, LoggingInterceptor>();\n\n// register the built proxy as a decorator.\ncontainer.RegisterDecorator<IEventProcessor>(eventProcessorProxy);\n```"
  },
  {
    "path": "docs/docs/advanced/generics.md",
    "content": "import CodeDescPanel from '@site/src/components/CodeDescPanel';\nimport Tabs from '@theme/Tabs'; \nimport TabItem from '@theme/TabItem';\n\n# Generics\nThis section is about how Stashbox handles various usage scenarios that involve .NET Generic types. Including the registration of open-generic and closed-generic types, [generic decorators](/docs/advanced/decorators#generic-decorators), conditions based on generic constraints, and variance.\n\n## Closed-generics\n\n<CodeDescPanel>\n<div>\n\nThe registration of a closed-generic type does not differ from registering a simple non-generic service.\n\nYou have all options available that you saw at the [basic](/docs/guides/basics) and [advanced registration](/docs/guides/advanced-registration) flows.\n\n</div>\n<div>\n\n<Tabs groupId=\"generic-runtime-apis\">\n<TabItem value=\"Generic API\" label=\"Generic API\">\n\n```cs\ncontainer.Register<IValidator<User>, UserValidator>();\nIValidator<User> validator = container.Resolve<IValidator<User>>();\n```\n\n</TabItem>\n<TabItem value=\"Runtime type API\" label=\"Runtime type API\">\n\n```cs\ncontainer.Register(typeof(IValidator<User>), typeof(UserValidator));\nobject validator = container.Resolve(typeof(IValidator<User>));\n```\n\n</TabItem>\n</Tabs>\n</div>\n</CodeDescPanel>\n\n## Open-generics\n\nThe registration of an open-generic type differs from registering a closed-generic one as C# doesn't allow the usage of open-generic types in generic method parameters. We have to get a runtime type from the open-generic type first with `typeof()`.\n\n<CodeDescPanel>\n<div>\n\nOpen-generic types could help in such scenarios where you have generic interface-implementation pairs with numerous generic parameter variations. The registration of those different versions would look like this: \n\n</div>\n<div>\n\n```cs\ncontainer.Register<IValidator<User>, Validator<User>>();\ncontainer.Register<IValidator<Role>, Validator<Role>>();\ncontainer.Register<IValidator<Company>, Validator<Company>>();\n// and so on...\n```\n\n</div>\n</CodeDescPanel>\n\n<CodeDescPanel>\n<div>\n\nRather than doing that, you can register your type's generic definition and let Stashbox bind the type parameters for you. When a matching closed [service type](/docs/getting-started/glossary#service-type--implementation-type) is requested, the container will construct an equivalent closed-generic implementation.\n\n</div>\n<div>\n\n```cs\ncontainer.Register(typeof(IValidator<>), typeof(Validator<>));\n// Validator<User> will be returned.\nIValidator<User> userValidator = container.Resolve<IValidator<User>>();\n// Validator<Role> will be returned.\nIValidator<Role> roleValidator = container.Resolve<IValidator<Role>>();\n```\n\n</div>\n</CodeDescPanel>\n\n<CodeDescPanel>\n<div>\n\nA registered closed-generic type always has priority over an open-generic type at service selection.\n\n</div>\n<div>\n\n```cs\ncontainer.Register<IValidator<User>, UserValidator>();\ncontainer.Register(typeof(IValidator<>), typeof(Validator<>));\n// UserValidator will be returned.\nIValidator<User> validator = container.Resolve<IValidator<User>>();\n```\n</div>\n</CodeDescPanel>\n\n\n## Generic constraints\nIn the following examples, you can see how the container handles generic constraints during service resolution. Constraints can be used for [conditional resolution](/docs/guides/service-resolution#conditional-resolution) including collection filters. \n\n\n<Tabs>\n<TabItem value=\"Conditional resolution\" label=\"Conditional resolution\">\n\nThe container chooses `UpdatedEventHandler` because it is the only one that has a constraint satisfied by the requested `UserUpdatedEvent` generic parameter as it's implementing `IUpdatedEvent`.\n```cs\ninterface IEventHandler<TEvent> { }\n\n// event interfaces\ninterface IUpdatedEvent { }\ninterface ICreatedEvent { }\n\n// event handlers\nclass UpdatedEventHandler<TEvent> : IEventHandler<TEvent> where TEvent : IUpdatedEvent { }\nclass CreatedEventHandler<TEvent> : IEventHandler<TEvent> where TEvent : ICreatedEvent { }\n\n// event implementation\nclass UserUpdatedEvent : IUpdatedEvent { }\n\nusing var container = new StashboxContainer();\n\ncontainer.RegisterTypesAs(typeof(IEventHandler<>), new[] \n    { \n        typeof(UpdateEventHandler<>), \n        typeof(CreateEventHandler<>) \n    });\n\n// eventHandler will be UpdatedEventHandler<ConstraintArgument>\nIEventHandler<UserUpdatedEvent> eventHandler = container.Resolve<IEventHandler<UserUpdatedEvent>>();\n```\n\n</TabItem>\n<TabItem value=\"Collection filter\" label=\"Collection filter\">\n\nThis example shows how the container is filtering out those services from the returned collection that does not satisfy the given generic constraint needed to create the closed generic type.\n```cs\ninterface IEventHandler<TEvent> { }\n\n// event interfaces\ninterface IUpdatedEvent { }\ninterface ICreatedEvent { }\n\n// event handlers\nclass UpdatedEventHandler<TEvent> : IEventHandler<TEvent> where TEvent : IUpdatedEvent { }\nclass CreatedEventHandler<TEvent> : IEventHandler<TEvent> where TEvent : ICreatedEvent { }\n\n// event implementation\nclass UserUpdatedEvent : IUpdatedEvent { }\n\nusing var container = new StashboxContainer();\n\ncontainer.RegisterTypesAs(typeof(IEventHandler<>), new[] \n    { \n        typeof(UpdateEventHandler<>), \n        typeof(CreateEventHandler<>) \n    });\n\n// eventHandlers will contain only UpdatedEventHandler<ConstraintArgument>\nIEnumerable<IEventHandler<UserUpdatedEvent>> eventHandlers = container.ResolveAll<IEventHandler<UserUpdatedEvent>>();\n```\n\n</TabItem>\n</Tabs>\n\n## Variance\nSince .NET Framework 4.0, C# supports [covariance and contravariance](https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/covariance-contravariance/) in generic interfaces and delegates and allows implicit conversion of generic type parameters. In this section, we'll focus on variance in generic interfaces. \n\n[Here](https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/covariance-contravariance/creating-variant-generic-interfaces) you can read more about how to create variant generic interfaces, and the following example will show how you can use them with Stashbox.\n\n<Tabs>\n<TabItem value=\"Contravariance\" label=\"Contravariance\">\n\n**Contravariance** only allows argument types that are less derived than that defined by the generic parameters. You can declare a generic type parameter contravariant by using the `in` keyword.\n\n```cs\n// contravariant generic event handler interface\ninterface IEventHandler<in TEvent> { } \n\n// event interfaces\ninterface IGeneralEvent { }\ninterface IUpdatedEvent : IGeneralEvent { }\n\n// event handlers\nclass GeneralEventHandler : IEventHandler<IGeneralEvent> { }\nclass UpdatedEventHandler : IEventHandler<IUpdatedEvent> { }\n\ncontainer.Register<IEventHandler<IGeneralEvent>, GeneralEventHandler>();\ncontainer.Register<IEventHandler<IUpdatedEvent>, UpdatedEventHandler>();\n\n// eventHandlers contain both GeneralEventHandler and UpdatedEventHandler\nIEnumerable<IEventHandler<IUpdatedEvent>> eventHandlers = container.ResolveAll<IEventHandler<IUpdatedEvent>>();\n```\nDespite the fact that only `IEventHandler<IUpdatedEvent>` implementations were requested, the result contains both `GeneralEventHandler` and `UpdatedEventHandler`. As `TEvent` is declared **contravariant** with the `in` keyword, and `IGeneralEvent` is less derived than `IUpdatedEvent`, `IEventHandler<IGeneralEvent>` implementations can be part of `IEventHandler<IUpdatedEvent>` collections.\n\nIf we request `IEventHandler<IGeneralEvent>`, only `GeneralEventHandler` would be returned, because `IUpdatedEvent` is more derived, so `IEventHandler<IUpdatedEvent>` implementations are not fit into `IEventHandler<IGeneralEvent>` collections. \n\n</TabItem>\n<TabItem value=\"Covariance\" label=\"Covariance\">\n\n**Covariance** only allows argument types that are more derived than that defined by the generic parameters. You can declare a generic type parameter covariant by using the `out` keyword.\n```cs\n// covariant generic event handler interface\ninterface IEventHandler<out TEvent> { } \n\n// event interfaces\ninterface IGeneralEvent { }\ninterface IUpdatedEvent : IGeneralEvent { }\n\n// event handlers\nclass GeneralEventHandler : IEventHandler<IGeneralEvent> { }\nclass UpdatedEventHandler : IEventHandler<IUpdatedEvent> { }\n\ncontainer.Register<IEventHandler<IGeneralEvent>, GeneralEventHandler>();\ncontainer.Register<IEventHandler<IUpdatedEvent>, UpdatedEventHandler>();\n\n// eventHandlers contain both GeneralEventHandler and UpdatedEventHandler\nIEnumerable<IEventHandler<IGeneralEvent>> eventHandlers = container.ResolveAll<IEventHandler<IGeneralEvent>>();\n```\n\nDespite the fact that only `IEventHandler<IGeneralEvent>` implementations were requested, the result contains both `GeneralEventHandler` and `UpdatedEventHandler`. As `TEvent` is declared **covariant** with the `out` keyword, and `IUpdatedEvent` is more derived than `IGeneralEvent`, `IEventHandler<IUpdatedEvent>` implementations can be part of `IEventHandler<IGeneralEvent>` collections.\n\nIf we request `IEventHandler<IUpdatedEvent>`, only `UpdatedEventHandler` would be returned, because `IGeneralEvent` is less derived, so `IEventHandler<IGeneralEvent>` implementations are not fit into `IEventHandler<IUpdatedEvent>` collections.\n\n</TabItem>\n</Tabs>\n\n:::info\nThe check for variant generic types is enabled by default, but it can be turned off via a [container configuration option](/docs/configuration/container-configuration#generic-variance).\n:::"
  },
  {
    "path": "docs/docs/advanced/special-resolution-cases.md",
    "content": "import Tabs from '@theme/Tabs'; \nimport TabItem from '@theme/TabItem';\n\n# Special resolution cases\n\n## Unknown type resolution\nWhen this [feature](/docs/configuration/container-configuration#unknown-type-resolution) is enabled, the container will try to resolve unregistered types by registering them using a pre-defined configuration delegate.\n\n<Tabs>\n<TabItem value=\"Default\" label=\"Default\">\n\nWithout a registration configuration, the container can resolve only non-interface and non-abstract unknown types. In the following example,\nthe container creates an implicit registration for `Dependency` and injects its instance into `Service`.\n```cs\nclass Dependency { }\n\nclass Service \n{\n    public Service(Dependency dependency)\n    { }     \n}\n\nvar container = new StashboxContainer(config => config\n    .WithUnknownTypeResolution());\n\ncontainer.Register<Service>();\n\nvar service = container.Resolve<Service>();\n```\n\n</TabItem>\n<TabItem value=\"With registration configuration\" label=\"With registration configuration\">\n\nWith a registration configuration, you can control how an unknown type's individual registration should behave. You can also react to a service resolution request. In the following example, we tell the container that if it finds an unregistered `IDependency` for the first time, that should be mapped to `Dependency` and have a singleton lifetime. Next time, when the container comes across this service, it will use the registration created at the first request.\n\n```cs\ninterface IDependency { }\n\nclass Dependency : IDependency { }\n\nclass Service \n{\n    public Service(IDependency dependency)\n    { }     \n}\n\nvar container = new StashboxContainer(config => config\n    .WithUnknownTypeResolution(options => \n    {\n        if(options.ServiceType == typeof(IDependency))\n        {\n            options.SetImplementationType(typeof(Dependency))\n                .WithLifetime(Lifetimes.Singleton);\n        }\n    }));\n\ncontainer.Register<Service>();\n\nvar service = container.Resolve<Service>();\n```\n\n</TabItem>\n</Tabs>\n\n## Default value injection\nWhen this [feature](/docs/configuration/container-configuration#default-value-injection) is enabled, the container will resolve unknown primitive dependencies with their default value.\n```cs\nclass Person \n{\n    public Person(string name, int age) { }\n}\n\nvar container = new StashboxContainer(config => config\n    .WithDefaultValueInjection());\n// the name parameter will be null and the age will be 0.\nvar person = container.Resolve<Person>();\n```\n\n:::note\nUnknown reference types are resolved to `null` only in properties and fields.\n:::\n\n## Optional value injection\nStashbox respects the optional value of each constructor and method argument.\n\n```cs\nclass Person \n{\n    public Person(string name = null, int age = 54, IContact contact = null) { }\n}\n\n// the name will be null \n// the age will be 54.\n// the contact will be null.\nvar person = container.Resolve<Person>();\n```"
  },
  {
    "path": "docs/docs/advanced/wrappers-resolvers.md",
    "content": "import CodeDescPanel from '@site/src/components/CodeDescPanel';\nimport Tabs from '@theme/Tabs'; \nimport TabItem from '@theme/TabItem';\n\n# Wrappers & resolvers \n\nStashbox uses so-called *Wrapper* and *Resolver* implementations to handle special resolution requests that none of the [service registrations](/docs/getting-started/glossary#service-registration--registered-service) can fulfill. Functionalities like [wrapper](/docs/advanced/wrappers-resolvers#wrappers) and [unknown type](/docs/advanced/special-resolution-cases#unknown-type-resolution) resolution, [cross-container requests](/docs/advanced/child-containers), [optional](/docs/advanced/special-resolution-cases#optional-value-injection) and [default value](/docs/advanced/special-resolution-cases#default-value-injection) injection are all built with resolvers.\n\n## Pre-defined wrappers & resolvers\n* `EnumerableWrapper`: Used to resolve a collection of services wrapped in one of the collection interfaces that a .NET `Array` implements. (`IEnumerable<>`, `IList<>`, `ICollection<>`, `IReadOnlyList<>`, `IReadOnlyCollection<>`) \n* `LazyWrapper`: Used to resolve services [wrapped](/docs/advanced/wrappers-resolvers#lazy) in `Lazy<>`.\n* `FuncWrapper`: Used to resolve services [wrapped](/docs/advanced/wrappers-resolvers#delegate) in a `Delegate` that has a non-void return type like `Func<>`.\n* `MetadataWrapper`: Used to resolve services [wrapped](/docs/advanced/wrappers-resolvers#metadata--tuple) in `ValueTuple<,>`, `Tuple<,>`, or `Metadata<,>`.\n* `KeyValueWrapper`: Used to resolve services [wrapped](/docs/advanced/wrappers-resolvers#keyvaluepair--readonlykeyvalue) in `KeyValuePair<,>` or `ReadOnlyKeyValue<,>`.\n* `ServiceProviderResolver`: Used to resolve the actual scope as `IServiceProvider` when no other implementation is registered.\n* `OptionalValueResolver`: Used to resolve optional parameters.\n* `DefaultValueResolver`: Used to resolve default values.\n* `ParentContainerResolver`: Used to resolve services that are only registered in one of the parent containers.\n* `UnknownTypeResolver`: Used to resolve services that are not registered into the container.\n\n## Wrappers\nStashbox can implicitly wrap your services into different data structures. All functionalities covered in the [service resolution](/docs/guides/service-resolution) are applied to the wrappers. Every wrapper request starts as a standard resolution; only the result is wrapped in the requested structure.\n\n<CodeDescPanel>\n<div>\n\n### Enumerable\nStashbox can compose a collection from each implementation registered to a [service type](/docs/getting-started/glossary#service-type--implementation-type). The requested type can be wrapped by any of the collection interfaces that a .NET `Array` implements.\n\n</div>\n<div>\n\n```cs\nIJob[] jobs = container.Resolve<IJob[]>();\nIEnumerable<IJob> jobs = container.Resolve<IEnumerable<IJob>>();\nIList<IJob> jobs = container.Resolve<IList<IJob>>();\nICollection<IJob> jobs = container.Resolve<ICollection<IJob>>();\nIReadOnlyList<IJob> jobs = container.Resolve<IReadOnlyList<IJob>>();\nIReadOnlyCollection<IJob> jobs = container.Resolve<IReadOnlyCollection<IJob>>();\n```\n\n</div>\n</CodeDescPanel>\n\n<CodeDescPanel>\n<div>\n\n### Lazy\nWhen requesting `Lazy<>`, the container implicitly constructs a new `Lazy<>` instance with a factory delegate as its constructor argument used to instantiate the underlying service. \n\n</div>\n<div>\n\n```cs\ncontainer.Register<IJob, DbBackup>();\n\n// new Lazy(() => new DbBackup())\nLazy<IJob> lazyJob = container.Resolve<Lazy<IJob>>();\nIJob job = lazyJob.Value;\n```\n</div>\n</CodeDescPanel>\n\n<CodeDescPanel>\n<div>\n\n### Delegate\n\nWhen requesting a `Delegate`, the container implicitly creates a factory used to instantiate the underlying service.\n\nIt's possible to request a delegate that expects some or all of the dependencies as delegate parameters.\nParameters are used for sub-dependencies as well, like: `(arg) => new A(new B(arg))`\n\nWhen a dependency is not available as a parameter, it will be resolved from the container directly.\n\n</div>\n<div>\n\n<Tabs>\n<TabItem value=\"Func\" label=\"Func\">\n\n```cs\ncontainer.Register<IJob, DbBackup>();\n\n// (conn, logger) => new DbBackup(conn, logger)\nFunc<string, ILogger, IJob> funcOfJob = container\n    .Resolve<Func<string, ILogger, IJob>>();\n    \nIJob job = funcOfJob(config[\"connectionString\"], new ConsoleLogger());\n```\n\n</TabItem>\n<TabItem value=\"Custom delegate\" label=\"Custom delegate\">\n\n```cs\nprivate delegate IJob JobFactory(string connectionString, ILogger logger);\n\ncontainer.Register<IJob, DbBackup>();\n\nvar jobDelegate = container.Resolve<JobFactory>();\nIJob job = jobDelegate(config[\"connectionString\"], new ConsoleLogger());\n```\n\n</TabItem>\n</Tabs>\n</div>\n</CodeDescPanel>\n\n<CodeDescPanel>\n<div>\n\n### Metadata & Tuple\nWith the `.WithMetadata()` registration option, you can attach additional information to a service.\nTo gather this information, you can request the service wrapped in either `Metadata<,>`, `ValueTuple<,>`, or `Tuple<,>`.\n\n`Metadata<,>` is a type from the `Stashbox` package, so you might prefer using `ValueTuple<,>` or `Tuple<,>` if you want to avoid referencing Stashbox in certain parts of your project.\n\nYou can also filter a collection of services by their metadata. Requesting `IEnumerable<ValueTuple<,>>` will yield only those services that have the given type of metadata.\n</div>\n<div>\n\n<Tabs>\n<TabItem value=\"Single service\" label=\"Single service\">\n\n```cs\ncontainer.Register<IJob, DbBackup>(options => options\n    .WithMetadata(\"connection-string-to-db\"));\n\nvar jobWithConnectionString = container.Resolve<Metadata<IJob, string>>();\n// prints: \"connection-string-to-db\"\nConsole.WriteLine(jobWithConnectionString.Data);\n\nvar alsoJobWithConnectionString = container.Resolve<ValueTuple<IJob, string>>();\n// prints: \"connection-string-to-db\"\nConsole.WriteLine(alsoJobWithConnectionString.Item2);\n\nvar stillJobWithConnectionString = container.Resolve<Tuple<IJob, string>>();\n// prints: \"connection-string-to-db\"\nConsole.WriteLine(stillJobWithConnectionString.Item2);\n```\n\n</TabItem>\n<TabItem value=\"Collection filtering\" label=\"Collection filtering\">\n\n```cs\ncontainer.Register<IService, Service1>(options => options\n    .WithMetadata(\"meta-1\"));\ncontainer.Register<IService, Service2>(options => options\n    .WithMetadata(\"meta-2\"));\ncontainer.Register<IService, Service3>(options => options\n    .WithMetadata(5));\n\n// the result is: [Service1, Service2]\nvar servicesWithStringMetadata = container.Resolve<ValueTuple<IService, string>[]>();\n\n// the result is: [Service3]\nvar servicesWithIntMetadata = container.Resolve<ValueTuple<IService, int>[]>();\n```\n\n</TabItem>\n</Tabs>\n</div>\n</CodeDescPanel>\n\n:::note\nMetadata can also be a complex type e.g., an `IDictionary<,>`.\n:::\n\n:::info\nWhen no service found for a particular metadata type, the container throws a [ResolutionFailedException](/docs/diagnostics/validation#resolution-validation). In case of an `IEnumerable<>` request, an empty collection will be returned for a non-existing metadata.\n:::\n\n<CodeDescPanel>\n<div>\n\n### KeyValuePair & ReadOnlyKeyValue\nWith named registration, you can give your service unique identifiers. Requesting a service wrapped in a `KeyValuePair<object, TYourService>` or `ReadOnlyKeyValue<object, TYourService>` returns the requested service with its identifier as key.\n\n`ReadOnlyKeyValue<,>` is a type from the `Stashbox` package, so you might prefer using `KeyValuePair<,>` if you want to avoid referencing Stashbox in certain parts of your project.\n\nRequesting an `IEnumerable<KeyValuePair<,>>` will return all services of the requested type along their identifiers. When a service don't have an identifier the `Key` will be set to `null`.\n\n</div>\n<div>\n\n```cs\ncontainer.Register<IService, Service1>(\"FirstServiceId\");\ncontainer.Register<IService, Service2>(\"SecondServiceId\");\ncontainer.Register<IService, Service3>();\n\nvar serviceKeyValue1 = container\n    .Resolve<KeyValuePair<object, IService>>(\"FirstServiceId\");\n// prints: \"FirstServiceId\"\nConsole.WriteLine(serviceKeyValue1.Key);\n\nvar serviceKeyValue2 = container\n    .Resolve<ReadOnlyKeyValue<object, IService>>(\"SecondServiceId\");\n// prints: \"SecondServiceId\"\nConsole.WriteLine(serviceKeyValue2.Key);\n\n// [\"FirstServiceId\": Service1, \"SecondServiceId\": Service2, null: Service3 ]\nvar servicesWithKeys = container.Resolve<KeyValuePair<object, IService>[]>();\n```\n</div>\n</CodeDescPanel>\n\n:::note\nWrappers can be composed e.g., `IEnumerable<Func<ILogger, Tuple<Lazy<IJob>, string>>>`.\n:::\n\n## User-defined wrappers & resolvers\nYou can add support for more wrapper types by implementing the `IServiceWrapper` interface.\n```cs\nclass CustomWrapper : IServiceWrapper\n{\n    // this method is supposed to generate the expression for the given wrapper's \n    // instantiation when it's selected by the container to resolve the actual service.\n    public Expression WrapExpression(\n        TypeInformation originalTypeInformation, \n        TypeInformation wrappedTypeInformation, \n        ServiceContext serviceContext)\n    {\n        // produce the expression for the wrapper.\n    }\n\n    // this method is called by the container to determine whether a \n    // given requested type is wrapped by a supported wrapper type.\n    public bool TryUnWrap(Type type, out Type unWrappedType)\n    {\n        // this is just a reference implementation of \n        // un-wrapping a service from a given wrapper.\n        if (!CanUnWrapServiceType(type))\n        {\n            unWrappedType = typeof(object);\n            return false;\n        }\n\n        unWrappedType = UnWrapServiceType(type);\n        return true;\n    }\n}\n```\n\nYou can extend the functionality of the container by implementing the `IServiceResolver` interface.\n```cs\nclass CustomResolver : IServiceResolver\n{\n    // called to generate the expression for the given service\n    // when this resolver is selected (through CanUseForResolution()) \n    // to fulfill the request.\n    public ServiceContext GetExpression(\n        IResolutionStrategy resolutionStrategy,\n        TypeInformation typeInfo,\n        ResolutionContext resolutionContext)\n    {\n        var expression = GenerateExpression(); // resolution expression generation.\n        return expression.AsServiceContext();\n    }\n\n    public bool CanUseForResolution(\n        TypeInformation typeInfo,\n        ResolutionContext resolutionContext)\n    {\n\t    // the predicate that determines whether the resolver \n        // is able to resolve the requested service or not.\n        return IsUsableFor(typeInfo);\n    }\n}\n```\nThen you can register your custom wrapper or resolver like this:\n```cs\ncontainer.RegisterResolver(new CustomWrapper());\ncontainer.RegisterResolver(new CustomResolver());\n```\n\n## Visiting order\nStashbox visits the wrappers and resolvers in the following order to satisfy the actual resolution request:\n\n1. `EnumerableWrapper`\n2. `LazyWrapper`\n3. `FuncWrapper`\n4. `MetadataWrapper`\n5. `KeyValueWrapper`\n6. **Custom, user-defined wrappers & resolvers**\n7. `ServiceProviderResolver`\n8. `OptionalValueResolver`\n9. `DefaultValueResolver`\n10. `ParentContainerResolver`\n11. `UnknownTypeResolver`"
  },
  {
    "path": "docs/docs/configuration/container-configuration.md",
    "content": "import CodeDescPanel from '@site/src/components/CodeDescPanel';\nimport Tabs from '@theme/Tabs'; \nimport TabItem from '@theme/TabItem';\n\n# Container configuration\n\n<CodeDescPanel>\n<div>\n\nThe container's constructor has an `Action<T>` parameter used to configure its behavior.\n\nThe configuration API is fluent, which means you can chain the configuration methods after each other.\n\n</div>\n<div>\n\n```cs\nvar container = new StashboxContainer(options => options\n    .WithDisposableTransientTracking()\n    .WithConstructorSelectionRule(Rules.ConstructorSelection.PreferLeastParameters)\n    .WithRegistrationBehavior(Rules.RegistrationBehavior.ThrowException));\n```\n\n</div>\n</CodeDescPanel>\n\n<CodeDescPanel>\n<div>\n\n**Re-configuration** of the container is also supported by calling its `.Configure()` method.\n\n</div>\n<div>\n\n```cs\nvar container = new StashboxContainer();\ncontainer.Configure(options => options.WithDisposableTransientTracking());\n```\n\n</div>\n</CodeDescPanel>\n\n\n## Default configuration\nThese features are set by default:\n\n- [Constructor selection](/docs/configuration/container-configuration#constructor-selection): `Rules.ConstructorSelection.PreferMostParameters`\n- [Registration behavior](/docs/configuration/container-configuration#registration-behavior): `Rules.RegistrationBehavior.SkipDuplications`\n- [Default lifetime](/docs/configuration/container-configuration#default-lifetime): `Lifetimes.Transient`\n\n\n## Tracking disposable transients\n<CodeDescPanel>\n<div>\n\nWith this option, you can enable or disable the tracking of disposable transient objects.\n\n</div>\n<div>\n\n```cs\nnew StashboxContainer(options => options\n    .WithDisposableTransientTracking());\n```\n\n</div>\n</CodeDescPanel>\n\n## Auto member-injection\nWith this option, you can enable or disable the auto member-injection without [attributes](/docs/guides/service-resolution#attributes).\n\n<CodeDescPanel>\n<div>\n\n### `PropertiesWithPublicSetter`\nWith this flag, the container will perform auto-injection on properties with public setters.\n\n</div>\n<div>\n\n```cs\nnew StashboxContainer(options => options\n    .WithAutoMemberInjection(\n        Rules.AutoMemberInjectionRules.PropertiesWithPublicSetter));\n```\n\n</div>\n</CodeDescPanel>\n\n<CodeDescPanel>\n<div>\n\n### `PropertiesWithLimitedAccess`\nWith this flag, the container will perform auto-injection on properties even when they don't have a public setter.\n\n</div>\n<div>\n\n```cs\nnew StashboxContainer(options => options\n    .WithAutoMemberInjection(\n        Rules.AutoMemberInjectionRules.PropertiesWithLimitedAccess));\n```\n\n</div>\n</CodeDescPanel>\n\n<CodeDescPanel>\n<div>\n\n### `PrivateFields`\nWith this flag, the container will perform auto-injection on private fields too.\n\n</div>\n<div>\n\n```cs\nnew StashboxContainer(options => options\n    .WithAutoMemberInjection(\n        Rules.AutoMemberInjectionRules.PrivateFields));\n```\n\n</div>\n</CodeDescPanel>\n\n<CodeDescPanel>\n<div>\n\n### Combined rules\nYou can also combine these flags with bitwise logical operators to get a merged ruleset.\n\n</div>\n<div>\n\n```cs\nnew StashboxContainer(options => options\n    .WithAutoMemberInjection(Rules.AutoMemberInjectionRules.PrivateFields | \n        Rules.AutoMemberInjectionRules.PropertiesWithPublicSetter));\n```\n\n</div>\n</CodeDescPanel>\n\n<CodeDescPanel>\n<div>\n\n#### Member selection filter\nYou can pass your own member selection logic to control which members should be auto injected.\n\n</div>\n<div>\n\n```cs\nnew StashboxContainer(options => options\n    .WithAutoMemberInjection(\n        filter: member => member.Type != typeof(ILogger)));\n```\n\n</div>\n</CodeDescPanel>\n\n## Required member injection\n<CodeDescPanel>\n<div>\n\nWith this option, you can enable or disable the auto injection of members defined with C# 11's [`required`](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/required) keyword.\n\n</div>\n<div>\n\n```cs\nnew StashboxContainer(options => options\n    .WithRequiredMemberInjection(enabled: false));\n```\n\n</div>\n</CodeDescPanel>\n\n:::note\nThe required member injection option is **enabled** by default.\n:::\n\n## Constructor selection\nWith this option, you can set the constructor selection rule used to determine which constructor the container should use for instantiation.\n<CodeDescPanel>\n<div>\n\n### `PreferMostParameters`\nIt prefers the constructor which has the most extended parameter list.\n\n</div>\n<div>\n\n```cs\nnew StashboxContainer(options => options\n    .WithConstructorSelectionRule(\n        Rules.ConstructorSelection.PreferMostParameters));\n```\n\n</div>\n</CodeDescPanel>\n\n<CodeDescPanel>\n<div>\n\n### `PreferLeastParameters`\nIt prefers the constructor which has the shortest parameter list.\n\n</div>\n<div>\n\n```cs\nnew StashboxContainer(options => options\n    .WithConstructorSelectionRule(\n        Rules.ConstructorSelection.PreferLeastParameters));\n```\n\n</div>\n</CodeDescPanel>\n\n## Registration behavior\nWith this option, you can set the actual behavior used when a new service is registered into the container. These options do not affect named registrations.\n<CodeDescPanel>\n<div>\n\n### `SkipDuplications`\nThe container will skip new registrations when the given [implementation type](/docs/getting-started/glossary#service-type--implementation-type) is already registered.\n\n</div>\n<div>\n\n```cs\nnew StashboxContainer(options => options\n    .WithRegistrationBehavior(\n        Rules.RegistrationBehavior.SkipDuplications));\n```\n\n</div>\n</CodeDescPanel>\n\n<CodeDescPanel>\n<div>\n\n### `ThrowException`\nThe container throws an [exception](/docs/diagnostics/validation#servicealreadyregisteredexception) when the given [implementation type](/docs/getting-started/glossary#service-type--implementation-type) is already registered.\n\n</div>\n<div>\n\n```cs\nnew StashboxContainer(options => options\n    .WithRegistrationBehavior(\n        Rules.RegistrationBehavior.ThrowException));\n```\n\n</div>\n</CodeDescPanel>\n\n<CodeDescPanel>\n<div>\n\n### `ReplaceExisting`\nThe container will replace the already [registered service](/docs/getting-started/glossary#service-registration--registered-service) with the given one when they have the same [implementation type](/docs/getting-started/glossary#service-type--implementation-type).\n\n</div>\n<div>\n\n```cs\nnew StashboxContainer(options => options\n    .WithRegistrationBehavior(\n        Rules.RegistrationBehavior.ReplaceExisting));\n```\n\n</div>\n</CodeDescPanel>\n\n<CodeDescPanel>\n<div>\n\n### `PreserveDuplications`\nThe container will keep registering the new services with the same [implementation type](/docs/getting-started/glossary#service-type--implementation-type).\n\n</div>\n<div>\n\n```cs\nnew StashboxContainer(options => options\n    .WithRegistrationBehavior(\n        Rules.RegistrationBehavior.PreserveDuplications));\n```\n\n</div>\n</CodeDescPanel>\n\n\n## Default lifetime\n<CodeDescPanel>\n<div>\n\nWith this option, you can set the default lifetime used when a service doesn't have a configured one.\n\n</div>\n<div>\n\n```cs\nnew StashboxContainer(options => options\n    .WithDefaultLifetime(Lifetimes.Scoped));\n```\n\n</div>\n</CodeDescPanel>\n\n\n## Lifetime validation\n<CodeDescPanel>\n<div>\n\nWith this option, you can enable or disable the life-span and [root scope](/docs/getting-started/glossary#root-scope) resolution [validation](/docs/diagnostics/validation#lifetime-validation) on the dependency tree.\n\n</div>\n<div>\n\n```cs\nnew StashboxContainer(options => options\n    .WithLifetimeValidation());\n```\n\n</div>\n</CodeDescPanel>\n\n## Generic variance\n<CodeDescPanel>\n<div>\n\nWith this option, you can enable or disable the check for [generic covariance and contravariance](/docs/advanced/generics#variance) during the resolution of generic type collections. \n\n_This option is enabled by default_.\n\n</div>\n<div>\n\n```cs\nnew StashboxContainer(options => options\n    .WithVariantGenericTypes());\n```\n\n</div>\n</CodeDescPanel>\n\n## Empty collection handling\n<CodeDescPanel>\n<div>\n\nWith this option, you can enable or disable the throwing of a `ResolutionFailedException` when no services are found for a collection resolution request. When this feature is disabled _(default)_, the container returns an empty array for those request.\n\n</div>\n<div>\n\n```cs\nnew StashboxContainer(options => options\n    .WithExceptionOverEmptyCollection());\n```\n\n</div>\n</CodeDescPanel>\n\n## Conventional resolution\n<CodeDescPanel>\n<div>\n\nWith this option, you can enable or disable conventional resolution, which means the container treats the constructor/method parameter or member names as dependency names used by [named resolution](/docs/getting-started/glossary#named-resolution).\n\n</div>\n<div>\n\n```cs\nnew StashboxContainer(options => options\n    .TreatParameterAndMemberNameAsDependencyName());\n```\n\n</div>\n</CodeDescPanel>\n\n## Using named service for un-named requests\n<CodeDescPanel>\n<div>\n\nWith this option, you can enable or disable the selection of named registrations when the resolution request is un-named but with the same type.\n\nThe `enabledForCollectionRequests` argument controls whether named registrations should be returned for an unnamed collection resolution request. It's **enabled** by default.\n</div>\n<div>\n\n```cs\nnew StashboxContainer(options => options\n    .WithNamedDependencyResolutionForUnNamedRequests(\n        enabled: true,\n        enabledForCollectionRequests: true\n    ));\n```\n\n</div>\n</CodeDescPanel>\n\n## Named service resolution\n<CodeDescPanel>\n<div>\n\n### `WithUniversalName`\nSets the universal name that represents a special name which allows named resolution work for any given name.\n\n</div>\n<div>\n\n```cs\nnew StashboxContainer(options => options\n    .WithUniversalName(\"Any\"));\n```\n\n</div>\n</CodeDescPanel>\n\n<CodeDescPanel>\n<div>\n\n### `WithAdditionalDependencyNameAttribute`\nAdds an attribute type that is considered a dependency name indicator just like the [`DependencyName` attribute](/docs/guides/service-resolution#attributes).\n\n</div>\n<div>\n\n```cs\nnew StashboxContainer(options => options\n    .WithAdditionalDependencyNameAttribute<CustomNameAttribute>());\n```\n\n</div>\n</CodeDescPanel>\n\n<CodeDescPanel>\n<div>\n\n### `WithAdditionalDependencyAttribute`\nAdds an attribute type that is considered a dependency indicator just like the [`Dependency` attribute](/docs/guides/service-resolution#attributes).\n\n</div>\n<div>\n\n```cs\nnew StashboxContainer(options => options\n    .WithAdditionalDependencyAttribute<CustomDependencyAttribute>());\n```\n\n</div>\n</CodeDescPanel>\n\n<CodeDescPanel>\n<div>\n\n### `WithIgnoreServicesWithUniversalNameForUniversalNamedRequests`\nEnables or disables the selection of services with `UniversalName` for a universal named resolution request.\n\n</div>\n<div>\n\n```cs\nnew StashboxContainer(options => options\n    .WithIgnoreServicesWithUniversalNameForUniversalNamedRequests());\n```\n\n</div>\n</CodeDescPanel>\n\n<CodeDescPanel>\n<div>\n\n### `WithForceThrowWhenNamedDependencyIsNotResolvable`\nEnables or disables throwing a `ResolutionFailedException` when a named dependency is not resolvable. Requests initiated by `.ResolveOrDefault()` may also throw when a named subdependency is not resolvable for example through the `Dependency` attribute.\n\n</div>\n<div>\n\n```cs\nnew StashboxContainer(options => options\n    .WithForceThrowWhenNamedDependencyIsNotResolvable());\n```\n\n</div>\n</CodeDescPanel>\n\n## Overriding the exception thrown upon resolution failure\n\n<CodeDescPanel>\n<div>\n\nWith this option, you can override the default `ResolutionFailedException` type thrown when the service resolution fails.\nThe details of the exception remain the same, only the type gets overridden.\n\n</div>\n<div>\n\n```cs\nnew StashboxContainer(options => options\n    .OverrideResolutionFailedExceptionWith<InvalidOperationException>());\n```\n\n</div>\n</CodeDescPanel>\n\n## Default value injection\n<CodeDescPanel>\n<div>\n\nWith this option, you can enable or disable the default value injection.\n\n</div>\n<div>\n\n```cs\nnew StashboxContainer(options => options\n    .WithDefaultValueInjection());\n```\n\n</div>\n</CodeDescPanel>\n\n\n## Unknown type resolution\n<CodeDescPanel>\n<div>\n\nWith this option, you can enable or disable the resolution of unregistered types. You can also use a configurator delegate to configure the registrations the container will create from the unknown types.\n\n</div>\n<div>\n\n```cs\nnew StashboxContainer(options => options\n    .WithUnknownTypeResolution(config => config.AsImplementedTypes()));\n```\n\n</div>\n</CodeDescPanel>\n\n\n## Custom compiler\n<CodeDescPanel>\n<div>\n\nWith this option, you can set an external expression tree compiler. It can be useful on platforms where the IL generator modules are not available; therefore, the expression compiler in Stashbox couldn't work.\n\n</div>\n<div>\n\n```cs\nnew StashboxContainer(options => options\n    .WithExpressionCompiler(\n        Rules.ExpressionCompilers.MicrosoftExpressionCompiler));\n```\n\n</div>\n</CodeDescPanel>\n\n\n## Re-build singletons in child containers\n<CodeDescPanel>\n<div>\n\nWith this option, you can enable or disable the re-building of singletons in child containers. It allows the child containers to override singleton dependencies in the parent.\n\n</div>\n<div>\n\n```cs\nnew StashboxContainer(options => options\n    .WithReBuildSingletonsInChildContainer());\n```\n\n</div>\n</CodeDescPanel>\n\n\n:::note\nThis feature is not affecting the already built singleton instances in the parent.\n:::"
  },
  {
    "path": "docs/docs/configuration/registration-configuration.md",
    "content": "import CodeDescPanel from '@site/src/components/CodeDescPanel';\nimport Tabs from '@theme/Tabs'; \nimport TabItem from '@theme/TabItem';\n\n# Registration configuration\n\n<CodeDescPanel>\n<div>\n\nMost of the registration methods have an `Action<TOptions>` parameter, enabling several customization options on the given registration.\n\nHere are three examples that show how the API's usage looks like. \nThey cover the exact functionalities you've read about in the [basics](/docs/guides/basics) section but are achieved with the options API.\n\n</div>\n<div>\n\n<Tabs>\n<TabItem value=\"Named\" label=\"Named\">\n\nThis is how you can use the options API to set a registration's name:\n```cs\ncontainer.Register<IJob, DbBackup>(options => options\n    .WithName(\"DbBackup\"));\n```\n\n</TabItem>\n<TabItem value=\"Lifetime\" label=\"Lifetime\">\n\nIt was mentioned in the [Lifetime shortcuts](/docs/guides/basics#lifetime-shortcuts) section, that those methods are only sugars; under the curtain, they are also using this API:\n```cs\ncontainer.Register<IJob, DbBackup>(options => options\n    .WithLifetime(Lifetimes.Singleton));\n```\n\n</TabItem>\n<TabItem value=\"Instance\" label=\"Instance\">\n\nAn example of how you can register an instance with the options API:\n```cs\ncontainer.Register<IJob, DbBackup>(options => options\n    .WithInstance(new DbBackup()));\n```\n\n</TabItem>\n</Tabs>\n</div>\n</CodeDescPanel>\n\n<CodeDescPanel>\n<div>\n\nThe registration configuration API is fluent, which means all option methods can be chained after each other. \nThis provides an easier way to configure complicated registrations.\n\n</div>\n<div>\n\n```cs\ncontainer.Register<IJob, DbBackup>(options => options\n    .WithName(\"DbBackup\")\n    .WithLifetime(Lifetimes.Singleton)\n    .WithoutDisposalTracking());\n```\n\n</div>\n</CodeDescPanel>\n\n## General options\n\n<CodeDescPanel>\n<div>\n\n### `WithName`\nSets the name identifier of the registration.\n\n</div>\n<div>\n\n```cs\ncontainer.Register<ILogger, ConsoleLogger>(config => config\n    .WithName(\"Console\"));\n```\n\n</div>\n</CodeDescPanel>\n\n<CodeDescPanel>\n<div>\n\n### `WithInstance`\nSets an existing instance for the registration. \n\nPassing true for the `wireUp` parameter means that the container performs member / method injection on the registered instance.\n\n</div>\n<div>\n\n<Tabs>\n<TabItem value=\"Instance\" label=\"Instance\">\n\n```cs\ncontainer.Register<ILogger>(options => options\n    .WithInstance(new ConsoleLogger()));\n```\n\n</TabItem>\n<TabItem value=\"WireUp\" label=\"WireUp\">\n\n```cs\ncontainer.Register<ILogger>(options => options\n    .WithInstance(new ConsoleLogger(), wireUp: true));\n```\n\n</TabItem>\n</Tabs>\n</div>\n</CodeDescPanel>\n\n<CodeDescPanel>\n<div>\n\n### `WithoutDisposalTracking`\nForce disables the disposal tracking on the registration.\n\n</div>\n<div>\n\n```cs\ncontainer.Register<ILogger, ConsoleLogger>(options => options\n    .WithoutDisposalTracking());\n```\n\n</div>\n</CodeDescPanel>\n\n\n<CodeDescPanel>\n<div>\n\n### `WithMetadata`\nSets additional metadata for the registration. It's attached to the service upon its resolution through `ValueTuple<,>`, `Tuple<,>`, or `Metadata<,>` wrappers.\n\n</div>\n<div>\n\n```cs\ncontainer.Register<IJob, DbBackup>(options => options\n    .WithMetadata(connectionString));\n\nvar jobWithConnectionString = container.Resolve<ValueTuple<IJob, string>>();\nConsole.WriteLine(jobWithConnectionString.Item2); // prints the connection string.\n\n```\n\n</div>\n</CodeDescPanel>\n\n\n<CodeDescPanel>\n<div>\n\n### `WithDynamicResolution`\nIndicates that the service's resolution should be handled by a dynamic `Resolve()` call on the current `IDependencyResolver` instead of a pre-built instantiation expression.\n\n</div>\n<div>\n\n```cs\ncontainer.Register<IJob, DbBackup>();\ncontainer.Register<ILogger, ConsoleLogger>(options => options\n    .WithDynamicResolution());\n\n// new DbBackup(currentScope.Resolve<ILogger>());\nvar job = container.Resolve<IJob>();\n\n```\n\n</div>\n</CodeDescPanel>\n\n<CodeDescPanel>\n<div>\n\n### `HasServiceType`\nUsed to build conditions based on service type in batch/assembly registrations.\nIt determines whether the registration is mapped to the given service type.\n\n</div>\n<div>\n\n```cs\ncontainer.RegisterAssemblyContaining<IService1>(configurator: options =>\n    {\n        if (options.HasServiceType<IService2>())\n            options.WithScopedLifetime();\n    });\n\n```\n\n</div>\n</CodeDescPanel>\n\n## Initializer / finalizer\n<CodeDescPanel>\n<div>\n\n### `WithFinalizer`\nSets a custom cleanup delegate that will be invoked when the scope / container holding the instance is being disposed.\n\n</div>\n<div>\n\n```cs\ncontainer.Register<ILogger, FileLogger>(options => options\n    .WithFinalizer(logger => logger\n        .CloseFile()));\n```\n\n</div>\n</CodeDescPanel>\n\n<CodeDescPanel>\n<div>\n\n### `WithInitializer`\nSets a custom initializer delegate that will be invoked when the given service is being instantiated.\n\n</div>\n<div>\n\n```cs\ncontainer.Register<ILogger, FileLogger>(options => options\n    .WithInitializer((logger, resolver) => logger\n        .OpenFile()));\n```\n\n</div>\n</CodeDescPanel>\n\n\n## Replace\n\n<Tabs>\n<TabItem value=\"ReplaceExisting\" label=\"ReplaceExisting\">\n\nIndicates whether the container should replace an existing registration with the current one (based on [implementation type](/docs/getting-started/glossary#service-type--implementation-type) and name). If there's no existing registration in place, the actual one will be added to the registration list.\n```cs\ncontainer.Register<ILogger, ConsoleLogger>(options => options\n    .ReplaceExisting());\n```\n\n</TabItem>\n<TabItem value=\"ReplaceOnlyIfExists\" label=\"ReplaceOnlyIfExists\">\n\nThe same as `ReplaceExisting()` except that the container will do the replace only when there's an already [registered service](/docs/getting-started/glossary#service-registration--registered-service) with the same type or name.\n```cs\ncontainer.Register<ILogger, ConsoleLogger>(options => options\n    .ReplaceOnlyIfExists());\n```\n\n</TabItem>\n</Tabs>\n\n## Multiple services\nYou can read more about binding a registration to multiple services [here](/docs/guides/advanced-registration#binding-to-multiple-services).\n<CodeDescPanel>\n<div>\n\n### `AsImplementedTypes`\nThe service will be mapped to all of its implemented interfaces and base types.\n\n</div>\n<div>\n\n```cs\ncontainer.Register<IUserRepository, UserRepository>(options => options\n    .AsImplementedTypes());\n```\n\n</div>\n</CodeDescPanel>\n\n<CodeDescPanel>\n<div>\n\n### `AsServiceAlso`\nBinds the currently configured registration to an additional [service type](/docs/getting-started/glossary#service-type--implementation-type). The registered type must implement or extend the additional [service type](/docs/getting-started/glossary#service-type--implementation-type).\n\n</div>\n<div>\n\n```cs\ncontainer.Register<IUserRepository, UserRepository>(options => options\n    .AsServiceAlso<IRepository>()\n    // or\n    .AsServiceAlso(typeof(IRepository)));\n```\n\n</div>\n</CodeDescPanel>\n\n## Dependency configuration\nThese options allows the same configuration functionality as the [dependency attribute](/docs/guides/service-resolution#attributes). \n\n<Tabs>\n<TabItem value=\"By parameter type\" label=\"By parameter type\">\n\nBinds a constructor / method parameter or a property / field to a named registration by the parameter's type. The container will perform a [named resolution](/docs/getting-started/glossary#named-resolution) on the bound dependency. The second parameter used to set the name of the dependency.\n```cs\ncontainer.Register<IUserRepository, UserRepository>(options => options\n    .WithDependencyBinding(typeof(ILogger), \"FileLogger\"));\n```\n\n</TabItem>\n<TabItem value=\"By parameter name\" label=\"By parameter name\">\n\nBinds a constructor / method parameter or a property / field to a named registration by the parameter's name. The container will perform a [named resolution](/docs/getting-started/glossary#named-resolution) on the bound dependency. The second parameter used to set the name of the dependency.\n```cs\ncontainer.Register<IUserRepository, UserRepository>(options => options\n    .WithDependencyBinding(\"logger\", \"FileLogger\"));\n```\n\n</TabItem>\n<TabItem value=\"By expression\" label=\"By expression\">\n\nMarks a member (property / field) as a dependency that should be filled by the container. The second parameter used to set the name of the dependency.\n```cs\ncontainer.Register<IUserRepository, UserRepository>(options => options\n    .WithDependencyBinding(logger => logger.Logger, \"ConsoleLogger\"));\n```\n\n</TabItem>\n</Tabs>\n\n## Lifetime\nYou can read more about lifetimes [here](/docs/guides/lifetimes).\n\n<CodeDescPanel>\n<div>\n\n### `WithSingletonLifetime`\nSets a singleton lifetime for the registration.\n\n</div>\n<div>\n\n```cs\ncontainer.Register<ILogger, ConsoleLogger>(config => config\n    .WithSingletonLifetime());\n```\n\n</div>\n</CodeDescPanel>\n\n<CodeDescPanel>\n<div>\n\n### `WithScopedLifetime`\nSets a scoped lifetime for the registration.\n\n</div>\n<div>\n\n```cs\ncontainer.Register<ILogger, ConsoleLogger>(config => config\n    .WithScopedLifetime());\n```\n\n</div>\n</CodeDescPanel>\n\n<CodeDescPanel>\n<div>\n\n### `WithPerRequestLifetime`\nSets the lifetime to `PerRequestLifetime`. This lifetime will create a new instance between resolution requests. Within the request the same instance will be re-used.\n\n</div>\n<div>\n\n```cs\ncontainer.Register<ILogger, ConsoleLogger>(options => options\n    .WithPerRequestLifetime());\n```\n\n</div>\n</CodeDescPanel>\n\n<CodeDescPanel>\n<div>\n\n### `WithAutoLifetime`\nSets the lifetime to auto lifetime. This lifetime aligns to the lifetime of the resolved service's dependencies. When the underlying service has a dependency with a higher lifespan, this lifetime will inherit that lifespan up to a given boundary.\n\n</div>\n<div>\n\n```cs\ncontainer.Register<ILogger, ConsoleLogger>(options => options\n    .WithAutoLifetime(Lifetimes.Scoped /* boundary lifetime */));\n```\n\n</div>\n</CodeDescPanel>\n\n<CodeDescPanel>\n<div>\n\n### `WithLifetime`\nSets a custom lifetime for the registration.\n\n</div>\n<div>\n\n```cs\ncontainer.Register<ILogger, ConsoleLogger>(config => config\n    .WithLifetime(new CustomLifetime()));\n```\n\n</div>\n</CodeDescPanel>\n\n## Conditions\nYou can read more about the concept of conditional resolution [here](/docs/guides/service-resolution#conditional-resolution).\n\n<CodeDescPanel>\n<div>\n\n### `WhenHas`\nSets an attribute condition for the registration.\n\n</div>\n<div>\n\n```cs\ncontainer.Register<ILogger, ConsoleLogger>(config => config\n    .WhenHas<ConsoleAttribute>());\n```\n\n</div>\n</CodeDescPanel>\n\n<CodeDescPanel>\n<div>\n\n### `WhenResolutionPathHas`\nSets a resolution path condition for the registration. The service will be selected only in the resolution path of the target that has the given attribute.\nThis means that only the direct and sub-dependencies of the target type that has the given attribute will get the configured service.\n\n</div>\n<div>\n\n```cs\ncontainer.Register<ILogger, ConsoleLogger>(config => config\n    // Each direct and sub-dependency of any service that has\n    // a ConsoleAttribute will get FileLogger wherever they \n    // depend on ILogger. \n    .WhenResolutionPathHas<ConsoleAttribute>());\n```\n\n</div>\n</CodeDescPanel>\n\n<CodeDescPanel>\n<div>\n\n### `WhenDependantIs`\nSets a parent target condition for the registration.\n\n</div>\n<div>\n\n```cs\ncontainer.Register<ILogger, FileLogger>(config => config\n    .WhenDependantIs<UserRepository>());\n```\n\n</div>\n</CodeDescPanel>\n\n<CodeDescPanel>\n<div>\n\n### `WhenInResolutionPathOf`\nSets a resolution path condition for the registration. The service will be selected only in the resolution path of the given target.\nThis means that only the direct and sub-dependencies of the target type will get the configured service.\n\n</div>\n<div>\n\n```cs\ncontainer.Register<ILogger, FileLogger>(config => config\n    // Each direct and sub-dependency of UserRepository\n    // will get FileLogger wherever they depend on ILogger. \n    .WhenInResolutionPathOf<UserRepository>());\n```\n\n</div>\n</CodeDescPanel>\n\n<CodeDescPanel>\n<div>\n\n### `When`\nSets a custom user-defined condition for the registration.\n\n</div>\n<div>\n\n```cs\ncontainer.Register<ILogger, FileLogger>(config => config\n    .When(typeInfo => typeInfo.ParentType == typeof(UserRepository)));\n```\n\n</div>\n</CodeDescPanel>\n\n\n## Constructor selection\n<CodeDescPanel>\n<div>\n\n### `WithConstructorSelectionRule`\nSets the constructor selection rule for the registration.\n\n</div>\n<div>\n\n```cs\ncontainer.Register<ILogger>(options => options\n    .WithConstructorSelectionRule(...));\n```\n\n</div>\n</CodeDescPanel>\n\n<CodeDescPanel>\n<div>\n\n#### PreferMostParameters\nSelects the constructor which has the longest parameter list.\n\n</div>\n<div>\n\n```cs\noptions.WithConstructorSelectionRule(\n    Rules.ConstructorSelection.PreferMostParameters)\n```\n\n</div>\n</CodeDescPanel>\n\n<CodeDescPanel>\n<div>\n\n#### PreferLeastParameters\nSelects the constructor which has the shortest parameter list.\n\n</div>\n<div>\n\n```cs\noptions.WithConstructorSelectionRule(\n    Rules.ConstructorSelection.PreferLeastParameters)\n```\n\n</div>\n</CodeDescPanel>\n\n<CodeDescPanel>\n<div>\n\n#### Custom\nYou can set your own custom constructor ordering logic.\n\n</div>\n<div>\n\n```cs\noptions.WithConstructorSelectionRule(\n    constructors => { /* custom constructor sorting logic */ })\n```\n\n</div>\n</CodeDescPanel>\n\n<CodeDescPanel>\n<div>\n\n### `WithConstructorByArgumentTypes`\nSelects a constructor by its argument types.\n\n</div>\n<div>\n\n```cs\ncontainer.Register<IUserRepository, UserRepository>(options => options\n    .WithConstructorByArgumentTypes(typeof(ILogger)));\n```\n\n</div>\n</CodeDescPanel>\n\n<CodeDescPanel>\n<div>\n\n### `WithConstructorByArguments`\nSelects a constructor by its arguments to use during resolution. These arguments are used to invoke the selected constructor.\n\n</div>\n<div>\n\n```cs\ncontainer.Register<IUserRepository, UserRepository>(options => options\n    .WithConstructorByArguments(new ConsoleLogger()));\n```\n\n</div>\n</CodeDescPanel>\n\n\n\n## Property / field Injection\n<CodeDescPanel>\n<div>\n\n### `WithAutoMemberInjection`\nEnables the auto member injection and sets the rule for it.\n\n</div>\n<div>\n\n```cs\ncontainer.Register<IUserRepository, UserRepository>(options => options\n    .WithAutoMemberInjection(...));\n```\n\n</div>\n</CodeDescPanel>\n\n<CodeDescPanel>\n<div>\n\n#### PropertiesWithPublicSetter\nWith this flag, the container will perform auto-injection on properties with a public setter.\n\n</div>\n<div>\n\n```cs\noptions.WithAutoMemberInjection(\n    Rules.AutoMemberInjectionRules.PropertiesWithPublicSetter)\n```\n\n</div>\n</CodeDescPanel>\n\n<CodeDescPanel>\n<div>\n\n#### PropertiesWithLimitedAccess\nWith this flag, the container will perform auto-injection on properties which has a non-public setter as well.\n\n</div>\n<div>\n\n```cs\noptions.WithAutoMemberInjection(\n    Rules.AutoMemberInjectionRules.PropertiesWithLimitedAccess)\n```\n\n</div>\n</CodeDescPanel>\n\n<CodeDescPanel>\n<div>\n\n#### PrivateFields\nWith this flag, the container will perform auto-injection on private fields too.\n\n</div>\n<div>\n\n```cs\noptions.WithAutoMemberInjection(\n    Rules.AutoMemberInjectionRules.PrivateFields)\n```\n\n</div>\n</CodeDescPanel>\n\n<CodeDescPanel>\n<div>\n\n#### Combined rules\nAs these rules are [bit flags](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/enum#enumeration-types-as-bit-flags), you can use them combined together with bitwise logical operators.\n\n</div>\n<div>\n\n```cs\noptions.WithAutoMemberInjection(Rules.AutoMemberInjectionRules.PrivateFields | \n    Rules.AutoMemberInjectionRules.PropertiesWithPublicSetter)\n```\n\n</div>\n</CodeDescPanel>\n\n<CodeDescPanel>\n<div>\n\n#### Member selection filter\nYou can pass your own member selection logic to control which members should be auto injected.\n\n</div>\n<div>\n\n```cs\ncontainer.Register<ILogger, ConsoleLogger>(options => options\n    .WithAutoMemberInjection(filter: member => member.Type != typeof(ILogger)));\n```\n\n</div>\n</CodeDescPanel>\n\n## Required member injection\n<CodeDescPanel>\n<div>\n\nWith this option, you can enable or disable the auto injection of members defined with C# 11's [`required`](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/required) keyword.\n\n</div>\n<div>\n\n```cs\ncontainer.Register<IUserRepository, UserRepository>(options => options\n    .WithRequiredMemberInjection(enabled: false));\n```\n\n</div>\n</CodeDescPanel>\n\n:::note\nThe required member injection option is **enabled** by default.\n:::\n\n\n## Injection parameters\n<CodeDescPanel>\n<div>\n\n### `WithInjectionParameters`\nSets multiple injection parameters for the registration.\n\n</div>\n<div>\n\n```cs\ncontainer.Register<IUserRepository, UserRepository>(options => options\n    .WithInjectionParameters(new KeyValuePair<string, object>(\"logger\", new ConsoleLogger()));\n```\n\n</div>\n</CodeDescPanel>\n\n<CodeDescPanel>\n<div>\n\n### `WithInjectionParameter`\nSets a single injection parameter for the registration.\n\n</div>\n<div>\n\n```cs\ncontainer.Register<IUserRepository, UserRepository>(options => options\n    .WithInjectionParameter(\"logger\", new ConsoleLogger());\n```\n\n</div>\n</CodeDescPanel>\n\n\n## Factory\nYou can read more about the concept of factory registration [here](/docs/guides/advanced-registration?id=factory-registration).\n\n<Tabs>\n<TabItem value=\"Parameterized\" label=\"Parameterized\">\n\n**WithFactory** - Sets a factory delegate that could take various number of pre-resolved dependencies as parameters and returns the service instance.\n```cs\n// 1 parameter factory\ncontainer.Register<IUserRepository, UserRepository>(options => options\n    .WithFactory<ILogger>(logger => new UserRepository(logger));\n\n// 2 parameters factory\ncontainer.Register<IUserRepository, UserRepository>(options => options\n    .WithFactory<ILogger, IDbContext>((logger, context) => new UserRepository(logger, context));\n\n// 3 parameters factory\ncontainer.Register<IUserRepository, UserRepository>(options => options\n    .WithFactory<ILogger, IDbContext, IOptions>((logger, context, options) => \n        new UserRepository(logger, context, options));\n\n// 4 parameters factory\ncontainer.Register<IUserRepository, UserRepository>(options => options\n    .WithFactory<ILogger, IDbConnection, IOptions, IUserValidator>((logger, connection, options, validator) => \n        new UserRepository(logger, connection, options, validator));\n\n// 5 parameters factory\ncontainer.Register<IUserRepository, UserRepository>(options => options\n    .WithFactory<ILogger, IDbConnection, IOptions, IUserValidator, IPermissionManage>(\n        (logger, connection, options, validator, permissionManager) => \n            new UserRepository(logger, connection, options, validator, permissionManager));\n```\nYou can also get the current [dependency resolver](/docs/getting-started/glossary#dependency-resolver) as a pre-resolved parameter:\n```cs\ncontainer.Register<IUserRepository, UserRepository>(options => options\n    .WithFactory<ILogger, IDependencyResolver>((logger, resolver) => \n        new UserRepository(logger, resolver.Resolve<IDbConnection>())));\n```\n\n</TabItem>\n<TabItem value=\"Parameter-less\" label=\"Parameter-less\">\n\n**WithFactory** - Sets a parameter-less factory delegate that returns the service instance.\n```cs\ncontainer.Register<IUserRepository, UserRepository>(options => options\n    .WithFactory(()) => new UserRepository(new ConsoleLogger()));\n```\n\n</TabItem>\n<TabItem value=\"Resolver parameter\" label=\"Resolver parameter\">\n\n**WithFactory** - Sets a factory delegate that takes an `IDependencyResolver` as parameter and returns the service instance.\n```cs\ncontainer.Register<IUserRepository, UserRepository>(options => options\n    .WithFactory(resolver => new UserRepository(resolver.Resolve<ILogger>()));\n```\n\n</TabItem>\n</Tabs>\n\n:::info\nAll factory configuration method has an `isCompiledLambda` parameter which should be set to `true` if the passed delegate is compiled from an `Expression` tree.\n:::\n\n## Scope definition\nYou can read more about the concept of defined scopes [here](/docs/guides/scopes?id=service-as-scope).\n<CodeDescPanel>\n<div>\n\n### `InNamedScope`\nSets a scope name condition for the registration; it will be used only when a scope with the same name requests it.\n\n</div>\n<div>\n\n```cs\ncontainer.Register<IUserRepository, UserRepository>(options => options\n    .InNamedScope(\"UserRepo\"));\n```\n\n</div>\n</CodeDescPanel>\n\n<CodeDescPanel>\n<div>\n\n### `InScopeDefinedBy`\nSets a condition for the registration; it will be used only within the scope defined by the given type.\n\n</div>\n<div>\n\n```cs\ncontainer.Register<ILogger, ConsoleLogger>(options => options\n    .InScopeDefinedBy<UserRepository>());\ncontainer.Register<IUserRepository, UserRepository>(options => options\n    .DefinesScope());\n```\n\n</div>\n</CodeDescPanel>\n\n<CodeDescPanel>\n<div>\n\n### `DefinesScope`\nThis registration is used as a logical scope for it's dependencies. Dependencies registered with `InNamedScope()` with the same name are preferred during resolution. \nWhen the `name` is not set, the [service type](/docs/getting-started/glossary#service-type--implementation-type) is used as the name. Dependencies registered with `InScopeDefinedBy()` are selected.\n\n</div>\n<div>\n\n```cs\ncontainer.Register<IUserRepository, UserRepository>(options => options\n    .DefinesScope(\"UserRepo\"));\n\n// or\ncontainer.Register<IUserRepository, UserRepository>(options => options\n    .DefinesScope());\n```\n\n</div>\n</CodeDescPanel>\n\n\n## Decorator specific\nYou can read more about decorators [here](/docs/advanced/decorators).\n<CodeDescPanel>\n<div>\n\n### `WhenDecoratedServiceIs`\nSets a decorated target condition for the registration.\n\n</div>\n<div>\n\n```cs\ncontainer.RegisterDecorator<ILogger, LoggerDecorator>(options => options\n    .WhenDecoratedServiceIs<FileLogger>());\n```\n\n</div>\n</CodeDescPanel>\n\n<CodeDescPanel>\n<div>\n\n### `WhenDecoratedServiceHas`\nSets an attribute condition that the decorated target has to satisfy.\n\n</div>\n<div>\n\n```cs\ncontainer.RegisterDecorator<ILogger, LoggerDecorator>(options => options\n    .WhenDecoratedServiceHas<DetailedLoggingAttribute>());\n```\n\n</div>\n</CodeDescPanel>\n\n\n## Unknown registration specific\nYou can read more about unknown type resolution [here](/docs/advanced/special-resolution-cases#unknown-type-resolution).\n<CodeDescPanel>\n<div>\n\n### `SetImplementationType`\nSets the current registration's [implementation type](/docs/getting-started/glossary#service-type--implementation-type).\n\n</div>\n<div>\n\n```cs\nvar container = new StashboxContainer(c => c.WithUnknownTypeResolution(config =>\n{\n    if (config.ServiceType == typeof(IService))\n        config.SetImplementationType(typeof(Service));\n}));\n```\n\n</div>\n</CodeDescPanel>\n\n<CodeDescPanel>\n<div>\n\n### `Skip`\nMarks the current unknown type registration as skipped.\n\n</div>\n<div>\n\n```cs\nvar container = new StashboxContainer(c => c.WithUnknownTypeResolution(config =>\n{\n    if (config.ServiceType == typeof(IService))\n        config.Skip();\n}));\n```\n\n</div>\n</CodeDescPanel>\n"
  },
  {
    "path": "docs/docs/diagnostics/utilities.md",
    "content": "import CodeDescPanel from '@site/src/components/CodeDescPanel';\nimport Tabs from '@theme/Tabs'; \nimport TabItem from '@theme/TabItem';\n\n# Utilities\n\n## Is registered?\n\n<CodeDescPanel>\n<div>\n\nWith the `IsRegistered()` function, you can find out whether a service is registered into the container or not.\n\nIt returns `true` only when the container has a registration with the given type (and name). It only checks the actual container's registrations. For every cases, you should use the `CanResolve()` method.\n\n</div>\n<div>\n\n<Tabs groupId=\"generic-runtime-apis\">\n<TabItem value=\"Generic API\" label=\"Generic API\">\n\n```cs\nbool isIJobRegistered = container.IsRegistered<IJob>();\n```\n\n</TabItem>\n<TabItem value=\"Runtime type API\" label=\"Runtime type API\">\n\n```cs\nbool isIJobRegistered = container.IsRegistered(typeof(IJob));\n```\n\n</TabItem>\n<TabItem value=\"Named\" label=\"Named\">\n\n#### **Named**\n```cs\nbool isIJobRegistered = container.IsRegistered<IJob>(\"DbBackup\");\n```\n\n</TabItem>\n</Tabs>\n</div>\n</CodeDescPanel>\n\n## Can resolve?\n\n<CodeDescPanel>\n<div>\n\nThere might be cases when you are more interested in whether a service is resolvable from the container's actual state rather than finding out whether it's registered.\n\n`CanResolve()` returns `true` only when at least one of the following is true:\n- The requested type is registered in the current or one of the parent containers.\n- The requested type is a closed generic type, and its open generic definition is registered.\n- The requested type is a wrapper (`IEnumerable<>`, `Lazy<>`, `Func<>`, `KeyValuePair<,>`, `ReadOnlyKeyValue<,>`, `Metadata<,>`, `ValueTuple<,>`, or `Tuple<,>`), and the underlying type is registered.\n- The requested type is not registered, but it's resolvable, and [unknown type resolution](/docs/configuration/container-configuration#unknown-type-resolution) is enabled.\n\n</div>\n<div>\n\n<Tabs groupId=\"generic-runtime-apis\">\n<TabItem value=\"Generic API\" label=\"Generic API\">\n\n```cs\nbool isIJobResolvable = container.CanResolve<IJob>();\n```\n\n</TabItem>\n<TabItem value=\"Runtime type API\" label=\"Runtime type API\">\n\n```cs\nbool isIJobResolvable = container.CanResolve(typeof(IJob));\n```\n\n</TabItem>\n<TabItem value=\"Named\" label=\"Named\">\n\n```cs\nbool isIJobResolvable = container.CanResolve<IJob>(\"DbBackup\");\n```\n\n</TabItem>\n</Tabs>\n</div>\n</CodeDescPanel>\n\n## Get all mappings\n\n<CodeDescPanel>\n<div>\n\nYou can get all registrations in a key-value pair collection (where the key is the [service type](/docs/getting-started/glossary#service-type--implementation-type) and the value is the actual registration) by calling the `.GetRegistrationMappings()` method.\n\n</div>\n<div>\n\n```cs\nIEnumerable<KeyValuePair<Type, ServiceRegistration>> mappings = \n    container.GetRegistrationMappings();\n```\n\n</div>\n</CodeDescPanel>\n\n## Registration diagnostics\n\n<CodeDescPanel>\n<div>\n\nYou can get a much more readable version of the registration mappings by calling the `.GetRegistrationDiagnostics()` method.\n\n`RegistrationDiagnosticsInfo` has an overridden `.ToString()` method that returns the mapping details formatted in a human-readable form.\n\n</div>\n<div>\n\n```cs\ncontainer.Register<IJob, DbBackup>(\"DbBackupJob\");\ncontainer.Register(typeof(IEventHandler<>), typeof(EventHandler<>));\n\nIEnumerable<RegistrationDiagnosticsInfo> diagnostics = \n    container.GetRegistrationDiagnostics();\n\ndiagnostics.ForEach(Console.WriteLine);\n// output:\n// IJob => DbBackup, name: DbBackupJob\n// IEventHandler<> => EventHandler<>, name: null\n```\n\n</div>\n</CodeDescPanel>\n"
  },
  {
    "path": "docs/docs/diagnostics/validation.md",
    "content": "import Tabs from '@theme/Tabs'; \nimport TabItem from '@theme/TabItem';\n\n# Validation\n\nStashbox validation routines help you detect and solve common misconfiguration issues. You can verify the container's actual state with its `.Validate()` method. It walks through the whole [resolution tree](/docs/getting-started/glossary#resolution-tree) and collects all issues into an `AggregateException`.\n\n## Registration validation\n\nDuring registration, the container validates the passed types and throws the following exceptions when the validation fails.\n\n### InvalidRegistrationException\n1. **When the [implementation type](/docs/getting-started/glossary#service-type--implementation-type) is not resolvable.** (it's an interface or an abstract class registered like: `Register<IService>()`):\n  ```\n  The type Namespace.IService could not be resolved. It's probably an interface, abstract class, or primitive type.\n  ```\n2. **When the [implementation type](/docs/getting-started/glossary#service-type--implementation-type) does not implement the [service type](/docs/getting-started/glossary#service-type--implementation-type)**.\n  ```\n  The type Namespace.MotorCycle does not implement the '[service type](/docs/getting-started/glossary#service-type--implementation-type)' Namespace.ICar.\n  ```\n\n### ServiceAlreadyRegisteredException\n**When the given [implementation type](/docs/getting-started/glossary#service-type--implementation-type) is already registered** and the `RegistrationBehavior` [container configuration option](/docs/configuration/container-configuration#registration-behavior) is set to `ThrowException`:\n```\nThe type Namespace.Service is already registered.\n```\n\n## Resolution validation\nDuring the [resolution tree's](/docs/getting-started/glossary#resolution-tree) construction, the container continuously checks its actual state to ensure stability. When any of the following issues occur, the container throws a `ResolutionFailedException`.\n\n1. **When a dependency is missing from the [resolution tree](/docs/getting-started/glossary#resolution-tree)**.\n\n    <Tabs>\n    <TabItem value=\"Parameter\" label=\"Parameter\">\n\n    ```cs\n    class Service\n    {\n        public Service(Dependency dep) { }\n\n        public Service(Dependency2 dep2) { }\n    }\n\n    container.Register<Service>();\n    var service = container.Resolve<Service>();\n    ```\n    This will result in the following exception message:\n\n    ```\n    Could not resolve type Namespace.Service.\n    Constructor Void .ctor(Dependency) found with unresolvable parameter: (Namespace.Dependency)dep.\n    Constructor Void .ctor(Dependency2) found with unresolvable parameter: (Namespace.Dependency2)dep2.\n    ```\n\n    </TabItem>\n    <TabItem value=\"Property / field\" label=\"Property / field\">\n\n    ```cs\n    class Service\n    {\n        public Dependency Dep { get; set; }\n    }\n\n    container.Register<Service>(options => options.WithDependencyBinding(s => s.Dep));\n    var service = container.Resolve<Service>();\n    ```\n    This will show the following message:\n    ```\n    Could not resolve type Namespace.Service.\n    Unresolvable property: (Namespace.Dependency)Dep.\n    ```\n\n    </TabItem>\n    </Tabs>\n\n2. **When the requested type is unresolvable.** E.g., it doesn't have a public constructor.\n\n    ```\n    Could not resolve type Namespace.Service.\n    Service is not registered or unresolvable type requested.\n    ```\n\n## Lifetime validation\nThis validation enforces the following rules. When they are violated, the container throws a `LifetimeValidationFailedException`.\n\n1. **When a scoped service is requested from the [root scope](/docs/getting-started/glossary#root-scope)**.  \n   As the [root scope's](/docs/getting-started/glossary#root-scope) lifetime is bound to the container's lifetime, this action unintentionally promotes the scoped service's lifetime to singleton:\n  ```\n  Resolution of Namespace.Service (ScopedLifetime) from the '[root scope](/docs/getting-started/glossary#root-scope)' is not allowed, \n  that would promote the service's lifetime to a singleton.\n  ```\n\n2. **When the life-span of a dependency is shorter than its parent's**.  \n   It's called [captive dependency](https://blog.ploeh.dk/2014/06/02/captive-dependency/). Every lifetime has a `LifeSpan` value, which determines how long the related service lives. The main rule is that services may not contain dependencies with shorter life spans. E.g., singletons should not depend on scoped services. The only exception is the life span value `0`, which indicates that the related service is state-less and could be injected into any service. \n\n   These are the `LifeSpan` values of the pre-defined lifetimes: \n   - **Singleton**: 20\n   - **Scoped**: 10\n   - **NamedScope**: 10\n   - **PerRequest**: 0\n   - **Transient**: 0\n\n  In case of a failed validation the exception message would be:\n  ```\n  The life-span of Namespace.Service (ScopedLifetime|10) is shorter than \n  its direct or indirect parent's Namespace.Dependency (Singleton|20). \n  This could lead to incidental lifetime promotions with longer life-span, \n  it's recommended to double-check your lifetime configurations.\n  ```\n\n## Circular dependency\nWhen the container encounters a circular dependency loop in the [resolution tree](/docs/getting-started/glossary#resolution-tree), it throws a `ResolutionFailedException`.\n\n```cs\nclass Service1\n{\n    public Service1(Service2 service2) { }\n}\n\nclass Service2\n{\n    public Service2(Service1 service1) { }\n}\n\ncontainer.Register<Service1>();\ncontainer.Register<Service2>();\nvar service = container.Resolve<Service1>();\n```\nThe exception message is:  \n```\nCircular dependency was detected while resolving Namespace.Service1.\n```\n\n## Other exceptions\n### CompositionRootNotFoundException\nThis exception pops up when we try to compose an assembly, but it doesn't contain an `ICompositionRoot` implementation.\n```cs\ncontainer.ComposeAssembly(typeof(Service).Assembly);\n```\nThe exception message is:  \n```\nNo ICompositionRoot found in the given assembly: {your-assembly-name}\n```\n\n### ConstructorNotFoundException\nDuring the registration phase, when you are using the [`WithConstructorByArgumentTypes()`](/docs/configuration/registration-configuration#withconstructorbyargumenttypes) or [`WithConstructorByArguments()`](/docs/configuration/registration-configuration#withconstructorbyarguments) options, you can accidentally point to a non-existing constructor. In that case, the container throws a `ConstructorNotFoundException`.\n\n```cs\nclass Service\n{\n    public Service(Dependency dep) { }\n}\n\ncontainer.Register<Service>(options => options.WithConstructorByArgumentTypes(typeof(string), typeof(int)));\n```\nThe exception message is:  \n```\nConstructor not found for Namespace.Service with the given argument types: System.String, System.Int32.\n```"
  },
  {
    "path": "docs/docs/getting-started/glossary.md",
    "content": "import CodeDescPanel from '@site/src/components/CodeDescPanel'; \n\n# Glossary\n\nThe following terms and definitions are used in this documentation.\n\n## Service type | Implementation type\nThe *Service type* is usually an interface or an abstract class type used for service resolution or dependency injection. The *Implementation type* is the actual type registered to the *Service type*. A registration maps the *Service type* to an *Implementation type*. The *Implementation type* must implement or extend the *Service type*. \n\n<CodeDescPanel>\n<div>\n\nExample where a *Service type* is mapped to an *Implementation type*:\n\n</div>\n<div>\n\n```cs\ncontainer.Register<IService, Implementation>();\n```\n\n</div>\n</CodeDescPanel>\n\n<CodeDescPanel>\n<div>\n\nThe *Service type* used for requesting a service from the container:\n\n</div>\n<div>\n\n```cs\ncontainer.Resolve<IService>(); // returns Implementation\n```\n\n</div>\n</CodeDescPanel>\n\n## Service registration | Registered service\nIt's an entity created by Stashbox when a service is registered. The service registration stores required information about how to instantiate the service, e.g., reflected type information, name, lifetime, conditions, and more.\n\n<CodeDescPanel>\n<div>\n\nIn this example, we are registering a named service. The container will create a service registration entity to store the type mapping and the name. During resolution, the container will find the registration by checking for the *Service type* and the *name*.\n\n</div>\n<div>\n\n```cs\n// the registration entity will look like: \n// IService => Implementation, name: Example\ncontainer.Register<IService, Implementation>(\"Example\");\nvar service = container.Resolve<IService>(\"Example\");\n```\n\n</div>\n</CodeDescPanel>\n\n## Injectable dependency\n\n<CodeDescPanel>\n<div>\n\nIt's a constructor/method argument or a property/field of a registered *Implementation type* that gets evaluated (*injected*) by Stashbox during the service's construction.\n\nIn this example, `Implementation` has an `IDependency` *injectable dependency* in its constructor.\n\n</div>\n<div>\n\n```cs\nclass Implementation : IService\n{\n    public Implementation(IDependency dependency) \n    { }\n}\n```\n\n</div>\n</CodeDescPanel>\n\n## Resolution tree\nIt's the structural representation of a service's resolution process. It describes the instantiation order of the dependencies required to resolve the desired type.\n\nLet's see through an example:\n```cs\nclass A\n{\n    public A(B b, C c) { }\n}\n\nclass B\n{\n    public B(C c, D d) { }\n}\n\nclass C { }\nclass D { }\n```\nWhen we request the service `A`, the container constructs the following resolution tree based on the dependencies and sub-dependencies.\n```\n        A\n      /   \\\n     B     C\n   /   \\\n  C     D\n```\nThe container instantiates those services first that don't have any dependencies. `C` and `D` will be injected into `B`. Then, a new `C` is instantiated (if it's [transient](/docs/guides/lifetimes#transient-lifetime)) and injected into `A` along with the previously created `B`.\n\n## Dependency resolver\nIt's the container itself or the [current scope](/docs/guides/scopes), depending on which was asked to resolve a particular service. They are both implementing Stashbox's `IDependencyResolver` and the .NET framework's `IServiceProvider` interface and can be used for service resolution.\n\n:::info\nStashbox implicitly injects the [current scope](/docs/guides/scopes) wherever `IDependencyResolver` or `IServiceProvider` is requested.\n:::\n\n## Root scope\nIt's the [main scope](/docs/guides/scopes) created inside every container instance. It stores and handles the lifetime of all singletons. It's the base of each subsequent scope created by the container with the `.BeginScope()` method.\n\n:::caution\n[Scoped services](/docs/guides/lifetimes#scoped-lifetime) requested from the container (and not from a [scope](/docs/guides/scopes)) are managed by the root scope. This can lead to issues because their lifetime will effectively switch to singleton. Always be sure that you don't resolve scoped services directly from the container, only from a [scope](/docs/guides/scopes). This case is monitored by the [lifetime](/docs/diagnostics/validation#lifetime-validation) validation rule when it's [enabled](/docs/configuration/container-configuration#lifetime-validation). \n:::\n\n## Named resolution\n\n<CodeDescPanel>\n<div>\n\nIt's a resolution request for a named service. The same applies, when the container sees a dependency in the resolution tree with a name (set by [attributes](/docs/guides/service-resolution#attributes) or [bindings](/docs/guides/service-resolution#dependency-binding)); it will search for a matching [Named registration](/docs/guides/basics#named-registration) to inject.\n\n</div>\n<div>\n\n```cs\ncontainer.Register<IService, Implementation>(\"Example\");\n// the named request.\nvar service = container.Resolve<IService>(\"Example\");\n```\n\n</div>\n</CodeDescPanel>\n\n## Self registration\n\n<CodeDescPanel>\n<div>\n\nIt's a service registration that's mapped to itself. This means its service and implementation type is the same.\n\n</div>\n<div>\n\n```cs\n// equivalent to container.Register<Implementation, Implementation>();\ncontainer.Register<Implementation>();\n```\n\n</div>\n</CodeDescPanel>"
  },
  {
    "path": "docs/docs/getting-started/introduction.md",
    "content": "---\ntitle: Introduction\n---\n\nimport Tabs from '@theme/Tabs'; \nimport TabItem from '@theme/TabItem';\n\nStashbox and its extensions are distributed via [NuGet](https://www.nuget.org/packages?q=stashbox) packages.\n\n<Tabs>\n<TabItem value=\"Package Manager\" label=\"Package Manager\">\n\nYou can install the package by typing the following into the Package Manager Console:\n```powershell\nInstall-Package Stashbox -Version 5.20.0\n```\n\n</TabItem>\n<TabItem value=\"dotnet CLI\" label=\"dotnet CLI\">\n\nYou can install the package by using the dotnet cli:\n```bash\ndotnet add package Stashbox --version 5.20.0\n```\n\n</TabItem>\n<TabItem value=\"PackageReference\" label=\"PackageReference\">\n\nYou can add the package into the package references of your `.csproj`:\n```xml\n<PackageReference Include=\"Stashbox\" Version=\"5.20.0\" />\n```\n\n</TabItem>\n</Tabs>\n\n## Usage\nThe general idea behind using Stashbox is that you structure your code with loosely coupled components with the [Dependency Inversion Principle](https://en.wikipedia.org/wiki/Dependency_inversion_principle), [Inversion Of Control](https://en.wikipedia.org/wiki/Inversion_of_control) and [Dependency Injection](https://martinfowler.com/articles/injection.html) in mind. \n\nRather than letting the services instantiate their dependencies inside themselves, inject the dependencies on construction. Also, rather than creating the object hierarchy manually, you can use a Dependency Injection framework that does the work for you. That's why you are here, I suppose. 🙂\n\nTo achieve the most efficient usage of Stashbox, you should follow these steps:\n- At the startup of your application, instantiate a `StashboxContainer`.\n- Register your services into the container.\n- [Validate](/docs/diagnostics/validation) the state of the container and the registrations with the `.Validate()` method. *(Optional)*\n- During the lifetime of the application, use the container to resolve your services.\n- Create [scopes](/docs/guides/scopes) and use them to resolve your services. *(Optional)*\n- On application exit, call the container's `.Dispose()` or `.DisposeAsync()` method to clean up the resources. *(Optional)*\n\n:::caution\nYou should create only a single instance from `StashboxContainer` (plus child containers if you use them) per application domain. `StashboxContainer` instances are thread-safe. Do not create new container instances continuously, such action will bypass the container's internal delegate cache and could lead to performance degradation. \n:::\n\n## How it works?\nStashbox builds and maintains a collection of [registered services](/docs/getting-started/glossary#service-registration--registered-service). When a service is requested for resolution, Stashbox starts looking for a matching registration that has the same [service type](/docs/getting-started/glossary#service-type--implementation-type) as the type that was requested. If it finds one, the container initiates a scan on the [implementation type's](/docs/getting-started/glossary#service-type--implementation-type) available constructors and selects the one with the most arguments it knows how to resolve by matching argument types to other registrations.\n\nWhen every constructor argument has a companion registration, Stashbox jumps to the first one and continues the same scanning operation. \n\nThis process is repeated until every [injectable dependency](/docs/getting-started/glossary#injectable-dependency) has a matching registration in the [resolution tree](/docs/getting-started/glossary#resolution-tree). At the end of the process, Stashbox will have each dependency node built-up in a hierarchical object structure to instantiate the initially requested service object.\n\n## Example\nLet's see a quick example. We have three services `DbBackup`, `MessageBus` and `ConsoleLogger`. `DbBackup` has a dependency on `IEventBroadcaster` (implemented by `MessageBus`) and `ILogger` (implemented by `ConsoleLogger`), `MessageBus` also depending on an `ILogger`:\n```cs\npublic interface IJob { void DoTheJob(); }\n\npublic interface ILogger { void Log(string message); }\n\npublic interface IEventBroadcaster { void Broadcast(IEvent @event); }\n\n\npublic class ConsoleLogger : ILogger\n{\n    public void Log(string message) => Console.WriteLine(message);\n}\n\npublic class MessageBus : IEventBroadcaster\n{\n    private readonly ILogger logger;\n\n    public MessageBus(ILogger logger)\n    {\n        this.logger = logger;\n    }\n\n    void Broadcast(IEvent @event) \n    {\n        this.logger.Log($\"Sending event to bus: {@event.Name}\");\n        // Do the actual event broadcast.\n    }\n}\n\npublic class DbBackup : IJob\n{\n    private readonly ILogger logger;\n    private readonly IEventBroadcaster eventBroadcaster;\n\n    public DbBackup(ILogger logger, IEventBroadcaster eventBroadcaster)\n    {\n        this.logger = logger;\n        this.eventBroadcaster = eventBroadcaster;\n    }\n\n    public void DoTheJob() \n    {\n        this.logger.Log(\"Backing up!\");\n        // Do the actual backup.\n        this.eventBroadcaster.Broadcast(new DbBackupCompleted());\n    } \n}\n```\n\n:::info\nBy depending only on interfaces, you decouple your services from concrete implementations. This gives you the flexibility of a more comfortable implementation replacement and also isolates your components from each other. For example, unit testing benefits a lot from the possibility of replacing real implementations with mocks.\n:::\n\nThe example above configured with Stashbox in a Console Application:\n\n```cs\nusing Stashbox;\nusing System;\n\nnamespace Example\n{\n    public class Program\n    {\n        private static readonly IStashboxContainer container;\n\n        static Program()\n        {\n            // 1. Create container\n            container = new StashboxContainer();\n\n            // 2. Register your services\n            container.RegisterSingleton<ILogger, ConsoleLogger>();\n            container.Register<IEventBroadcaster, MessageBus>();\n            container.Register<IJob, DbBackup>();\n\n            // 3. Validate the configuration.\n            container.Validate();\n        }\n\n        static void Main(string[] args)\n        {\n            // 4. Resolve and use your service\n            var job = container.Resolve<IJob>();\n            job.DoTheJob();\n        }\n    }\n}\n```"
  },
  {
    "path": "docs/docs/getting-started/overview.md",
    "content": "---\ntitle: Overview\n---\n\n# Stashbox\n\n[![Appveyor Build Status](https://img.shields.io/appveyor/build/pcsajtai/stashbox?logo=appveyor&logoColor=white)](https://ci.appveyor.com/project/pcsajtai/stashbox/branch/master) \n[![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/z4kn4fein/stashbox/linux-macOS-CI.yml?logo=GitHub&branch=master)](https://github.com/z4kn4fein/stashbox/actions/workflows/linux-macOS-CI.yml)\n[![NuGet Downloads](https://img.shields.io/nuget/dt/Stashbox?label=nuget)](https://www.nuget.org/packages/Stashbox)\n[![Sonar Tests](https://img.shields.io/sonar/tests/z4kn4fein_stashbox?compact_message&logo=sonarcloud&server=https%3A%2F%2Fsonarcloud.io)](https://sonarcloud.io/project/overview?id=z4kn4fein_stashbox) \n[![Sonar Coverage](https://img.shields.io/sonar/coverage/z4kn4fein_stashbox?logo=SonarCloud&server=https%3A%2F%2Fsonarcloud.io)](https://sonarcloud.io/project/overview?id=z4kn4fein_stashbox) \n[![Sonar Quality Gate](https://img.shields.io/sonar/quality_gate/z4kn4fein_stashbox?logo=sonarcloud&server=https%3A%2F%2Fsonarcloud.io)](https://sonarcloud.io/project/overview?id=z4kn4fein_stashbox) \n[![Sourcelink](https://img.shields.io/badge/sourcelink-enabled-brightgreen.svg)](https://github.com/dotnet/sourcelink)\n\nStashbox is a lightweight, fast, and portable dependency injection framework for .NET-based solutions. It encourages the building of loosely coupled applications and simplifies the construction of hierarchical object structures. It can be integrated easily with .NET Core, Generic Host, ASP.NET, Xamarin, and many other applications.\n\nThese are the latest available stable and pre-release versions:\n\nGithub (stable) | NuGet (stable) | NuGet (daily)\n--- | --- | ---\n[![Github release](https://img.shields.io/github/release/z4kn4fein/stashbox.svg)](https://github.com/z4kn4fein/stashbox/releases) | [![NuGet Version](https://img.shields.io/nuget/v/Stashbox)](https://www.nuget.org/packages/Stashbox) | [![Nuget pre-release](https://img.shields.io/nuget/vpre/Stashbox)](https://www.nuget.org/packages/Stashbox/)\n\n## Core attributes\n - 🚀 Fast, thread-safe, and lock-free operations.\n - ⚡️ Easy-to-use Fluent configuration API.\n - ♻️ Small memory footprint.\n - 🔄 Tracks the dependency tree for cycles. \n - 🚨 Detects and warns about misconfigurations.\n - 🔥 Gives fast feedback on registration/resolution issues.\n\n## Supported platforms\n - .NET 5+\n - .NET Standard 2.0+\n - .NET Framework 4.5+\n - Mono\n - Universal Windows Platform\n - Xamarin (Android/iOS/Mac)\n - Unity\n\n## Contact & support\n- Create a [GitHub issue](https://github.com/z4kn4fein/stashbox/issues) for bug reports and feature requests.\n- Start a [GitHub discussion](https://github.com/z4kn4fein/stashbox/discussions) for your questions and ideas.\n- Add a ⭐️ [on GitHub](https://github.com/z4kn4fein/stashbox) to support the project!\n\n## License\nThis project is licensed under the [MIT license](https://github.com/z4kn4fein/stashbox/blob/master/LICENSE).\n"
  },
  {
    "path": "docs/docs/guides/advanced-registration.md",
    "content": "import CodeDescPanel from '@site/src/components/CodeDescPanel';\nimport Tabs from '@theme/Tabs'; \nimport TabItem from '@theme/TabItem';\n\n# Advanced registration\nThis section is about Stashbox's further configuration options, including the registration configuration API, the registration of factory delegates, multiple implementations, batch registrations, the concept of the [Composition Root](https://blog.ploeh.dk/2011/07/28/CompositionRoot/), and many more.\n\n:::info\nThis section won't cover all the available options of the registrations API, but you can find them [here](/docs/configuration/registration-configuration).\n:::\n\n## Factory registration\n\n<CodeDescPanel>\n<div>\n\nYou can bind a factory delegate to a registration that the container will invoke directly to instantiate your service. \n\nYou can use parameter-less and custom parameterized delegates as a factory. [Here](/docs/configuration/registration-configuration#factory) is the list of all available options.\n\nYou can also get the current [dependency resolver](/docs/getting-started/glossary#dependency-resolver) as a delegate parameter to resolve any additional dependencies required for the service construction.\n\n</div>\n<div>\n\n<Tabs>\n<TabItem value=\"Parameter-less\" label=\"Parameter-less\">\n\n```cs\ncontainer.Register<ILogger, ConsoleLogger>(options => options\n    .WithFactory(() => new ConsoleLogger());\n\n// the container uses the factory for instantiation.\nIJob job = container.Resolve<ILogger>();\n```\n\n</TabItem>\n<TabItem value=\"Parameterized\" label=\"Parameterized\">\n\n```cs\ncontainer.Register<IJob, DbBackup>(options => options\n    .WithFactory<ILogger>(logger => new DbBackup(logger));\n\n// the container uses the factory for instantiation.\nIJob job = container.Resolve<IJob>();\n```\n\n</TabItem>\n<TabItem value=\"Resolver parameter\" label=\"Resolver parameter\">\n\n```cs\ncontainer.Register<IJob, DbBackup>(options => options\n    .WithFactory(resolver => new DbBackup(resolver.Resolve<ILogger>()));\n    \n// the container uses the factory for instantiation.\nIJob job = container.Resolve<IJob>();\n```\n\n</TabItem>\n</Tabs>\n</div>\n</CodeDescPanel>\n\n<CodeDescPanel>\n<div>\n\nDelegate factories are useful when your service's instantiation is not straight-forward for the container, like when it depends on something that is not available at resolution time. E.g., a connection string.\n\n</div>\n<div>\n\n```cs\ncontainer.Register<IJob, DbBackup>(options => options\n    .WithFactory<ILogger>(logger => \n        new DbBackup(Configuration[\"DbConnectionString\"], logger));\n```\n\n</div>\n</CodeDescPanel>\n\n\n<CodeDescPanel>\n<div>\n\n### Factories with parameter overrides\nStashbox can implicitly [wrap](/docs/advanced/wrappers-resolvers#delegate) your service in a `Delegate` and lets you pass parameters that can override your service's dependencies. Moreover, you can register your own custom delegate that the container will resolve when you request your service wrapped in a `Delegate`.\n\n</div>\n<div>\n\n<Tabs groupId=\"generic-runtime-apis\">\n<TabItem value=\"Generic API\" label=\"Generic API\">\n\n```cs\ncontainer.RegisterFunc<string, IJob>((connectionString, resolver) => \n    new DbBackup(connectionString, resolver.Resolve<ILogger>()));\n\nFunc<string, IJob> backupFactory = container.Resolve<Func<string, IJob>>();\nIJob dbBackup = backupFactory(Configuration[\"ConnectionString\"]);\n```\n\n</TabItem>\n<TabItem value=\"Runtime type API\" label=\"Runtime type API\">\n\n```cs\ncontainer.RegisterFunc<string, IJob>((connectionString, resolver) => \n    new DbBackup(connectionString, resolver.Resolve<ILogger>()));\n\nDelegate backupFactory = container.ResolveFactory(typeof(IJob), \n    parameterTypes: new[] { typeof(string) });\nIJob dbBackup = backupFactory.DynamicInvoke(Configuration[\"ConnectionString\"]);\n```\n<!-- tabs:end -->\n\n</TabItem>\n</Tabs>\n</div>\n</CodeDescPanel>\n\n<CodeDescPanel>\n<div>\n\nIf a service has multiple constructors, the container visits those first, that has matching parameters passed to the factory, with respecting the additional [constructor selection rules](/docs/configuration/registration-configuration#constructor-selection).\n\n</div>\n<div>\n\n```cs\nclass Service\n{\n    public Service(int number) { }\n    public Service(string text) { }\n}\n\ncontainer.Register<Service>();\n\n// create the factory with an int input parameter.\nvar func = constainer.Resolve<Func<int, Service>>();\n\n// the constructor with the int param \n// is used for instantiation.\nvar service = func(2);\n```\n</div>\n</CodeDescPanel>\n\n<CodeDescPanel>\n<div>\n\n### Consider this before using the resolver parameter inside a factory\nDelegate factories are a black-box for the container. It doesn't have control over what's happening inside a delegate, which means when you resolve additional dependencies with the [dependency resolver](/docs/getting-started/glossary#dependency-resolver) parameter, they could easily bypass the [lifetime](/docs/diagnostics/validation#lifetime-validation) and [circular dependency](/docs/diagnostics/validation#circular-dependency) validations. Fortunately, you have the option to keep them validated anyway with parameterized factory delegates.\n\n#### Delegates with dependencies passed as parameters\nRather than using the [dependency resolver](/docs/getting-started/glossary#dependency-resolver) parameter inside the factory, let the container inject the dependencies into the delegate as parameters. This way, the [resolution tree's](/docs/getting-started/glossary#resolution-tree) integrity remains stable because no service resolution happens inside the black-box, and each parameter is validated.\n\n</div>\n<div>\n\n\n```cs\ninterface IEventProcessor { }\n\nclass EventProcessor : IEventProcessor\n{\n    public EventProcessor(ILogger logger, IEventValidator validator)\n    { }\n}\n\ncontainer.Register<ILogger, ConsoleLogger>();\ncontainer.Register<IEventValidator, EventValidator>();\n\ncontainer.Register<IEventProcessor, EventProcessor>(options => options\n    // Ilogger and IEventValidator instances are injected\n    // by the container at resolution time, so they will be\n    // validated against circular and captive dependencies.\n    .WithFactory<ILogger, IEventValidator>((logger, validator) => \n        new EventProcessor(logger, validator));\n\n// the container resolves ILogger and IEventValidator first, then\n// it passes them to the factory as delegate parameters.\nIEventProcessor processor = container.Resolve<IEventProcessor>();\n```\n\n</div>\n</CodeDescPanel>\n\n<CodeDescPanel>\n<div>\n\n### Accessing the currently resolving type in factories\n\nTo access the currently resolving type in factory delegates, you can set the `TypeInformation` type as an input parameter of the factory.\nThe `TypeInformation` holds every reflected context information about the currently resolving type. \n\nThis can be useful when the resolution is, e.g., in an open generic context, and we want to know which closed generic variant is requested.\n\n</div>\n<div>\n\n\n```cs\ninterface IService<T> { }\n\nclass Service<T> : IService<T> { }\n\ncontainer.Register(typeof(IService<>), typeof(Service<>), options => \n    options.WithFactory<TypeInformation>(typeInfo => \n    {\n        // typeInfo.Type here holds the actual type like\n        // IService<int> based on the resolution request below.\n    }));\n    \ncontainer.Resolve<IService<int>>();\n```\n\n</div>\n</CodeDescPanel>\n\n\n## Multiple implementations\n\n<CodeDescPanel>\n<div>\n\nAs we previously saw in the [Named registration](/docs/guides/basics#named-registration) topic, Stashbox allows you to have multiple implementations bound to a particular [service type](/docs/getting-started/glossary#service-type--implementation-type). You can use names to distinguish them, but you can also access them by requesting a typed collection using the [service type](/docs/getting-started/glossary#service-type--implementation-type).\n\n:::note \nThe returned collection is in the same order as the services were registered.\nAlso, to request a collection, you can use any interface implemented by an array.\n:::\n\n</div>\n<div>\n\n```cs\ncontainer.Register<IJob, DbBackup>();\ncontainer.Register<IJob, StorageCleanup>();\ncontainer.Register<IJob, ImageProcess>();\n```\n\n<Tabs>\n<TabItem value=\"ResolveAll\" label=\"ResolveAll\">\n\n```cs\n// jobs contain all three services in registration order.\nIEnumerable<IJob> jobs = container.ResolveAll<IJob>();\n```\n\n</TabItem>\n<TabItem value=\"Array\" label=\"Array\">\n\n```cs\n// jobs contain all three services in registration order.\nIJob[] jobs = container.Resolve<IJob[]>();\n```\n\n</TabItem>\n<TabItem value=\"IEnumerable\" label=\"IEnumerable\">\n\n```cs\n// jobs contain all three services in registration order.\nIEnumerable<IJob> jobs = container.Resolve<IEnumerable<IJob>>();\n```\n\n</TabItem>\n<TabItem value=\"IList\" label=\"IList\">\n\n```cs\n// jobs contain all three services in registration order.\nIList<IJob> jobs = container.Resolve<IList<IJob>>();\n```\n\n</TabItem>\n<TabItem value=\"ICollection\" label=\"ICollection\">\n\n```cs\n// jobs contain all three services in registration order.\nICollection<IJob> jobs = container.Resolve<ICollection<IJob>>();\n```\n\n</TabItem>\n</Tabs>\n</div>\n</CodeDescPanel>\n\n<CodeDescPanel>\n<div>\n\nWhen you have multiple implementations registered to a service, a request to the [service type](/docs/getting-started/glossary#service-type--implementation-type) without a name will return the **last registered implementation**.\n\n:::info\nNot only names can be used to distinguish registrations, [conditions](/docs/guides/service-resolution#conditional-resolution), [named scopes](/docs/guides/scopes#named-scopes), and [metadata](/docs/advanced/wrappers-resolvers#metadata--tuple) can also influence the results.\n:::\n\n</div>\n<div>\n\n```cs\ncontainer.Register<IJob, DbBackup>();\ncontainer.Register<IJob, StorageCleanup>();\ncontainer.Register<IJob, ImageProcess>();\n\n// job will be the ImageProcess.\nIJob job = container.Resolve<IJob>();\n```\n\n</div>\n</CodeDescPanel>\n\n## Binding to multiple services\n\n<CodeDescPanel>\n<div>\n\nWhen you have a service that implements multiple interfaces, you have the option to bind its registration to all or some of those additional interfaces or base types.\n\nSuppose we have the following class declaration:\n```cs\nclass DbBackup : IJob, IScheduledJob\n{ \n    public DbBackup() { }\n}\n```\n\n</div>\n<div>\n\n<Tabs>\n<TabItem value=\"To another type\" label=\"To another type\">\n\n```cs\ncontainer.Register<IJob, DbBackup>(options => options\n    .AsServiceAlso<IScheduledJob>());\n\nIJob job = container.Resolve<IJob>(); // DbBackup\nIScheduledJob job = container.Resolve<IScheduledJob>(); // DbBackup\nDbBackup job = container.Resolve<DbBackup>(); // error, not found\n```\n\n</TabItem>\n<TabItem value=\"To all implemented types\" label=\"To all implemented types\">\n\n```cs\ncontainer.Register<DbBackup>(options => options\n    .AsImplementedTypes());\n\nIJob job = container.Resolve<IJob>(); // DbBackup\nIScheduledJob job = container.Resolve<IScheduledJob>(); // DbBackup\nDbBackup job = container.Resolve<DbBackup>(); // DbBackup\n```\n\n</TabItem>\n</Tabs>\n</div>\n</CodeDescPanel>\n\n## Batch registration\n\n<CodeDescPanel>\n<div>\n\nYou have the option to register multiple services in a single registration operation. \n\n**Filters (optional):**\nFirst, the container will use the *implementation filter* action to select only those types from the collection we want to register. When we have those, the container will execute the *service filter* on their implemented interfaces and base classes to select which [service type](/docs/getting-started/glossary#service-type--implementation-type) they should be mapped to.\n\n:::note\nFramework types like `IDisposable` are excluded from being considered as a [service type](/docs/getting-started/glossary#service-type--implementation-type) by default.\n:::\n\n:::tip \nYou can use the registration configuration API to configure individual registrations.\n:::\n\n</div>\n<div>\n\n<Tabs>\n<TabItem value=\"Default\" label=\"Default\">\n\nThis example will register three types to all their implemented interfaces, extended base classes, and to themselves ([self registration](/docs/getting-started/glossary#self-registration)) without any filter:\n```cs\ncontainer.RegisterTypes(new[] \n    { \n        typeof(DbBackup), \n        typeof(ConsoleLogger), \n        typeof(StorageCleanup) \n    });\n\nIEnumerable<IJob> jobs = container.ResolveAll<IJob>(); // 2 items\nILogger logger = container.Resolve<ILogger>(); // ConsoleLogger\nIJob job = container.Resolve<IJob>(); // StorageCleanup\nDbBackup backup = container.Resolve<DbBackup>(); // DbBackup\n```\n\n</TabItem>\n<TabItem value=\"Filters\" label=\"Filters\">\n\nIn this example, we assume that `DbBackup` and `StorageCleanup` are implementing `IDisposable` besides `IJob` and also extending a `JobBase` abstract class.\n```cs\ncontainer.RegisterTypes(new[] \n    { typeof(DbBackup), typeof(ConsoleLogger), typeof(StorageCleanup) },\n    // implementation filter, only those implementations that implements IDisposable\n    impl => typeof(IDisposable).IsAssignableFrom(impl),\n    // service filter, register them to base classes only\n    (impl, service) => service.IsAbstract && !service.IsInterface);\n\nIEnumerable<IJob> jobs = container.ResolveAll<IJob>(); // 0 items\nIEnumerable<JobBase> jobs = container.ResolveAll<JobBase>(); // 2 items\nILogger logger = container.Resolve<ILogger>(); // error, not found\nDbBackup backup = container.Resolve<DbBackup>(); // DbBackup\n```\n\n</TabItem>\n<TabItem value=\"Without self\" label=\"Without self\">\n\nThis example ignores the [self registrations](/docs/getting-started/glossary#self-registration) completely:\n```cs\ncontainer.RegisterTypes(new[] \n    { \n        typeof(DbBackup), \n        typeof(ConsoleLogger), \n        typeof(StorageCleanup)\n    },\n    registerSelf: false);\n\nIEnumerable<IJob> jobs = container.ResolveAll<IJob>(); // 2 items\nILogger logger = container.Resolve<ILogger>(); // ConsoleLogger\nDbBackup backup = container.Resolve<DbBackup>(); // error, not found\nConsoleLogger logger = container.Resolve<ConsoleLogger>(); // error, not found\n```\n\n</TabItem>\n<TabItem value=\"Registration options\" label=\"Registration options\">\n\nThis example will configure all registrations mapped to `ILogger` as `Singleton`:\n```cs\ncontainer.RegisterTypes(new[] \n    { \n        typeof(DbBackup), \n        typeof(ConsoleLogger), \n        typeof(StorageCleanup)\n    },\n    configurator: options => \n    {\n        if (options.HasServiceType<ILogger>())\n            options.WithSingletonLifetime();\n    });\n\nILogger logger = container.Resolve<ILogger>(); // ConsoleLogger\nILogger newLogger = container.Resolve<ILogger>(); // the same ConsoleLogger\nIEnumerable<IJob> jobs = container.ResolveAll<IJob>(); // 2 items\n```\n\n</TabItem>\n</Tabs>\n\n</div>\n</CodeDescPanel>\n\n<CodeDescPanel>\n<div>\n\nAnother type of service filter is the `.RegisterTypesAs<T>()` method, which registers only those types that implements the `T` [service type](/docs/getting-started/glossary#service-type--implementation-type).\n\n:::note \nThis method also accepts an implementation filter and a registration configurator action like `.RegisterTypes()`.\n:::\n\n:::caution\n`.RegisterTypesAs<T>()` doesn't create [self registrations](/docs/getting-started/glossary#self-registration) as it only maps the implementations to the given `T` [service type](/docs/getting-started/glossary#service-type--implementation-type).\n:::\n\n</div>\n<div>\n\n<Tabs groupId=\"generic-runtime-apis\">\n<TabItem value=\"Generic API\" label=\"Generic API\">\n\n```cs\ncontainer.RegisterTypesAs<IJob>(new[] \n    { \n        typeof(DbBackup), \n        typeof(ConsoleLogger), \n        typeof(StorageCleanup) \n    });\n\nIEnumerable<IJob> jobs = container.ResolveAll<IJob>(); // 2 items\nILogger logger = container.Resolve<ILogger>(); // error, not found\nIJob job = container.Resolve<IJob>(); // StorageCleanup\nDbBackup backup = container.Resolve<DbBackup>(); // error, not found\n```\n\n</TabItem>\n<TabItem value=\"Runtime type API\" label=\"Runtime type API\">\n\n```cs\ncontainer.RegisterTypesAs(typeof(IJob), new[] \n    { \n        typeof(DbBackup), \n        typeof(ConsoleLogger), \n        typeof(StorageCleanup) \n    });\n\nIEnumerable<IJob> jobs = container.ResolveAll<IJob>(); // 2 items\nILogger logger = container.Resolve<ILogger>(); // error, not found\nIJob job = container.Resolve<IJob>(); // StorageCleanup\nDbBackup backup = container.Resolve<DbBackup>(); // error, not found\n```\n\n</TabItem>\n</Tabs>\n</div>\n</CodeDescPanel>\n\n## Assembly registration\n\n<CodeDescPanel>\n<div>\n\nThe batch registration API *(filters, registration configuration action, self-registration)* is also usable for registering services from given assemblies.\n\nIn this example, we assume that the same three services we used in the [batch registration](#batch-registration) section are in the same assembly.\n\n:::info\nThe container also detects and registers open-generic definitions (when applicable) from the supplied type collection. You can read about [open-generics here](/docs/advanced/generics#open-generics).\n:::\n\n</div>\n<div>\n\n<Tabs>\n<TabItem value=\"Single assembly\" label=\"Single assembly\">\n\n```cs\ncontainer.RegisterAssembly(typeof(DbBackup).Assembly,\n    // service filter, register to interfaces only\n    serviceTypeSelector: (impl, service) => service.IsInterface,\n    registerSelf: false,\n    configurator: options => options.WithoutDisposalTracking()\n);\n\nIEnumerable<IJob> jobs = container.ResolveAll<IJob>(); // 2 items\nIEnumerable<JobBase> jobs = container.ResolveAll<JobBase>(); // 0 items\nILogger logger = container.Resolve<ILogger>(); // ConsoleLogger\nDbBackup backup = container.Resolve<DbBackup>(); // error, not found\n```\n\n</TabItem>\n<TabItem value=\"Multiple assemblies\" label=\"Multiple assemblies\">\n\n```cs\ncontainer.RegisterAssemblies(new[] \n    { \n        typeof(DbBackup).Assembly, \n        typeof(JobFromAnotherAssembly).Assembly \n    },\n    // service filter, register to interfaces only\n    serviceTypeSelector: (impl, service) => service.IsInterface,\n    registerSelf: false,\n    configurator: options => options.WithoutDisposalTracking()\n);\n\nIEnumerable<IJob> jobs = container.ResolveAll<IJob>(); // 2 items\nIEnumerable<JobBase> jobs = container.ResolveAll<JobBase>(); // 0 items\nILogger logger = container.Resolve<ILogger>(); // ConsoleLogger\nDbBackup backup = container.Resolve<DbBackup>(); // error, not found\n```\n\n</TabItem>\n<TabItem value=\"Containing type\" label=\"Containing type\">\n\n```cs\ncontainer.RegisterAssemblyContaining<DbBackup>(\n    // service filter, register to interfaces only\n    serviceTypeSelector: (impl, service) => service.IsInterface,\n    registerSelf: false,\n    configurator: options => options.WithoutDisposalTracking()\n);\n\nIEnumerable<IJob> jobs = container.ResolveAll<IJob>(); // 2 items\nIEnumerable<JobBase> jobs = container.ResolveAll<JobBase>(); // 0 items\nILogger logger = container.Resolve<ILogger>(); // ConsoleLogger\nDbBackup backup = container.Resolve<DbBackup>(); // error, not found\n```\n\n</TabItem>\n</Tabs>\n</div>\n</CodeDescPanel>\n\n## Composition root\n\n<CodeDescPanel>\n<div>\n\nThe [Composition Root](https://blog.ploeh.dk/2011/07/28/CompositionRoot/) is an entry point where all services required to make a component functional are wired together.\n\nStashbox provides an `ICompositionRoot` interface that can be used to define an entry point for a given component or even for an entire assembly. \n\nYou can wire up your *composition root* implementation with `ComposeBy<TRoot>()`, or you can let the container find and execute all available *composition root* implementations within an assembly.\n\n:::note\nYour `ICompositionRoot` implementation also can have dependencies that the container will resolve.\n:::\n\n</div>\n<div>\n\n\n```cs\nclass ExampleRoot : ICompositionRoot\n{\n    public ExampleRoot(IDependency rootDependency)\n    { }\n\n    public void Compose(IStashboxContainer container)\n    {\n       container.Register<IServiceA, ServiceA>();\n       container.Register<IServiceB, ServiceB>();\n    }\n}\n```\n\n<Tabs>\n<TabItem value=\"Single\" label=\"Single\">\n\n```cs\n// compose a single root.\ncontainer.ComposeBy<ExampleRoot>();\n```\n\n</TabItem>\n<TabItem value=\"Assembly\" label=\"Assembly\">\n\n```cs\n// compose every root in the given assembly.\ncontainer.ComposeAssembly(typeof(IServiceA).Assembly);\n```\n\n</TabItem>\n<TabItem value=\"Override\" label=\"Override\">\n\n```cs\n// compose a single root with dependency override.\ncontainer.ComposeBy<ExampleRoot>(new CustomRootDependency());\n```\n\n</TabItem>\n</Tabs>\n</div>\n</CodeDescPanel>\n\n## Injection parameters\n\n<CodeDescPanel>\n<div>\n\nIf you have pre-evaluated dependencies you'd like to inject at resolution time, you can set them as injection parameters during registration. \n\n:::note\nInjection parameter names are matched to constructor arguments or field/property names.\n:::\n\n</div>\n<div>\n\n```cs\ncontainer.Register<IJob, DbBackup>(options => options\n    .WithInjectionParameter(\"logger\", new ConsoleLogger())\n    .WithInjectionParameter(\"eventBroadcaster\", new MessageBus());\n\n// the injection parameters will be passed to DbBackup's constructor.\nIJob backup = container.Resolve<IJob>();\n```\n</div>\n</CodeDescPanel>\n\n## Initializer / finalizer\n\n<CodeDescPanel>\n<div>\n\nThe container provides specific extension points to let you react to lifetime events of an instantiated service. \n\nFor this reason, you can specify *Initializer* and *Finalizer* delegates. The *finalizer* is called upon the service's [disposal](/docs/guides/scopes#disposal), and the *initializer* is called upon the service's construction.\n\n</div>\n<div>\n\n```cs\ncontainer.Register<ILogger, FileLogger>(options => options\n    // delegate that called right after instantiation.\n    .WithInitializer((logger, resolver) => logger.OpenFile())\n    // delegate that called right before the instance's disposal.\n    .WithFinalizer(logger => logger.CloseFile()));\n```\n</div>\n</CodeDescPanel>\n"
  },
  {
    "path": "docs/docs/guides/basics.md",
    "content": "import CodeDescPanel from '@site/src/components/CodeDescPanel';\nimport Tabs from '@theme/Tabs'; \nimport TabItem from '@theme/TabItem';\n\n# Basic usage\n\nThis section is about the basics of Stashbox's API. It will give you a good starting point for more advanced topics described in the following sections. \nStashbox provides several methods that enable registering services, and we'll go through the most common scenarios with code examples.\n\n## Default registration\n\n<CodeDescPanel>\n<div>\n\nStashbox allows registration operations via the `Register()` methods. \n\nDuring registration, the container checks whether the [service type](/docs/getting-started/glossary#service-type--implementation-type) is assignable from the [implementation type](/docs/getting-started/glossary#service-type--implementation-type) and if not, the container throws an [exception](/docs/diagnostics/validation#registration-validation). \n\nAlso, when the implementation is not resolvable, the container throws the same [exception](/docs/diagnostics/validation#registration-validation).\n\nThe example registers `DbBackup` to be returned when `IJob` is requested.\n\n</div>\n\n<div>\n\n<Tabs groupId=\"generic-runtime-apis\">\n<TabItem value=\"Generic API\" label=\"Generic API\">\n\n```cs\ncontainer.Register<IJob, DbBackup>();\nIJob job = container.Resolve<IJob>();\n// throws an exception because ConsoleLogger doesn't implement IJob.\ncontainer.Register<IJob, ConsoleLogger>();\n// throws an exception because IJob is not a valid implementation.\ncontainer.Register<IJob, IJob>();\n```\n\n</TabItem>\n<TabItem value=\"Runtime type API\" label=\"Runtime type API\">\n\n```cs\ncontainer.Register(typeof(IJob), typeof(DbBackup));\nobject job = container.Resolve(typeof(IJob));\n// throws an exception because ConsoleLogger doesn't implement IJob.\ncontainer.Register(typeof(IJob), typeof(ConsoleLogger));\n// throws an exception because IJob is not a valid implementation.\ncontainer.Register(typeof(IJob), typeof(IJob));\n```\n\n</TabItem>\n</Tabs>\n</div>\n</CodeDescPanel>\n\n<CodeDescPanel>\n<div>\n\nYou can register a service to itself without specifying a [service type](/docs/getting-started/glossary#service-type--implementation-type), only the implementation ([self registration](/docs/getting-started/glossary#self-registration)). \n\nIn this case, the given implementation is considered the [service type](/docs/getting-started/glossary#service-type--implementation-type) and must be used to request the service (`DbBackup` in the example).\n\n</div>\n<div>\n<Tabs groupId=\"generic-runtime-apis\">\n<TabItem value=\"Generic API\" label=\"Generic API\">\n\n```cs\ncontainer.Register<DbBackup>();\nDbBackup backup = container.Resolve<DbBackup>();\n```\n\n</TabItem>\n<TabItem value=\"Runtime type API\" label=\"Runtime type API\">\n\n```cs\ncontainer.Register(typeof(DbBackup));\nobject backup = container.Resolve(typeof(DbBackup));\n```\n</TabItem>\n</Tabs>\n</div>\n</CodeDescPanel>\n\n<CodeDescPanel>\n\n<div>\n\nThe container's API is fluent, which means you can chain the calls on its methods after each other.\n\n</div>\n<div>\n\n```cs\nvar job = container.Register<IJob, DbBackup>()\n    .Register<ILogger, ConsoleLogger>()\n    .Resolve<IJob>();\n```\n\n</div>\n</CodeDescPanel>\n\n## Named registration\n\n<CodeDescPanel>\n\n<div>\n\nThe example shows how you can bind more implementations to a [service type](/docs/getting-started/glossary#service-type--implementation-type) using names for identification. \n\nThe same name must be used to resolve the named service.\n\n:::note\nThe name is an `object` type.\n:::\n\n</div>\n<div>\n\n<Tabs groupId=\"generic-runtime-apis\">\n<TabItem value=\"Generic API\" label=\"Generic API\">\n\n```cs\ncontainer.Register<IJob, DbBackup>(\"DbBackup\");\ncontainer.Register<IJob, StorageCleanup>(\"StorageCleanup\");\nIJob cleanup = container.Resolve<IJob>(\"StorageCleanup\");\n```\n\n</TabItem>\n<TabItem value=\"Runtime type API\" label=\"Runtime type API\">\n\n```cs\ncontainer.Register(typeof(IJob), typeof(DbBackup), \"DbBackup\");\ncontainer.Register(typeof(IJob), typeof(StorageCleanup), \"StorageCleanup\");\nobject cleanup = container.Resolve(typeof(IJob), \"StorageCleanup\");\n```\n\n</TabItem>\n</Tabs>\n</div>\n</CodeDescPanel>\n\n<CodeDescPanel>\n<div>\n\nYou can also get each service that share the same name by requesting an `IEnumerable<>` or using the `ResolveAll()` method with the `name` parameter.\n\n</div>\n<div>\n\n```cs\ncontainer.Register<IJob, DbBackup>(\"StorageJobs\");\ncontainer.Register<IJob, StorageCleanup>(\"StorageJobs\");\ncontainer.Register<IJob, AnotherJob>();\n// jobs will be [DbBackup, StorageCleanup].\nIEnumerable<IJob> jobs = container.Resolve<IEnumerable<IJob>>(\"StorageJobs\");\n```\n\n</div>\n</CodeDescPanel>\n\n## Instance registration\n\n<CodeDescPanel>\n<div>\n\nWith instance registration, you can provide an already created external instance to use when the given [service type](/docs/getting-started/glossary#service-type--implementation-type) is requested.\n\nStashbox automatically handles the [disposal](/docs/guides/scopes#disposal) of the registered instances, but you can turn this feature off with the `withoutDisposalTracking` parameter.\n\nWhen an `IJob` is requested, the container will always return the external instance.\n\n</div>\n<div>\n<Tabs groupId=\"generic-runtime-apis\">\n<TabItem value=\"Generic API\" label=\"Generic API\">\n\n```cs\nvar job = new DbBackup();\ncontainer.RegisterInstance<IJob>(job);\n\n// resolvedJob and job are the same.\nIJob resolvedJob = container.Resolve<IJob>();\n```\n\n</TabItem>\n<TabItem value=\"Runtime type API\" label=\"Runtime type API\">\n\n```cs\nvar job = new DbBackup();\ncontainer.RegisterInstance(job, typeof(IJob));\n\n// resolvedJob and job are the same.\nobject resolvedJob = container.Resolve(typeof(IJob));\n```\n\n</TabItem>\n<TabItem value=\"Named\" label=\"Named\">\n\n```cs\nvar job = new DbBackup();\ncontainer.RegisterInstance<IJob>(job, \"DbBackup\");\n\n// resolvedJob and job are the same.\nIJob resolvedJob = container.Resolve<IJob>(\"DbBackup\");\n```\n\n</TabItem>\n<TabItem value=\"No dispose\" label=\"No dispose\">\n\n```cs\nvar job = new DbBackup();\ncontainer.RegisterInstance<IJob>(job, withoutDisposalTracking: true);\n\n// resolvedJob and job are the same.\nIJob resolvedJob = container.Resolve<IJob>();\n```\n\n</TabItem>\n</Tabs>\n</div>\n</CodeDescPanel>\n\n<CodeDescPanel>\n<div>\n\nThe instance registration API allows the batched registration of different instances.\n\n</div>\n<div>\n\n```cs\ncontainer.RegisterInstances<IJob>(new DbBackup(), new StorageCleanup());\nIEnumerable<IJob> jobs = container.ResolveAll<IJob>();\n```\n\n</div>\n</CodeDescPanel>\n\n## Re-mapping\n\n<CodeDescPanel>\n\n<div>\n\nWith re-map, you can bind new implementations to a [service type](/docs/getting-started/glossary#service-type--implementation-type) and delete old registrations in one action. \n\n:::caution\nWhen there are multiple registrations mapped to a [service type](/docs/getting-started/glossary#service-type--implementation-type), `.ReMap()` will replace all of them with the given [implementation type](/docs/getting-started/glossary#service-type--implementation-type). If you want to replace only one specific service, use the `.ReplaceExisting()` [configuration option](/docs/configuration/registration-configuration#replace).\n:::\n\n</div>\n<div>\n\n<Tabs groupId=\"generic-runtime-apis\">\n<TabItem value=\"Generic API\" label=\"Generic API\">\n\n```cs\ncontainer.Register<IJob, DbBackup>();\ncontainer.Register<IJob, StorageCleanup>();\n// jobs contain all two jobs\nIEnumerable<IJob> jobs = container.ResolveAll<IJob>();\n\ncontainer.ReMap<IJob, SlackMessageSender>();\n// jobs contains only the SlackMessageSender\njobs = container.ResolveAll<IJob>();\n```\n\n</TabItem>\n<TabItem value=\"Runtime type API\" label=\"Runtime type API\">\n\n```cs\ncontainer.Register(typeof(IJob), typeof(DbBackup));\ncontainer.Register(typeof(IJob), typeof(StorageCleanup));\n// jobs contain all two jobs\nIEnumerable<object> jobs = container.ResolveAll(typeof(IJob));\n\ncontainer.ReMap(typeof(IJob), typeof(SlackMessageSender));\n// jobs contains only the SlackMessageSender\njobs = container.ResolveAll(typeof(IJob));\n```\n\n</TabItem>\n</Tabs>\n</div>\n</CodeDescPanel>\n\n## Wiring up\n<CodeDescPanel>\n\n<div>\n\nWiring up is similar to [Instance registration](#instance-registration) except that the container will perform property/field injection (if configured so and applicable) on the registered instance during resolution.\n\n</div>\n<div>\n\n<Tabs groupId=\"generic-runtime-apis\">\n<TabItem value=\"Generic API\" label=\"Generic API\">\n\n```cs\ncontainer.WireUp<IJob>(new DbBackup());\nIJob job = container.Resolve<IJob>();\n```\n\n</TabItem>\n<TabItem value=\"Runtime type API\" label=\"Runtime type API\">\n\n```cs\ncontainer.WireUp(new DbBackup(), typeof(IJob));\nobject job = container.Resolve(typeof(IJob));\n```\n\n</TabItem>\n</Tabs>\n</div>\n</CodeDescPanel>\n\n## Lifetime shortcuts\n<CodeDescPanel>\n\n<div>\nA service's lifetime indicates how long its instance will live and which re-using policy should be applied when it gets injected.\n\nThis example shows how you can use the registration API's shortcuts for lifetimes. These are just sugars, and there are more ways explained in the [lifetimes](/docs/guides/lifetimes) section.\n\n:::info\nThe `DefaultLifetime` is [configurable](/docs/guides/lifetimes#default-lifetime).\n:::\n\n</div>\n<div>\n\n<Tabs groupId=\"generic-runtime-apis\">\n<TabItem value=\"Default\" label=\"Default\">\n\nWhen no lifetime is specified, the service will use the container's `DefaultLifetime`, which is `Transient` by default.\n\n```cs\ncontainer.Register<IJob, DbBackup>();\nIJob job = container.Resolve<IJob>();\n```\n\n</TabItem>\n<TabItem value=\"Singleton\" label=\"Singleton\">\n\nA service with `Singleton` lifetime will be instantiated once and reused during the container's lifetime.\n```cs\ncontainer.RegisterSingleton<IJob, DbBackup>();\nIJob job = container.Resolve<IJob>();\n```\n\n</TabItem>\n<TabItem value=\"Scoped\" label=\"Scoped\">\n\nThe `Scoped` lifetime behaves like a `Singleton` within a [scope](/docs/guides/scopes). \nA scoped service is instantiated once and reused during the scope's whole lifetime.\n```cs\ncontainer.RegisterScoped<IJob, DbBackup>();\nIJob job = container.Resolve<IJob>();\n```\n\n</TabItem>\n</Tabs>\n</div>\n</CodeDescPanel>\n"
  },
  {
    "path": "docs/docs/guides/lifetimes.md",
    "content": "import CodeDescPanel from '@site/src/components/CodeDescPanel';\nimport Tabs from '@theme/Tabs'; \nimport TabItem from '@theme/TabItem';\n\n# Lifetimes\n\nLifetime management controls how long a service's instances will live (from instantiation to [disposal](/docs/guides/scopes#disposal)) and how they will be reused between resolution requests.\n\n:::info\nChoosing the right lifetime helps you avoid [captive dependencies](/docs/diagnostics/validation#lifetime-validation).\n:::\n\n## Default lifetime\n\n<CodeDescPanel>\n<div>\n\nWhen you are not specifying a lifetime during registration, Stashbox will use the default lifetime. By default, it's set to [Transient](#transient-lifetime), but you can override it with the `.WithDefaultLifetime()` [container configuration option](/docs/configuration/container-configuration#default-lifetime). \n\nYou can choose either from the pre-defined lifetimes defined on the `Lifetimes` static class or use a [custom lifetime](#custom-lifetime).\n\n</div>\n<div>\n\n<Tabs>\n<TabItem value=\"Transient (default)\" label=\"Transient (default)\">\n\n```cs\nvar container = new StashboxContainer(options => options\n    .WithDefaultLifetime(Lifetimes.Transient));\n```\n\n</TabItem>\n<TabItem value=\"Singleton\" label=\"Singleton\">\n\n```cs\nvar container = new StashboxContainer(options => options\n    .WithDefaultLifetime(Lifetimes.Singleton));\n```\n\n</TabItem>\n<TabItem value=\"Scoped\" label=\"Scoped\">\n\n```cs\nvar container = new StashboxContainer(options => options\n    .WithDefaultLifetime(Lifetimes.Scoped));\n```\n\n</TabItem>\n</Tabs>\n</div>\n</CodeDescPanel>\n\n## Transient lifetime\n\n<CodeDescPanel>\n<div>\n\nA new instance is created for each resolution request. If a transient is referred by multiple consumers in the same [resolution tree](/docs/getting-started/glossary#resolution-tree), each will get a new instance.\n\n</div>\n<div>\n\n```cs\ncontainer.Register<IJob, DbBackup>(options => options\n    .WithLifetime(Lifetimes.Transient));\n```\n\n</div>\n</CodeDescPanel>\n\n:::info\nTransient services are not tracked for disposal by default, but this feature can be turned on with the `.WithDisposableTransientTracking()` [container configuration option](/docs/configuration/container-configuration#tracking-disposable-transients). When it's enabled, the current [scope](/docs/guides/scopes) on which the resolution request was initiated takes the responsibility to track and dispose transient services.\n:::\n\n## Singleton lifetime\n\n<CodeDescPanel>\n<div>\n\nA single instance is created and reused for each resolution request and injected into each consumer.\n\n:::note\nSingleton services are disposed when the container ([root scope](/docs/getting-started/glossary#root-scope)) is being disposed.\n:::\n\n</div>\n<div>\n\n<Tabs groupId=\"lifetime-forms\">\n<TabItem value=\"Longer form\" label=\"Longer form\">\n\n```cs\ncontainer.Register<IJob, DbBackup>(options => options\n    .WithLifetime(Lifetimes.Singleton));\n```\n\n</TabItem>\n<TabItem value=\"Shorter form\" label=\"Shorter form\">\n\n```cs\ncontainer.RegisterSingleton<IJob, DbBackup>();\n```\n\n</TabItem>\n</Tabs>\n</div>\n</CodeDescPanel>\n\n## Scoped lifetime\n\n<CodeDescPanel>\n<div>\n\nA new instance is created for each [scope](/docs/guides/scopes), which will be returned for every resolution request initiated on the given scope. It's like a singleton lifetime within a scope. \n\n:::note\nScoped services are disposed when their scope is being disposed.\n:::\n\n</div>\n<div>\n\n<Tabs groupId=\"lifetime-forms\">\n<TabItem value=\"Longer form\" label=\"Longer form\">\n\n```cs\ncontainer.Register<IJob, DbBackup>(options => options\n    .WithLifetime(Lifetimes.Scoped));\n\nusing var scope = container.BeginScope();\nIJob job = scope.Resolve<IJob>();\n```\n\n</TabItem>\n<TabItem value=\"Shorter form\" label=\"Shorter form\">\n\n```cs\ncontainer.RegisterScoped<IJob, DbBackup>();\n\nusing var scope = container.BeginScope();\nIJob job = scope.Resolve<IJob>();\n```\n\n</TabItem>\n</Tabs>\n</div>\n</CodeDescPanel>\n\n## Named scope lifetime\n\n<CodeDescPanel>\n<div>\n\nIt is the same as scoped lifetime, except the given service will be selected only when a scope with the same name initiates the resolution request.\n\nYou can also let a service [define](/docs/guides/scopes#service-as-scope) its own named scope. During registration, this scope can be referred to by its name upon using a named scope lifetime.\n\n</div>\n<div>\n\n<Tabs>\n<TabItem value=\"Named\" label=\"Named\">\n\n```cs\ncontainer.Register<IJob, DbBackup>(options => options\n    .InNamedScope(\"DbScope\"));\n\nusing var scope = container.BeginScope(\"DbScope\");\nIJob job = scope.Resolve<IJob>();\n```\n\n</TabItem>\n<TabItem value=\"Defined\" label=\"Defined\">\n\n```cs\ncontainer.Register<DbJobExecutor>(options => options\n    .DefinesScope());\n\nontainer.Register<IJob, DbBackup>(options => options\n    .InScopeDefinedBy<DbJobExecutor>());\n\n// the executor will begin a new scope within itself\n// when it gets resolved and DbBackup will be selected\n// and attached to that scope instead.\nusing var scope = container.BeginScope();\nDbJobExecutor executor = scope.Resolve<DbJobExecutor>();\n```\n\n</TabItem>\n<TabItem value=\"Defined with name\" label=\"Defined with name\">\n\n```cs\ncontainer.Register<DbJobExecutor>(options => options\n    .DefinesScope(\"DbScope\"));\n\nontainer.Register<IJob, DbBackup>(options => options\n    .InNamedScope(\"DbScope\"));\n\n// the executor will begin a new scope within itself\n// when it gets resolved and DbBackup will be selected\n// and attached to that scope instead.\nusing var scope = container.BeginScope();\nDbJobExecutor executor = scope.Resolve<DbJobExecutor>();\n```\n\n</TabItem>\n</Tabs>\n</div>\n</CodeDescPanel>\n\n:::note\nServices with named scope lifetime are disposed when the related named scope is being disposed.\n:::\n\n## Per-request lifetime\n\n<CodeDescPanel>\n<div>\n\nThe requested service will be reused within the whole resolution request. A new instance is created for each individual request .\n\n</div>\n<div>\n\n```cs\ncontainer.Register<IJob, DbBackup>(options => options\n    .WithPerRequestLifetime());\n```\n\n</div>\n</CodeDescPanel>\n\n## Auto lifetime\n\n<CodeDescPanel>\n<div>\n\nThe requested service's lifetime will align to the lifetime of its dependencies. When the requested service has a dependency with a higher lifespan, this lifetime will inherit that lifespan up to a given boundary.\n\n</div>\n<div>\n\n```cs\ncontainer.Register<IJob, DbBackup>(options => options\n    .WithAutoLifetime(Lifetimes.Scoped /* boundary lifetime */));\n```\n\n</div>\n</CodeDescPanel>\n\n<CodeDescPanel>\n<div>\n\nIf the requested service has auto lifetime with a scoped boundary and it has only transient dependencies, it'll inherit their transient lifetime.\n\n</div>\n<div>\n\n```cs\ncontainer.Register<ILogger, Logger>();\n\ncontainer.Register<IJob, DbBackup>(options => options\n    .WithAutoLifetime(Lifetimes.Scoped /* boundary lifetime */));\n\n// job has transient lifetime.\nvar job = container.Resolve<IJob>();\n```\n\n</div>\n</CodeDescPanel>\n\n<CodeDescPanel>\n<div>\n\nWhen there's a dependency with higher lifespan than the given boundary, the requested service will get the boundary lifetime.\n\n</div>\n<div>\n\n```cs\ncontainer.RegisterSingleton<ILogger, Logger>();\n\ncontainer.Register<IJob, DbBackup>(options => options\n    .WithAutoLifetime(Lifetimes.Scoped /* boundary lifetime */));\n\n// job has scoped lifetime.\nvar job = container.Resolve<IJob>();\n```\n\n</div>\n</CodeDescPanel>\n\n## Custom lifetime\nIf you'd like to use a custom lifetime, you can create your implementation by inheriting either from `FactoryLifetimeDescriptor` or from `ExpressionLifetimeDescriptor`, depending on how do you want to manage the service instances.\n\n- **ExpressionLifetimeDescriptor**: With this, you can build your lifetime with the expression form of the service instantiation.\n  ```cs\n  class CustomLifetime : ExpressionLifetimeDescriptor\n  {\n      protected override Expression ApplyLifetime(\n          Expression expression, // The expression which describes the service creation\n          ServiceRegistration serviceRegistration, \n          ResolutionContext resolutionContext, \n          Type requestedType)\n      {\n          // Lifetime managing functionality\n      }\n  }\n  ```\n\n- **FactoryLifetimeDescriptor**: With this, you can build your lifetime based on a pre-compiled factory delegate used for service instantiation.\n  ```cs\n  class CustomLifetime : FactoryLifetimeDescriptor\n  {\n      protected override Expression ApplyLifetime(\n          Func<IResolutionScope, object> factory, // The factory used for service creation\n          ServiceRegistration serviceRegistration, \n          ResolutionContext resolutionContext, \n          Type requestedType)\n      {\n          // Lifetime managing functionality\n      }\n  }\n  ```\n\nThen you can use your lifetime like this:\n```cs\ncontainer.Register<IJob, DbBackup>(options => options.WithLifetime(new CustomLifetime()));\n```"
  },
  {
    "path": "docs/docs/guides/scopes.md",
    "content": "import CodeDescPanel from '@site/src/components/CodeDescPanel';\nimport Tabs from '@theme/Tabs'; \nimport TabItem from '@theme/TabItem';\n\n# Scopes\nA scope is Stashbox's implementation of the unit-of-work pattern; it encapsulates a given unit used to resolve and store instances required for a given work. When a scoped service is resolved or injected, the scope ensures that it gets instantiated only once within the scope's lifetime. When the work is finished, the scope cleans up the resources by disposing each tracked disposable instance.\n\nA web application is a fair usage example for scopes as it has a well-defined execution unit that can be bound to a scope - the HTTP request. Every request could have its unique scope attached to the request's lifetime. When a request ends, the scope gets closed, and all the scoped instances will be disposed.\n\n## Creating a scope\n\n<CodeDescPanel>\n<div>\n\nYou can create a scope from the container by calling its `.BeginScope()` method.\n\nScopes can be **nested**, which means you can create sub-scopes from existing ones with their `.BeginScope()` method. \n\nScoped service instances are not shared across parent and sub-scope relations.\n\nNested scopes can be **attached to their parent's lifetime**, which means when a parent gets disposed all child scopes attached to it will be disposed.\n\nScopes are `IDisposable`; they track all `IDisposable` instances they resolved. Calling their `Dispose()` method or wrapping them in `using` statements is a crucial part of their service's lifetime management.\n\n</div>\n<div>\n\n<Tabs>\n<TabItem value=\"Create\" label=\"Create\">\n\n```cs\ncontainer.RegisterScoped<IJob, DbBackup>();\n\n// create the scope with using so it'll be auto disposed.\nusing (var scope = container.BeginScope())\n{\n    IJob job = scope.Resolve<IJob>();\n    IJob jobAgain = scope.Resolve<IJob>();\n    // job and jobAgain are created in the \n    // same scope, so they are the same instance.\n}\n```\n\n</TabItem>\n<TabItem value=\"Nested\" label=\"Nested\">\n\n```cs\ncontainer.RegisterScoped<IJob, DbBackup>();\n\nusing (var parent = container.BeginScope())\n{\n    IJob job = parent.Resolve<IJob>();\n    IJob jobAgain = parent.Resolve<IJob>();\n    // job and jobAgain are created in the \n    // same scope, so they are the same instance.\n\n    // create a sub-scope.\n    using var sub = parent.BeginScope();\n\n    IJob subJob = sub.Resolve<IJob>();\n    // subJob is a new instance created in the sub-scope, \n    // differs from either job and jobAgain.\n}\n```\n\n</TabItem>\n<TabItem value=\"Nested attached\" label=\"Nested attached\">\n\n```cs\ncontainer.RegisterScoped<IJob, DbBackup>();\n\nvar parent = container.BeginScope();\nvar sub = parent.BeginScope(attachToParent: true);\n\n// sub will also be disposed with the scope.\nscope.Dispose(); \n```\n\n</TabItem>\n</Tabs>\n</div>\n</CodeDescPanel>\n\n## Named scopes\n\n<CodeDescPanel>\n<div>\n\nThere might be cases where you don't want to use a service globally across every scope, only in specific ones. \n\nFor this reason, you can differentiate specific scope groups from other scopes with a **name**.\n\nYou can set a service's lifetime to [named scope lifetime](/docs/guides/lifetimes#named-scope-lifetime) initialized with the **scope's name** to mark it usable only for that named scope.\n\n```cs\ncontainer.Register<IJob, DbBackup>(options => \n    options.InNamedScope(\"DbScope\"));\n\ncontainer.Register<IJob, DbCleanup>(options => \n    options.InNamedScope(\"DbScope\"));\n\ncontainer.Register<IJob, DbIndexRebuild>(options => \n    options.InNamedScope(\"DbSubScope\"));\n\ncontainer.Register<IJob, StorageCleanup>(options => \n    options.InNamedScope(\"StorageScope\"));\n```\n\n:::note\nServices with named scope lifetime are **shared across parent and sub-scope relations**.\n:::\n\nIf you request a name-scoped service from an un-named scope, you'll get an error or no result (depending on the configuration) because those services are selectable only by named scopes with a matching name.\n\n</div>\n<div>\n\n```cs\nusing (var dbScope = container.BeginScope(\"DbScope\"))\n{ \n    // DbBackup and DbCleanup will be returned.\n    IEnumerable<IJob> jobs = dbScope.ResolveAll<IJob>();\n\n    // create a sub-scope of dbScope.\n    using var sub = dbScope.BeginScope();\n\n    // DbBackup and DbCleanup will be returned from the named parent scope.\n    IEnumerable<IJob> jobs = sub.ResolveAll<IJob>();\n\n    // create a named sub-scope.\n    using var namedSub = dbScope.BeginScope(\"DbSubScope\");\n    // DbIndexRebuild will be returned from the named sub-scope.\n    IEnumerable<IJob> jobs = namedSub.ResolveAll<IJob>();\n}\n\nusing (var storageScope = container.BeginScope(\"StorageScope\"))\n{\n    // StorageCleanup will be returned.\n    IJob job = storageScope.Resolve<IJob>();\n}\n\n// create a common scope without a name.\nusing (var unNamed = container.BeginScope())\n{\n    // empty result as there's no service registered without named scope.\n    IEnumerable<IJob> jobs = unNamed.ResolveAll<IJob>();\n\n    // throws an exception because there's no unnamed service registered.\n    IJob job = unNamed.Resolve<IJob>();\n}\n```\n\n</div>\n</CodeDescPanel>\n\n## Service as scope\n\n<CodeDescPanel>\n<div>\n\nYou can configure a service to behave like a nested named scope. At the resolution of this kind of service, a new dedicated named scope is created implicitly for managing the service's dependencies. \n\nWith this feature, you can organize your dependencies around logical groups (named scopes) instead of individual services.\n\nUsing `InScopeDefinedBy()`, you can bind services to a defined scope without giving it a name. In this case, the defining service's [implementation type](/docs/getting-started/glossary#service-type--implementation-type) is used for naming the scope.\n\n:::note\nThe lifetime of the defined scope is attached to the current scope that was used to create the service.\n:::\n\n</div>\n<div>\n\n<Tabs>\n<TabItem value=\"Define named\" label=\"Define named\">\n\n```cs\ncontainer.Register<IJob, DbBackup>(options => options\n    .DefinesScope(\"DbBackupScope\"));\ncontainer.Register<ILogger, ConsoleLogger>(options => options\n    .InNamedScope(\"DbBackupScope\"));\ncontainer.Register<ILogger, FileLogger>();\n\nvar scope = container.BeginScope();\n\n// DbBackup will create a named scope with the name \"DbBackupScope\".\n// the named scope will select ConsoleLogger as it's \n// bound to the named scope's identifier.\nIJob job = scope.Resolve<IJob>();\n\n// this will dispose the implicitly created named scope by DbBackup.\nscope.Dispose(); \n```\n\n</TabItem>\n<TabItem value=\"Define typed\" label=\"Define typed\">\n\n```cs\ncontainer.Register<IJob, DbBackup>(options => options\n    .DefinesScope());\ncontainer.Register<ILogger, ConsoleLogger>(options => options\n    .InScopeDefinedBy<DbBackup>());\ncontainer.Register<ILogger, FileLogger>();\n\nvar scope = container.BeginScope();\n\n// DbBackup will create a named scope with the name typeof(DbBackup).\n// the named scope will select ConsoleLogger as it's \n// bound to the named scope's identifier.\nIJob job = scope.Resolve<IJob>();\n\n// this will dispose the implicitly created named scope by DbBackup.\nscope.Dispose(); \n```\n\n</TabItem>\n</Tabs>\n</div>\n</CodeDescPanel>\n\n## Put instance to a scope\n\n<CodeDescPanel>\n<div>\n\nYou can add an already instantiated service to a scope. The instance's lifetime will be tracked by the given scope.\n\n</div>\n<div>\n\n```cs\nusing var scope = container.BeginScope();\nscope.PutInstanceInScope<IJob>(new DbBackup());\n```\n\n</div>\n</CodeDescPanel>\n\n<CodeDescPanel>\n<div>\n\nYou can disable the tracking by passing `true` for the `withoutDisposalTracking` parameter. In this case, only the strong reference to the instance is dropped when the scope is disposed.\n\n</div>\n<div>\n\n```cs\nusing var scope = container.BeginScope();\nscope.PutInstanceInScope<IJob>(new DbBackup(), withoutDisposalTracking: true);\n```\n\n</div>\n</CodeDescPanel>\n\n<CodeDescPanel>\n<div>\n\nYou can also give your instance a name to use it like a [named registration](/docs/guides/basics#named-registration):\n\n</div>\n<div>\n\n```cs\nusing var scope = container.BeginScope();\nscope.PutInstanceInScope<IDrow>(new DbBackup(), false, name: \"DbBackup\");\n```\n\n</div>\n</CodeDescPanel>\n\n:::note\nInstances put to a scope will take precedence over existing registrations with the same [service type](/docs/getting-started/glossary#service-type--implementation-type).\n:::\n\n## Disposal\n\n<CodeDescPanel>\n<div>\n\nThe currently resolving scope tracks services that implement either `IDisposable` or `IAsyncDisposable`. This means that when the scope is disposed, all the tracked disposable instances will be disposed with it.\n\n:::note\nDisposing the container will dispose all the singleton instances and their dependencies.\n:::\n\n</div>\n<div>\n\n<Tabs groupId=\"lifetime-dispose\">\n<TabItem value=\"Using\" label=\"Using\">\n\n```cs\nusing (var scope = container.BeginScope())\n{\n    var disposable = scope.Resolve<DisposableService>();\n} // 'disposable' will be disposed when \n  // the using statement ends.\n```\n\n</TabItem>\n<TabItem value=\"Dispose\" label=\"Dispose\">\n\n```cs\nvar scope = container.BeginScope();\nvar disposable = scope.Resolve<DisposableService>();\n\n// 'disposable' will be disposed with the scope.\nscope.Dispose();\n```\n\n</TabItem>\n</Tabs>\n</div>\n</CodeDescPanel>\n\n<CodeDescPanel>\n<div>\n\nYou can disable the disposal tracking on a [service registration](/docs/getting-started/glossary#service-registration--registered-service) with the `.WithoutDisposalTracking()` option.\n\n</div>\n<div>\n\n```cs\ncontainer.Register<IJob, DbBackup>(options => \n    options.WithoutDisposalTracking());\n```\n\n</div>\n</CodeDescPanel>\n\n<CodeDescPanel>\n<div>\n\n### Async disposal\nAs the container and its scopes implement the `IAsyncDisposable` interface, you can dispose them asynchronously when they are used in an `async` context.\n\nCalling `DisposeAsync` disposes both `IDisposable` and `IAsyncDisposable` instances; however, calling `Dispose` only disposes `IDisposable` instances.\n\n</div>\n<div>\n\n<Tabs groupId=\"lifetime-dispose\">\n<TabItem value=\"Using\" label=\"Using\">\n\n```cs\nawait using (var scope = container.BeginScope())\n{\n    var disposable = scope.Resolve<DisposableService>();\n} // 'disposable' will be disposed asynchronously \n  // when the using statement ends.\n```\n\n</TabItem>\n<TabItem value=\"Dispose\" label=\"Dispose\">\n\n```cs\nvar scope = container.BeginScope();\nvar disposable = scope.Resolve<DisposableService>();\n\n// 'disposable' will be disposed asynchronously with the scope.\nawait scope.DisposeAsync();\n```\n\n</TabItem>\n</Tabs>\n</div>\n</CodeDescPanel>\n\n<CodeDescPanel>\n<div>\n\n### Finalizer delegate\nDuring [service registration](/docs/getting-started/glossary#service-registration--registered-service), you can set a custom finalizer delegate that will be invoked at the service's disposal.\n\n</div>\n<div>\n\n```cs\ncontainer.Register<IJob, DbBackup>(options => \n    options.WithFinalizer(backup => \n        backup.CloseDbConnection()));\n```\n\n</div>\n</CodeDescPanel>\n"
  },
  {
    "path": "docs/docs/guides/service-resolution.md",
    "content": "import CodeDescPanel from '@site/src/components/CodeDescPanel';\nimport Tabs from '@theme/Tabs'; \nimport TabItem from '@theme/TabItem';\n\n# Service resolution\nWhen you have all your components registered and configured adequately, you can resolve them from the container or a [scope](/docs/guides/scopes) by requesting their [service type](/docs/getting-started/glossary#service-type--implementation-type).\n\nDuring a service's resolution, the container walks through the entire [resolution tree](/docs/getting-started/glossary#resolution-tree) and instantiates all dependencies required for the service construction.\nWhen the container encounters any violations of [these rules](/docs/diagnostics/validation#resolution-validation) *(circular dependencies, missing required services, lifetime misconfigurations)* during the walkthrough, it lets you know that something is wrong by throwing a specific exception.\n\n## Injection patterns\n\n<CodeDescPanel>\n<div>\n\n**Constructor injection** is the *primary dependency injection pattern*. It encourages the organization of dependencies to a single place - the constructor.\n\nStashbox, by default, uses the constructor that has the most parameters it knows how to resolve. This behavior is configurable through [constructor selection](/docs/configuration/registration-configuration#constructor-selection).\n\n[Property/field injection](/docs/configuration/registration-configuration#property-field-injection) is also supported in cases where constructor injection is not applicable.\n\nMembers defined with C# 11's [`required`](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/required) keyword are automatically injected by the container. \nThis behavior can be controlled with [registration](/docs/configuration/registration-configuration#required-member-injection) or [container](/docs/configuration/container-configuration#required-member-injection) configuration options \n\n:::info \n[Constructor selection](/docs/configuration/container-configuration#constructor-selection) and [property/field injection](/docs/configuration/container-configuration#auto-member-injection) is also configurable container-wide.\n:::\n\n</div>\n<div>\n\n<Tabs>\n<TabItem value=\"Constructor injection\" label=\"Constructor injection\">\n\n```cs\nclass DbBackup : IJob\n{\n    private readonly ILogger logger;\n    private readonly IEventBroadcaster eventBroadcaster;\n\n    public DbBackup(ILogger logger, IEventBroadcaster eventBroadcaster)\n    {\n        this.logger = logger;\n        this.eventBroadcaster = eventBroadcaster;\n    }\n}\n\ncontainer.Register<ILogger, ConsoleLogger>();\ncontainer.Register<IEventBroadcaster, MessageBus>();\n\ncontainer.Register<IJob, DbBackup>();\n\n// resolution using the available constructor.\nIJob job = container.Resolve<IJob>();\n```\n\n</TabItem>\n<TabItem value=\"Property/field injection\" label=\"Property/field injection\">\n\n```cs\nclass DbBackup : IJob\n{\n    public ILogger Logger { get; set; }\n    public IEventBroadcaster EventBroadcaster { get; set; }\n\n    public DbBackup() \n    { }\n}\n\ncontainer.Register<ILogger, ConsoleLogger>();\ncontainer.Register<IEventBroadcaster, MessageBus>();\n\n// registration of service with auto member injection.\ncontainer.Register<IJob, DbBackup>(options => \n    options.WithAutoMemberInjection());\n\n// resolution will inject the properties.\nIJob job = container.Resolve<IJob>();\n```\n\n</TabItem>\n</Tabs>\n</div>\n</CodeDescPanel>\n\n\n:::caution\nIt's a common mistake to use the *property/field injection* only to disencumber the constructor from having too many parameters. That's a code smell and also violates the [Single-responsibility principle](https://en.wikipedia.org/wiki/Single-responsibility_principle). If you recognize these conditions, you should consider splitting your class into multiple smaller units rather than adding an extra property-injected dependency. \n:::\n\n## Attributes\n\n<CodeDescPanel>\n<div>\n\nAttributes can give you control over how Stashbox selects dependencies for a service's resolution.\n\n**Dependency attribute**: \n- **On a constructor/method parameter**: used with the *name* property, it works as a marker for [named resolution](/docs/getting-started/glossary#named-resolution).\n\n- **On a property/field**: first, it enables *auto-injection* on the marked property/field (even if it wasn't configured at registration explicitly), and just as with the method parameter, it allows [named resolution](/docs/getting-started/glossary#named-resolution).\n\n**DependencyName attribute**: a parameter marked with this attribute will get the related service's dependency name.\n\n**InjectionMethod attribute**: marks a method to be called when the requested service is instantiated.\n\n</div>\n<div>\n\n<Tabs>\n<TabItem value=\"Constructor\" label=\"Constructor\">\n\n```cs\nclass DbBackup : IJob\n{\n    private readonly ILogger logger;\n\n    public DbBackup([Dependency(\"Console\")]ILogger logger)\n    {\n        this.logger = logger;\n    }\n}\n\ncontainer.Register<ILogger, ConsoleLogger>(\"Console\");\ncontainer.Register<ILogger, FileLogger>(\"File\");\n\ncontainer.Register<IJob, DbBackup>();\n\n// the container will resolve DbBackup with ConsoleLogger.\nIJob job = container.Resolve<IJob>();\n```\n\n</TabItem>\n<TabItem value=\"Property/field\" label=\"Property/field\">\n\n```cs\nclass DbBackup : IJob\n{\n    [Dependency(\"Console\")]\n    public ILogger Logger { get; set; }\n\n    public DbBackup() \n    { }\n}\n\ncontainer.Register<ILogger, ConsoleLogger>(\"Console\");\ncontainer.Register<ILogger, FileLogger>(\"File\");\n\ncontainer.Register<IJob, DbBackup>();\n\n// the container will resolve DbBackup with ConsoleLogger.\nIJob job = container.Resolve<IJob>();\n```\n\n</TabItem>\n<TabItem value=\"DependencyName\" label=\"DependencyName\">\n\n```cs\nclass DbBackup : IJob\n{\n    public string Name { get; set; }\n\n    public DbBackup([DependencyName] string name) \n    { }\n}\n\ncontainer.Register<IJob, DbBackup>(\"Backup\");\n\n\nIJob job = container.Resolve<IJob>();\n// name is \"Backup\".\nvar name = job.Name;\n```\n\n</TabItem>\n<TabItem value=\"Method\" label=\"Method\">\n\n```cs\nclass DbBackup : IJob\n{\n    [InjectionMethod]\n    public void Initialize([Dependency(\"Console\")]ILogger logger)\n    {\n        this.logger.Log(\"Initializing.\");\n    }\n}\n\ncontainer.Register<ILogger, ConsoleLogger>(\"Console\");\ncontainer.Register<ILogger, FileLogger>(\"File\");\n\ncontainer.Register<IJob, DbBackup>();\n\n// the container will call DbBackup's Initialize method.\nIJob job = container.Resolve<IJob>();\n```\n\n</TabItem>\n</Tabs>\n</div>\n</CodeDescPanel>\n\n\n:::caution\nAttributes provide a more straightforward configuration, but using them also tightens the bond between your application and Stashbox. If you consider this an issue, you can use the [dependency binding](/docs/guides/service-resolution#dependency-binding) API or [your own attributes](/docs/guides/service-resolution#using-your-own-attributes).\n:::\n\n### Using your own attributes\n\n<CodeDescPanel>\n<div>\nThere's an option to extend the container's dependency finding mechanism with your own attributes.\n\n- **Additional Dependency attributes**: you can use the [`.WithAdditionalDependencyAttribute()`](/docs/configuration/container-configuration#withadditionaldependencyattribute) container configuration option to let the container know that it should watch for additional attributes besides the built-in [`Dependency`](/docs/guides/service-resolution#attributes) attribute upon building up the [resolution tree](/docs/getting-started/glossary#resolution-tree).\n\n- **Additional DependencyName attributes**: you can use the [`.WithAdditionalDependencyNameAttribute()`](/docs/configuration/container-configuration#withadditionaldependencynameattribute) container configuration option to use additional dependency name indicator attributes besides the built-in [`DependencyName`](/docs/guides/service-resolution#attributes) attribute.\n\n</div>\n<div>\n\n<Tabs>\n<TabItem value=\"Dependency\" label=\"Dependency\">\n\n```cs\nclass DbBackup : IJob\n{\n    [CustomDependency(\"Console\")]\n    public ILogger Logger { get; set; }\n\n    public DbBackup() \n    { }\n}\n\nvar container = new StashboxContainer(options => options\n    .WithAdditionalDependencyAttribute<CustomDependencyAttribute>());\n\ncontainer.Register<ILogger, ConsoleLogger>(\"Console\");\ncontainer.Register<ILogger, FileLogger>(\"File\");\n\ncontainer.Register<IJob, DbBackup>();\n\n// the container will resolve DbBackup with ConsoleLogger.\nIJob job = container.Resolve<IJob>();\n```\n\n</TabItem>\n<TabItem value=\"DependencyName\" label=\"DependencyName\">\n\n```cs\nclass DbBackup : IJob\n{\n    public string Name { get; set; }\n\n    public DbBackup([CustomName] string name) \n    { }\n}\n\nvar container = new StashboxContainer(options => options\n    .WithAdditionalDependencyNameAttribute<CustomNameAttribute>());\n\ncontainer.Register<IJob, DbBackup>(\"Backup\");\n\nIJob job = container.Resolve<IJob>();\n// name is \"Backup\".\nvar name = job.Name;\n```\n\n</TabItem>\n</Tabs>\n\n</div>\n</CodeDescPanel>\n\n## Dependency binding\n\n<CodeDescPanel>\n<div>\n\nThe same dependency configuration functionality as attributes, but without attributes.\n\n- **Binding to a parameter**: the same functionality as the [`Dependency`](/docs/guides/service-resolution#attributes) attribute on a constructor or method parameter, enabling [named resolution](/docs/getting-started/glossary#named-resolution).\n\n- **Binding to a property/field**: the same functionality as the [`Dependency`](/docs/guides/service-resolution#attributes) attribute, enabling the injection of the given property/field.\n\n:::info\nThere are further dependency binding options [available](/docs/configuration/registration-configuration#dependency-configuration) on the registration configuration API.\n:::\n\n</div>\n<div>\n\n<Tabs>\n<TabItem value=\"Bind to parameter\" label=\"Bind to parameter\">\n\n```cs\nclass DbBackup : IJob\n{\n    public DbBackup(ILogger logger)\n    { }\n}\n\ncontainer.Register<ILogger, ConsoleLogger>(\"Console\");\ncontainer.Register<ILogger, FileLogger>(\"File\");\n\n// registration of service with the dependency binding.\ncontainer.Register<IJob, DbBackup>(options => options\n    .WithDependencyBinding(\"logger\", \"Console\"));\n\n// the container will resolve DbBackup with ConsoleLogger.\nIJob job = container.Resolve<IJob>();\n```\n\n</TabItem>\n<TabItem value=\"Bind to property / field\" label=\"Bind to property / field\">\n\n```cs\nclass DbBackup : IJob\n{\n    public ILogger Logger { get; set; }\n}\n\ncontainer.Register<ILogger, ConsoleLogger>(\"Console\");\ncontainer.Register<ILogger, FileLogger>(\"File\");\n\n// registration of service with the member injection.\ncontainer.Register<IJob, DbBackup>(options => options\n    .WithDependencyBinding(\"Logger\", \"Console\"));\n\n// the container will resolve DbBackup with ConsoleLogger.\nIJob job = container.Resolve<IJob>();\n```\n\n</TabItem>\n</Tabs>\n</div>\n</CodeDescPanel>\n\n## Conventional resolution\n\n<CodeDescPanel>\n<div>\n\nWhen you enable conventional resolution, the container treats member and method parameter names as their dependency identifier. \n\nIt's like an implicit dependency binding on every class member.\n\nFirst, you have to enable conventional resolution through the configuration of the container:  \n```cs\nnew StashboxContainer(options => options\n    .TreatParameterAndMemberNameAsDependencyName());\n```\n\n:::note\nThe container will attempt a [named resolution](/docs/getting-started/glossary#named-resolution) on each dependency based on their parameter or property/field name.\n:::\n\n</div>\n<div>\n\n\n<Tabs>\n<TabItem value=\"Parameters\" label=\"Parameters\">\n\n```cs\nclass DbBackup : IJob\n{\n    public DbBackup(\n        // the parameter name identifies the dependency.\n        ILogger consoleLogger)\n    { }\n}\n\ncontainer.Register<ILogger, ConsoleLogger>(\"consoleLogger\");\ncontainer.Register<ILogger, FileLogger>(\"fileLogger\");\n\ncontainer.Register<IJob, DbBackup>();\n\n// the container will resolve DbBackup with ConsoleLogger.\nIJob job = container.Resolve<IJob>();\n```\n\n</TabItem>\n<TabItem value=\"Properties / fields\" label=\"Properties / fields\">\n\n```cs\nclass DbBackup : IJob\n{\n    // the property name identifies the dependency.\n    public ILogger ConsoleLogger { get; set; }\n}\n\ncontainer.Register<ILogger, ConsoleLogger>(\"ConsoleLogger\");\ncontainer.Register<ILogger, FileLogger>(\"FileLogger\");\n\n// registration of service with auto member injection.\ncontainer.Register<IJob, DbBackup>(options => options\n    .WithAutoMemberInjection());\n\n// the container will resolve DbBackup with ConsoleLogger.\nIJob job = container.Resolve<IJob>();\n```\n\n</TabItem>\n</Tabs>\n</div>\n</CodeDescPanel>\n\n## Conditional resolution\n\n<CodeDescPanel>\n<div>\n\nStashbox can resolve a particular dependency based on its context. This context is typically the reflected type of dependency, its usage, and the type it gets injected into.\n\n- **Attribute**: you can filter on constructor, method, property, or field attributes to select the desired dependency for your service. In contrast to the `Dependency` attribute, this configuration doesn't tie your application to Stashbox because you use your own attributes.\n\n- **Parent type**: you can filter on what type the given service is injected into.\n\n- **Resolution path**: similar to the parent type and attribute condition but extended with inheritance. You can set that the given service is only usable in a type's resolution path. This means that each direct and sub-dependency of the selected type must use the provided service as a dependency.\n\n- **Custom**: with this, you can build your own selection logic based on the given contextual type information.\n\n</div>\n<div>\n\n<Tabs>\n<TabItem value=\"Attribute\" label=\"Attribute\">\n\n```cs\nclass ConsoleAttribute : Attribute { }\n\nclass DbBackup : IJob\n{\n    public DbBackup([Console]ILogger logger)\n    { }\n}\n\ncontainer.Register<ILogger, ConsoleLogger>(options => options\n    // resolve only when the injected parameter, \n    // property or field has the 'Console' attribute\n    .WhenHas<ConsoleAttribute>());\n\ncontainer.Register<IJob, DbBackup>();\n\n// the container will resolve DbBackup with ConsoleLogger.\nIJob job = container.Resolve<IJob>();\n```\n\n</TabItem>\n<TabItem value=\"Parent\" label=\"Parent\">\n\n```cs\nclass DbBackup : IJob\n{\n    public DbBackup(ILogger logger)\n    { }\n}\n\ncontainer.Register<ILogger, ConsoleLogger>(options => options\n    // inject only when we are \n    // currently resolving DbBackup OR StorageCleanup.\n    .WhenDependantIs<DbBackup>()\n    .WhenDependantIs<StorageCleanup>());\n\ncontainer.Register<IJob, DbBackup>();\n\n// the container will resolve DbBackup with ConsoleLogger.\nIJob job = container.Resolve<IJob>();\n```\n\n</TabItem>\n<TabItem value=\"Path\" label=\"Path\">\n\n```cs\nclass DbBackup : IJob\n{\n    public DbBackup(IStorage storage)\n    { }\n}\n\nclass FileStorage : IStorage\n{\n    public FileStorage(ILogger logger) \n    { }\n}\n\ncontainer.Register<ILogger, ConsoleLogger>(options => options\n    // inject only when we are in the\n    // resolution path of DbBackup\n    .WhenInResolutionPathOf<DbBackup>());\n\ncontainer.Register<IStorage, FileStorage>();\ncontainer.Register<IJob, DbBackup>();\n\n// the container will select ConsoleLogger for FileStorage\n// because they are injected into DbBackup.\nIJob job = container.Resolve<IJob>();\n```\n\n</TabItem>\n<TabItem value=\"Custom\" label=\"Custom\">\n\n```cs\nclass DbBackup : IJob\n{\n    public DbBackup(ILogger logger)\n    { }\n}\n\ncontainer.Register<ILogger, ConsoleLogger>(options => options\n    // inject only when we are \n    // currently resolving DbBackup.\n    .When(typeInfo => typeInfo.ParentType.Equals(typeof(DbBackup))));\n\ncontainer.Register<IJob, DbBackup>();\n\n// the container will resolve DbBackup with ConsoleLogger.\nIJob job = container.Resolve<IJob>();\n```\n\n</TabItem>\n<TabItem value=\"Collection\" label=\"Collection\">\n\n```cs\nclass DbJobsExecutor : IJobsExecutor\n{\n    public DbBackup(IEnumerable<IJob> jobs)\n    { }\n}\n\ncontainer.Register<IJob, DbBackup>(options => options\n    .WhenDependantIs<DbJobsExecutor>());\ncontainer.Register<IJob, DbCleanup>(options => options\n    .WhenDependantIs<DbJobsExecutor>());\nontainer.Register<IJob, StorageCleanup>();\n\ncontainer.Register<IJobsExecutor, DbJobsExecutor>();\n\n// jobsExecutor will get DbBackup and DbCleanup within a collection.\nIJobsExecutor jobsExecutor = container.Resolve<IJobsExecutor>();\n```\n\n</TabItem>\n</Tabs>\n</div>\n</CodeDescPanel>\n\nThe specified conditions are behaving like filters when a **collection** is requested.\n\nWhen you use the same conditional option multiple times, the container will evaluate them **with OR** logical operator.\n\n:::tip\n[Here](/docs/configuration/registration-configuration#conditions) you can find each condition related registration option.\n:::\n\n## Optional resolution\n\n<CodeDescPanel>\n<div>\n\nIn cases where it's not guaranteed that a service is resolvable, either because it's not registered or any of its dependencies are missing, you can attempt an optional resolution using the `ResolveOrDefault()` method. \n\nWhen the resolution attempt fails, it will return `null` (or `default` in case of value types).\n</div>\n<div>\n\n<Tabs groupId=\"generic-runtime-apis\">\n<TabItem value=\"Generic API\" label=\"Generic API\">\n\n```cs\n// returns null when the resolution fails.\nIJob job = container.ResolveOrDefault<IJob>();\n\n// throws ResolutionFailedException when the resolution fails.\nIJob job = container.Resolve<IJob>();\n```\n\n</TabItem>\n<TabItem value=\"Runtime type API\" label=\"Runtime type API\">\n\n```cs\n// returns null when the resolution fails.\nobject job = container.ResolveOrDefault(typeof(IJob));\n\n// throws ResolutionFailedException when the resolution fails.\nobject job = container.Resolve(typeof(IJob));\n```\n\n</TabItem>\n</Tabs>\n</div>\n</CodeDescPanel>\n\n## Dependency overrides\n\n<CodeDescPanel>\n<div>\n\nAt resolution time, you can override a service's dependencies by passing an `object[]` to the `Resolve()` method.\n\n```cs\nclass DbBackup : IJob\n{\n    public DbBackup(ILogger logger)\n    { }\n}\n```\n\n</div>\n<div>\n\n<Tabs groupId=\"generic-runtime-apis\">\n<TabItem value=\"Generic API\" label=\"Generic API\">\n\n```cs\nDbBackup backup = container.Resolve<DbBackup>( \n    dependencyOverrides: new object[] \n    { \n        new ConsoleLogger() \n    });\n```\n\n</TabItem>\n<TabItem value=\"Runtime type API\" label=\"Runtime type API\">\n\n```cs\nobject backup = container.Resolve(typeof(DbBackup),\n    dependencyOverrides: new object[] \n    { \n        new ConsoleLogger() \n    });\n```\n\n</TabItem>\n</Tabs>\n</div>\n</CodeDescPanel>\n\n<CodeDescPanel>\n<div>\n\nTo get more control over your overrides (like giving them name to allow [named resolution](/docs/getting-started/glossary#named-resolution)), you can use the `Override` built-in wrapper.\n\n```cs\nclass DbBackup : IJob\n{\n    public DbBackup([Dependency(\"console\")]ILogger logger)\n    { }\n}\n```\n\n</div>\n<div>\n\n<Tabs groupId=\"generic-runtime-apis\">\n<TabItem value=\"Generic API\" label=\"Generic API\">\n\n```cs\nDbBackup backup = container.Resolve<DbBackup>( \n    dependencyOverrides: new object[] \n    { \n        Override.Of<ILogger>(new ConsoleLogger(), \"console\"), \n    });\n```\n\n</TabItem>\n<TabItem value=\"Runtime type API\" label=\"Runtime type API\">\n\n```cs\nobject backup = container.Resolve(typeof(DbBackup),\n    dependencyOverrides: new object[] \n    { \n        Override.Of(typeof(ILogger), new ConsoleLogger(), \"console\"), \n    });\n```\n\n</TabItem>\n</Tabs>\n</div>\n</CodeDescPanel>\n\n## Activation\n\n<CodeDescPanel>\n<div>\n\nYou can use the container's `.Activate()` method when you only want to build up an instance from a type on the fly without registration.\n\nIt allows dependency overriding with `object` arguments and performs property/field/method injection (when configured).\n\nIt works like `Activator.CreateInstance()` except that Stashbox supplies the dependencies.\n\n</div>\n<div>\n\n<Tabs groupId=\"generic-runtime-apis\">\n<TabItem value=\"Generic API\" label=\"Generic API\">\n\n```cs\n// use dependency injected by container.\nDbBackup backup = container.Activate<DbBackup>();\n\n// override the injected dependency.\nDbBackup backup = container.Activate<DbBackup>(new ConsoleLogger());\n```\n\n</TabItem>\n<TabItem value=\"Runtime type API\" label=\"Runtime type API\">\n\n```cs\n// use dependency injected by container.\nobject backup = container.Activate(typeof(DbBackup));\n\n// override the injected dependency.\nobject backup = container.Activate(typeof(DbBackup), new ConsoleLogger());\n```\n\n</TabItem>\n</Tabs>\n</div>\n</CodeDescPanel>\n\n<CodeDescPanel>\n<div>\n\n### Build-up\n\nWith the `.BuildUp()` method, you can do the same *on the fly* post-processing (property/field/method injection) on already constructed instances. \n\n:::caution\n`.BuildUp()` won't register the given instance into the container.\n:::\n</div>\n<div>\n\n```cs\nclass DbBackup : IJob\n{\n    public ILogger Logger { get; set; }\n}\n\nDbBackup backup = new DbBackup();\n// the container fills the Logger property.\ncontainer.BuildUp(backup); \n```\n\n</div>\n</CodeDescPanel>"
  },
  {
    "path": "docs/docusaurus.config.js",
    "content": "// @ts-check\n// @ts-ignore\nimport { themes } from 'prism-react-renderer';\nconst prismLightTheme = themes.github;\n\n/** @type {import('@docusaurus/types').Config} */\nconst config = {\n  title: 'Stashbox',\n  tagline: 'A lightweight, fast, and portable .NET DI framework.',\n  url: 'https://z4kn4fein.github.io',\n  baseUrl: '/stashbox',\n  onBrokenLinks: 'throw',\n  onBrokenMarkdownLinks: 'warn',\n  favicon: 'img/favicon.ico',\n\n  organizationName: 'z4kn4fein',\n  projectName: 'stashbox',\n  trailingSlash: false,\n\n  i18n: {\n    defaultLocale: 'en',\n    locales: ['en'],\n  },\n\n  presets: [\n    [\n      'classic',\n      /** @type {import('@docusaurus/preset-classic').Options} */\n      ({\n        docs: {\n          sidebarPath: require.resolve('./sidebars.js'),\n          showLastUpdateAuthor: true,\n          showLastUpdateTime: true,\n          sidebarCollapsible: true,\n          editUrl:\n            'https://github.com/z4kn4fein/stashbox/edit/master/docs',\n        },\n        theme: {\n          customCss: require.resolve('./src/css/custom.scss'),\n        },\n        gtag: {\n          trackingID: 'G-HLNT9WV1HH'\n        }\n      }),\n    ],\n  ],\n\n  plugins: [\n    'docusaurus-plugin-sass',\n  ],\n\n  themeConfig:\n    /** @type {import('@docusaurus/preset-classic').ThemeConfig} */\n    ({\n      navbar: {\n        hideOnScroll: true,\n        title: 'Stashbox',\n        logo: {\n          alt: 'Stashbox logo',\n          src: 'img/icon.png',\n        },\n        items: [\n          {\n            type: 'dropdown',\n            position: 'left',\n            label: 'Extensions',\n            items: [\n              {\n                type: 'html',\n                className: 'navbar-title',\n                value: '<b>.NET Core</b>',\n              },\n              {\n                href: 'https://github.com/z4kn4fein/stashbox-extensions-dependencyinjection#aspnet-core',\n                label: 'ASP.NET Core',\n              },\n              {\n                href: 'https://github.com/z4kn4fein/stashbox-extensions-dependencyinjection#multitenant',\n                label: 'ASP.NET Core Multitenant',\n              },\n              {\n                href: 'https://github.com/z4kn4fein/stashbox-extensions-dependencyinjection#testing',\n                label: 'ASP.NET Core Testing',\n              },\n              {\n                href: 'https://github.com/z4kn4fein/stashbox-extensions-dependencyinjection#net-generic-host',\n                label: '.NET Generic Host',\n              },\n              {\n                href: 'https://github.com/z4kn4fein/stashbox-extensions-dependencyinjection#servicecollection-based-applications',\n                label: 'ServiceCollection Extensions',\n              },\n              {\n                type: 'html',\n                value: '<hr class=\"dropdown-separator\">',\n              },\n              {\n                type: 'html',\n                className: 'navbar-title',\n                value: '<b>ASP.NET</b>',\n              },\n              {\n                href: 'https://github.com/z4kn4fein/stashbox-extensions/tree/main/src/stashbox-web-webapi',\n                label: 'Web API',\n              },\n              {\n                href: 'https://github.com/z4kn4fein/stashbox-extensions/tree/main/src/stashbox-web-mvc',\n                label: 'MVC',\n              },\n              {\n                href: 'https://github.com/z4kn4fein/stashbox-extensions/tree/main/src/stashbox-signalr',\n                label: 'SignalR',\n              },\n              {\n                type: 'html',\n                value: '<hr class=\"dropdown-separator\">',\n              },\n              {\n                type: 'html',\n                className: 'navbar-title',\n                value: '<b>OWIN</b>',\n              },\n              {\n                href: 'https://github.com/z4kn4fein/stashbox-extensions/tree/main/src/stashbox-owin',\n                label: 'OWIN',\n              },\n              {\n                href: 'https://github.com/z4kn4fein/stashbox-extensions/tree/main/src/stashbox-webapi-owin',\n                label: 'Web API',\n              },\n              {\n                href: 'https://github.com/z4kn4fein/stashbox-extensions/tree/main/src/stashbox-signalr-owin',\n                label: 'SignalR',\n              },\n              {\n                type: 'html',\n                value: '<hr class=\"dropdown-separator\">',\n              },\n              {\n                type: 'html',\n                className: 'navbar-title',\n                value: '<b>Other</b>',\n              },\n              {\n                href: 'https://github.com/z4kn4fein/stashbox-extensions/tree/main/src/stashbox-hangfire',\n                label: 'Hangfire',\n              },\n              {\n                href: 'https://github.com/z4kn4fein/stashbox-mocking',\n                label: 'Mocking',\n              },\n            ]\n          },\n          {\n            type: 'dropdown',\n            position: 'left',\n            label: 'Benchmarks',\n            items: [\n              {\n                href: 'https://danielpalme.github.io/IocPerformance',\n                label: 'Performance',\n              },\n            ]\n          },\n          {\n            position: 'left',\n            label: 'Changelog',\n            href: 'https://github.com/z4kn4fein/stashbox/releases'\n          },\n          {\n            type: 'custom-icon',\n            icon: 'nuget',\n            position: 'right',\n            className: 'nav-icon',\n            href: 'https://www.nuget.org/packages/Stashbox'\n          },\n          {\n            type: 'custom-icon',\n            icon: 'github',\n            position: 'right',\n            className: 'nav-icon',\n            href: 'https://github.com/z4kn4fein/stashbox'\n          },\n          {\n            type: 'custom-separator',\n            position: 'right',\n          },\n        ],\n      },\n      footer: {\n        style: 'dark',\n        links: [\n          {\n            title: 'GUIDES',\n            items: [\n              { label: 'Basic usage', to: 'docs/guides/basics' },\n              { label: 'Advanced registration', to: 'docs/guides/advanced-registration' },\n              { label: 'Service resolution', to: 'docs/guides/service-resolution' },\n              { label: 'Lifetimes', to: 'docs/guides/lifetimes' },\n              { label: 'Scopes', to: 'docs/guides/scopes' },\n            ],\n          },\n          {\n            title: 'ADVANCED',\n            items: [\n              { label: 'Generics', to: 'docs/advanced/generics' },\n              { label: 'Decorators', to: 'docs/advanced/decorators' },\n              { label: 'Wrappers & resolvers', to: 'docs/advanced/wrappers-resolvers' },\n              { label: 'Child containers', to: 'docs/advanced/child-containers' },\n              { label: 'Special resolution cases', to: 'docs/advanced/special-resolution-cases' },\n            ],\n          }\n        ],\n        copyright: `Copyright © ${new Date().getFullYear()} Peter Csajtai. Built with Docusaurus.`,\n      },\n      docs: {\n        sidebar: {\n          hideable: true,\n        },\n      },\n      prism: {\n        theme: prismLightTheme,\n        additionalLanguages: [\n          'csharp',\n          'powershell',\n          'bash',\n        ],\n      },\n      colorMode: {\n        defaultMode: 'light',\n        disableSwitch: false,\n        respectPrefersColorScheme: true,\n      },\n      algolia: {\n        appId: 'CYYLE77D6F',\n        apiKey: '70fdb3ec7ec00e65922f35e5a5e35562',\n        indexName: 'stashbox'\n      },\n    }),\n};\n\nasync function createConfig() {\n  const darkTheme = (await import('./src/utils/prismDark.mjs')).default;\n  // @ts-expect-error: it exists\n  config.themeConfig.prism.darkTheme = darkTheme;\n  return config;\n}\n\nmodule.exports = createConfig;\n"
  },
  {
    "path": "docs/package.json",
    "content": "{\n  \"name\": \"website\",\n  \"version\": \"0.0.0\",\n  \"private\": true,\n  \"scripts\": {\n    \"docusaurus\": \"docusaurus\",\n    \"start\": \"docusaurus start\",\n    \"build\": \"docusaurus build\",\n    \"swizzle\": \"docusaurus swizzle\",\n    \"deploy\": \"docusaurus deploy\",\n    \"clear\": \"docusaurus clear\",\n    \"serve\": \"docusaurus serve\",\n    \"write-translations\": \"docusaurus write-translations\",\n    \"write-heading-ids\": \"docusaurus write-heading-ids\"\n  },\n  \"dependencies\": {\n    \"@docusaurus/core\": \"3.9.2\",\n    \"@docusaurus/preset-classic\": \"3.9.2\",\n    \"@mdx-js/react\": \"^3.0.0\",\n    \"clsx\": \"^2.0.0\",\n    \"docusaurus-plugin-sass\": \"^0.2.6\",\n    \"prism-react-renderer\": \"^2.1.0\",\n    \"react\": \"^18.2.0\",\n    \"react-dom\": \"^18.2.0\",\n    \"sass\": \"^1.69.5\"\n  },\n  \"devDependencies\": {\n    \"@docusaurus/module-type-aliases\": \"3.0.0\"\n  },\n  \"browserslist\": {\n    \"production\": [\n      \">0.5%\",\n      \"not dead\",\n      \"not op_mini all\"\n    ],\n    \"development\": [\n      \"last 1 chrome version\",\n      \"last 1 firefox version\",\n      \"last 1 safari version\"\n    ]\n  },\n  \"engines\": {\n    \"node\": \">=20.0\"\n  }\n}\n"
  },
  {
    "path": "docs/sidebars.js",
    "content": "/** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */\nconst sidebars = {\n  docs: [\n    {\n      type: 'category',\n      label: 'Get started',\n      collapsed: false,\n      items: [\n        'getting-started/overview',\n        'getting-started/introduction',\n        'getting-started/glossary',\n      ],\n    },\n    {\n      type: 'category',\n      label: 'Guides',\n      collapsed: false,\n      items: [\n        'guides/basics',\n        'guides/advanced-registration',\n        'guides/service-resolution',\n        'guides/lifetimes',\n        'guides/scopes',\n      ],\n    },\n    {\n      type: 'category',\n      label: 'Configuration',\n      collapsed: false,\n      items: [\n        'configuration/registration-configuration',\n        'configuration/container-configuration',\n      ],\n    },\n    {\n      type: 'category',\n      label: 'Advanced',\n      collapsed: false,\n      items: [\n        'advanced/generics',\n        'advanced/decorators',\n        'advanced/wrappers-resolvers',\n        'advanced/child-containers',\n        'advanced/special-resolution-cases',\n      ],\n    },\n    {\n      type: 'category',\n      label: 'Diagnostics',\n      collapsed: false,\n      items: [\n        'diagnostics/validation',\n        'diagnostics/utilities',\n      ],\n    },\n  ]\n};\n\nmodule.exports = sidebars;\n"
  },
  {
    "path": "docs/src/components/CodeDescPanel/index.tsx",
    "content": "import React from 'react';\nimport styles from './styles.module.scss';\n\nexport default function CodeDescPanel({children}) {\n  let notNullChildren = React.Children.toArray(children).filter(c => c);\n  return (\n    <div className={styles.codeDescContainer}>\n        <div className={styles.desc}>\n          {notNullChildren[0]}\n        </div>\n        <div className={styles.example}>\n          {notNullChildren[1]}\n        </div>\n    </div>\n  );\n}"
  },
  {
    "path": "docs/src/components/CodeDescPanel/styles.module.scss",
    "content": ".codeDescContainer {\n    width: 100%;\n    display: inline-block;\n}\n\n.desc {\n    float: left;\n    max-width: 45%;\n    width: 45%;\n    padding-right: 10px;\n}\n\n.example {\n    width: 55%;\n    max-width: 55%;\n    padding-left: 10px;\n    display: inline-block;\n}\n\n@media screen and (max-width: 996px) {\n    .desc {\n        float: none;\n        max-width: 100%;\n        width: 100%;\n        padding-right: 0px;\n    }\n    \n    .example {\n        width: 100%;\n        max-width: 100%;\n        padding-left: 0px;\n        display: block;\n    }\n}"
  },
  {
    "path": "docs/src/components/NavbarItems/SeparatorNavbarItem/index.tsx",
    "content": "import React from 'react';\nimport clsx from 'clsx';\nimport styles from './styles.module.scss';\n\nexport default function SeparatorNavbarItem({mobile, ...props}): JSX.Element {\n    return <div {...props} className={clsx(props.className, styles.separator)} />;\n}"
  },
  {
    "path": "docs/src/components/NavbarItems/SeparatorNavbarItem/styles.module.scss",
    "content": ".separator {\n    height: 1.7rem;\n    width: 1px;\n    background-color: var(--ifm-navbar-link-color);\n    opacity: .2;\n    margin: 0 12px 0 8px;\n}\n\n@media screen and (max-width: 996px) {\n    .separator {\n        display: none;\n    }\n}"
  },
  {
    "path": "docs/src/components/NavbarItems/SvgNavbarItem/index.tsx",
    "content": "import useBaseUrl from '@docusaurus/useBaseUrl';\nimport clsx from 'clsx';\nimport React from 'react';\nimport SvgIcon from '../../SvgIcon';\nimport styles from './styles.module.scss';\n\nexport default function SvgNavbarItem({icon, href, mobile, ...props}): JSX.Element {\n    return (\n        <div className={clsx(props.className, styles.icon_container)}>\n            <a\n            {...props}\n            className={styles.link}\n            href={useBaseUrl(href)}\n            target=\"_blank\"\n            rel=\"noreferrer noopener\"\n            >\n                <SvgIcon icon={icon} className={styles.icon} />\n            </a>\n        </div>\n    );\n}"
  },
  {
    "path": "docs/src/components/NavbarItems/SvgNavbarItem/styles.module.scss",
    "content": ".icon_container {\n    display: flex;\n    align-items: center;\n}\n\n.icon {\n    color: var(--ifm-navbar-link-color);\n    width: 24px;\n    height: 24px;\n    transition: opacity .2s;\n    display: flex;\n    align-items: center;\n}\n\n.icon:hover {\n    opacity: .7;\n}\n\n.link {\n    padding: 0 10px;\n}"
  },
  {
    "path": "docs/src/components/SvgIcon/index.tsx",
    "content": "import React from 'react';\nimport GitHubSvg from '@site/static/img/github.svg';\nimport ApiSvg from '@site/static/img/api.svg';\nimport GitterSvg from '@site/static/img/gitter.svg';\nimport SlackSvg from '@site/static/img/slack.svg';\nimport NuGetSvg from '@site/static/img/nuget.svg';\n\nexport default function SvgIcon({icon, ...props}): JSX.Element {\n    return (\n        {\n            'github': <GitHubSvg {...props} />,\n            'api': <ApiSvg {...props} />,\n            'gitter': <GitterSvg {...props} />,\n            'slack': <SlackSvg {...props} />,\n            'nuget': <NuGetSvg {...props} />,\n        }[icon] || null\n    );\n}"
  },
  {
    "path": "docs/src/css/custom.scss",
    "content": "/**\n * Any CSS included here will be global. The classic template\n * bundles Infima by default. Infima is a CSS framework designed to\n * work well for content-centric websites.\n */\n\n@use 'sidebar';\n@use 'toc';\n@use 'pagination';\n@use 'tab';\n@use 'search';\n\n:root {\n  --ifm-color-primary: #3385b5;\n  --ifm-color-primary-dark: #2e78a3;\n  --ifm-color-primary-darker: #2b719a;\n  --ifm-color-primary-darkest: #245d7f;\n  --ifm-color-primary-light: #3892c7;\n  --ifm-color-primary-lighter: #4197ca;\n  --ifm-color-primary-lightest: #5ca6d1;\n\n  --ifm-menu-color: var(--ifm-color-content-secondary);\n  --menu-secondary-color: rgb(83, 83, 95);\n  --base-contrast-background-color: var(--ifm-color-primary);\n  --base-contrast-background-hover-color: var(--ifm-color-primary-dark);\n\n  @media (min-width: 1840px) {\n    --ifm-container-width-xl: 1440px;\n  }\n}\n\n[data-theme='dark'] {\n  --ifm-color-primary: #43c8ff;\n  --ifm-color-primary-dark: #23bfff;\n  --ifm-color-primary-darker: #13baff;\n  --ifm-color-primary-darkest: #009fe1;\n  --ifm-color-primary-light: #63d1ff;\n  --ifm-color-primary-lighter: #73d6ff;\n  --ifm-color-primary-lightest: #a4e4ff;\n  \n  --menu-secondary-color: rgb(192, 192, 199);\n  --base-contrast-background-color: var(--ifm-color-primary-darkest);\n  --base-contrast-background-hover-color: #0079ad;\n\n  h2 {\n    border-bottom: 1px solid rgba(122, 122, 122, 0.3);\n  }\n}\n\n.theme-doc-sidebar-container .button--outline {\n  border: 0 !important;\n  background-color: var(--ifm-hover-overlay);\n  margin-right: 1px;\n}\n\n.theme-doc-sidebar-container div[role='button'] {\n  background-color: var(--ifm-hover-overlay);\n}\n\n.dropdown__link svg {\n  opacity: .5;\n  width: 10px;\n  height: 10px;\n}\n\n.navbar-title {\n  font-size: .875rem;\n  padding: 0.2rem 0.2rem;\n  font-weight: 500;\n}\n\n.dropdown-separator {\n  margin: 0.3rem 0;\n  opacity: .3;\n}\n\nh1, h2 {\n  font-weight: 600;\n}\n\nh2 {\n  border-bottom: 1px solid rgba(165, 165, 165, 0.3);\n  padding-bottom: 5px;\n}\n\n.dropdown__link {\n  color: var(--menu-secondary-color);\n  font-weight: 400;\n}\n\n.button--mid {\n  --ifm-button-size-multiplier: 1.1;\n}\n\n@media screen and (max-width: 460px) {\n  .button--mid {\n    --ifm-button-size-multiplier: 1;\n  }\n}"
  },
  {
    "path": "docs/src/css/pagination.scss",
    "content": ".pagination-nav__link {\n    background-color: var(--base-contrast-background-color);\n    border: none;\n    color: #fff;\n    transition: background-color .2s;\n}\n\n.pagination-nav__link:hover {\n    background-color: var(--base-contrast-background-hover-color);\n    color: #fff;\n}\n\n.pagination-nav__sublabel {\n    display: none;\n}\n\n.pagination-nav__link--next .pagination-nav__label {\n    transition: padding-right .2s;\n    padding-right: .25rem;\n}\n\n.pagination-nav__link--next:hover .pagination-nav__label {\n    padding-right: 0;\n}\n\n.pagination-nav__link--prev .pagination-nav__label {\n    transition: padding-left .2s;\n    padding-left: .25rem;\n}\n\n.pagination-nav__link--prev:hover .pagination-nav__label {\n    padding-left: 0;\n}"
  },
  {
    "path": "docs/src/css/search.scss",
    "content": "div[class^='searchBox'], div[class*=' searchBox']{\n    position: static;\n}\n\n@media (max-width: 996px) {\n    div[class^='searchBox'], div[class*=' searchBox']{\n        margin-left: 8px !important;\n    }\n}"
  },
  {
    "path": "docs/src/css/sidebar.scss",
    "content": ".menu__list-item-collapsible {\n    font-size: 13px;\n    font-weight: 600;\n    text-transform: uppercase;\n\n    .menu__link--active {\n        color: var(--ifm-menu-color);\n    }\n}\n\n.menu>.menu__list .menu__list {\n    font-size: 14px;\n    font-weight: 400;\n    margin-bottom: 4px;\n    padding-left: 14px;\n\n    .menu__link {\n        padding-top: 8px;\n        padding-bottom: 8px;\n        border-top-left-radius: 0;\n        border-bottom-left-radius: 0;\n    }\n\n    .menu__link:not(.menu__link--active) {\n        color: var(--menu-secondary-color);\n        padding-left: 13px;\n        border-left: 1px solid var(--ifm-toc-border-color);\n        margin-left: 3px;\n    }\n\n    .menu__link--active {\n        border-left: 3px solid var(--ifm-color-primary);\n        margin-left: 2px;\n    }\n}\n\n.menu__list-item {\n    .dropdown-separator {\n      display: none;\n    }\n\n    &:not(:first-child) {\n        margin-top: 0;\n    }\n}\n  \n.menu__list {\n    .nav-icon {\n      display: none;\n    }\n}"
  },
  {
    "path": "docs/src/css/tab.scss",
    "content": "li[role='tab'] {\n    font-weight: 500;\n    font-size: 14px;\n    padding: .6rem 1rem;\n  }\n\nli[role='tab'][aria-selected='true'] {\n  background-color: var(--base-contrast-background-color);\n  border: 1px solid var(--base-contrast-background-color);\n  color: #fff;\n  transition: border .2s;\n  border-radius: var(--ifm-global-radius);\n}\n\nli[role='tab'][aria-selected='false'] {\n  opacity: .8;\n  transition: opacity .2s;\n  border: 1px solid var(--ifm-color-emphasis-200)\n}\n\nli[role='tab'][aria-selected='false']:hover {\n    opacity: 1;\n  }\n\nli[role='tab']:not(:first-of-type) {\n  margin-left: 5px;\n}\n\n[data-theme='light'] {\n  li[role='tab'][aria-selected='true'] {\n    background-color: var(--base-contrast-background-color);\n    border: 1px solid var(--base-contrast-background-color);\n  }\n}\n\n@media screen and (max-width: 996px) {\n  li[role='tab'] {\n    padding: .6rem .5rem;\n  }\n}"
  },
  {
    "path": "docs/src/css/toc.scss",
    "content": ".table-of-contents {\n    font-size: 13px;\n}\n\n.table-of-contents__link:not(.table-of-contents__link--active) {\n    color: var(--menu-secondary-color);\n}\n\n.table-of-contents__link:hover {\n    color: var(--ifm-color-primary);\n}\n\n.table-of-contents li {\n    position: relative;\n}\n\nul ul .table-of-contents__link--active:before {\n    left: -33px;\n}\n\n.table-of-contents__link--active:before {\n    background: var(--ifm-color-primary);\n    width: 2px;\n    position: absolute;\n    bottom: 0;\n    left: -17px;\n    top: 0;\n    content: \" \";\n}"
  },
  {
    "path": "docs/src/pages/index.js",
    "content": "import Link from '@docusaurus/Link';\nimport useDocusaurusContext from '@docusaurus/useDocusaurusContext';\nimport useBaseUrl from '@docusaurus/useBaseUrl';\nimport Layout from '@theme/Layout';\nimport React from 'react';\nimport styles from './index.module.scss';\n\n\nfunction HomepageHeader() {\n  const {siteConfig} = useDocusaurusContext();\n  return (\n    <header className={styles.heroBanner}>\n      <div className=\"container\">\n        <img src={useBaseUrl('/img/icon.png')} alt=\"Logo\" className={styles.logo}></img>\n\n        <h1 className={styles.title}>{siteConfig.title}</h1>\n        <p className={styles.subtitle}>{siteConfig.tagline}</p>\n\n        <div className={styles.attributes}>\n          🚀 Thread-safe and lock-free.<br />\n          ⚡️️ Easy-to-use Fluent API.<br />\n          ♻️ Small memory footprint.<br />\n        </div>\n\n        <div className={styles.installContainer}>\n          <div className={styles.install}>\n            <pre><span className={styles.command_start}>{'$'} </span><span className={styles.command}>dotnet</span><span> add package Stashbox</span><span className={styles.options}> --version</span> 5.20.0<span className={styles.cursor}></span></pre>\n          </div>\n        </div>\n       \n        <div className={styles.buttons}>\n          <Link\n            className=\"button button--primary button--mid\"\n            to=\"/docs/getting-started/overview\">\n            Get Started\n          </Link>\n          <Link\n            className=\"button button--secondary button--outline button--mid\"\n            to=\"https://github.com/z4kn4fein/stashbox\">\n            GitHub\n          </Link>\n          <Link\n            className=\"button button--secondary button--outline button--mid\"\n            to=\"https://www.nuget.org/packages/Stashbox\">\n            NuGet\n          </Link>\n        </div>\n      </div>\n    </header>\n  );\n}\n\nexport default function Home() {\n  const {siteConfig} = useDocusaurusContext();\n  return (\n    <Layout\n      title={`${siteConfig.title} Documentation`}\n      description=\"Stashbox is a lightweight, fast, and portable dependency injection framework for .NET-based solutions. It encourages the building of loosely coupled applications and simplifies the construction of hierarchical object structures. It can be integrated easily with .NET Core, Generic Host, ASP.NET, Xamarin, and many other applications.\">\n      <HomepageHeader />\n    </Layout>\n  );\n}\n"
  },
  {
    "path": "docs/src/pages/index.module.scss",
    "content": "/**\n * CSS files with the .module.css suffix will be treated as CSS modules\n * and scoped locally.\n */\n\n.heroBanner {\n  padding: 4rem 0;\n  text-align: center;\n  position: relative;\n  overflow: hidden;\n}\n\n.logo {\n  margin: 15px 0 20px 0;\n}\n\n.attributes {\n  font-size: 1em;\n  margin-bottom: 30px;\n  color: var(--ifm-color-gray-600);\n}\n\n.buttons {\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  margin-top: 30px;\n}\n\n.buttons a {\n  margin: 5px;\n}\n\n.title {\n  font-size: 3em;\n  font-weight: bold;\n}\n\n.subtitle {\n  font-size: 1.2em;\n}\n\n.installContainer {\n  margin: auto;\n  max-width: 420px;\n}\n\n.install {\n  margin: 30px 0;\n\n  pre {\n    font-family: monospace;\n    font-size: 14px;\n    display: flex;\n    align-items: center;\n    flex-wrap: nowrap;\n    padding-top: 1.1rem;\n  }\n} \n\n.command {\n  color: yellow;\n}\n\n.command_start {\n  -webkit-user-select: none;\n  -ms-user-select: none;\n  user-select: none;\n  color: var(--ifm-color-gray-600);\n}\n\n.options {\n  color: var(--ifm-color-gray-600);\n}\n\n.cursor {\n  content: \"\";\n  display: inline-block;\n  background-color: var(--ifm-font-color-secondary);\n  width: 7px;\n  min-width: 7px;\n  height: 15px;\n  margin-left: 1px;\n  margin-bottom: 2px;\n  -webkit-animation: blink 1s step-end infinite;\n  animation: blink 1s step-end infinite;\n\n  @-webkit-keyframes blink {\n    0% { opacity: 1.0; }\n    50% { opacity: 0.0; }\n    100% { opacity: 1.0; }\n  }\n  \n  @keyframes blink {\n    0% { opacity: 1.0; }\n    50% { opacity: 0.0; }\n    100% { opacity: 1.0; }\n  }\n}\n\n[data-theme='light'] {\n  .command {\n    color: darkgoldenrod;\n  }\n}\n\n@media screen and (max-width: 996px) {\n  .heroBanner {\n    padding: 3rem;\n  }\n}\n\n@media screen and (max-width: 460px) {\n  .heroBanner {\n    padding: 3rem .5rem;\n  }\n}"
  },
  {
    "path": "docs/src/theme/CodeBlock/index.js",
    "content": "import CodeBlock from '@theme-original/CodeBlock';\nimport React from 'react';\n\nexport default function CodeBlockWrapper(props) {\n  return (\n    <>\n      <CodeBlock {...props} showLineNumbers />\n    </>\n  );\n}"
  },
  {
    "path": "docs/src/theme/Footer/index.js",
    "content": "import React from 'react';\nimport clsx from 'clsx';\nimport {useThemeConfig} from '@docusaurus/theme-common';\nimport LinkItem from '@theme/Footer/LinkItem';\nimport Link from '@docusaurus/Link';\nimport FooterCopyright from '@theme/Footer/Copyright';\nimport styles from './styles.module.scss';\nimport SvgIcon from '../../components/SvgIcon';\n\nconst footerLinks = [\n  {\n    link: \"https://github.com/z4kn4fein/stashbox\",\n    icon: \"github\",\n    text: \"GitHub\"\n  },\n  {\n    link: \"https://www.nuget.org/packages/Stashbox\",\n    icon: \"nuget\",\n    text: \"NuGet\"\n  },\n]\n\nfunction Footer() {\n  const {footer} = useThemeConfig();\n  if (!footer) {\n    return null;\n  }\n  const {copyright, links, style} = footer;\n  return (\n    <footer\n      className={clsx(styles.footer, {\n        'footer--dark': style === 'dark',\n      })}>\n      <div className=\"container container-fluid\">\n        <div className=\"row footer__links\">\n          <div className={clsx(styles.repo, \"col footer__col\")}>\n            <div className={clsx(styles.footer_title, \"footer__title\")}>REPOSITORY</div>\n            <Link\n              to=\"https://github.com/z4kn4fein/stashbox\">\n                <img src=\"https://github-readme-stats-pcsajtai.vercel.app/api/pin/?username=z4kn4fein&repo=stashbox&show_owner=true&title_color=43c8ff&text_color=e3e3e3&bg_color=2a313c&icon_color=f9f9f9\"></img>\n            </Link>\n          </div>\n\n          {links.map((link, i) => (\n            <div key={i} className=\"col footer__col\">\n              <div className={clsx(styles.footer_title, \"footer__title\")}>{link.title}</div>\n              <ul className=\"footer__items clean-list\">\n                {link.items.map((item, k) => (\n                  item.html ? (\n                    <li\n                      className=\"footer__item\"\n                      dangerouslySetInnerHTML={{__html: item.html}}\n                    />\n                  ) : (\n                    <li key={item.href ?? item.to} className=\"footer__item\">\n                      <LinkItem item={item} />\n                    </li>\n                  )\n                ))}\n              </ul>\n            </div>\n          ))}\n          <div className=\"col footer__col\">\n            <div className={clsx(styles.footer_title, \"footer__title\")}>LINKS</div>\n            <ul className=\"footer__items clean-list\">\n              {footerLinks.map((link, i) => (\n                <li key={i} className=\"footer__item\">\n                  <div className={styles.footer_link}>\n                    <SvgIcon icon={link.icon} className={styles.footer_icon} />\n                    <a href={link.link} target=\"_blank\" className=\"footer__link-item\" rel=\"noreferrer noopener\" aria-label={link.text}>\n                      {link.text} <svg width=\"12\" height=\"12\" aria-hidden=\"true\" viewBox=\"0 0 24 24\" className={styles.remote_link_icon}><path fill=\"currentColor\" d=\"M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z\"></path></svg>\n                    </a>\n                  </div>\n                </li>\n              ))}\n            </ul>\n          </div>\n        </div>\n      </div>\n      <hr className={styles.separator}></hr>\n      <div className=\"container container-fluid\">\n        {(copyright) && (\n          <div className={clsx(styles.footer_copyright, \"footer__bottom\")}>\n            <FooterCopyright copyright={copyright} />\n          </div>\n        )}\n      </div>\n    </footer>\n  );\n}\nexport default React.memo(Footer);\n"
  },
  {
    "path": "docs/src/theme/Footer/styles.module.scss",
    "content": ".footer {\n    background-color: var(--ifm-footer-background-color);\n    padding: var(--ifm-footer-padding-vertical) 0;\n    font-size: 14px;\n}\n\n.footer_title {\n  color: #858a96;\n  font-weight: 500;\n  font-size: 14px;\n}\n\n.footer_icon {\n    margin-right: 7px;\n    width: 14px;\n    height: 14px;\n    color: var(--ifm-footer-color);\n}\n\n.footer_copyright {\n    font-size: 13px;\n    color: var(--ifm-color-gray-600);\n}\n\n.footer_link {\n    display: flex;\n    flex-direction: row;\n    flex-wrap: nowrap;\n    align-items: center;\n}\n\n.separator {\n    opacity: .2;\n}\n\n.repo {\n    min-width: 500px;\n}\n\n.remote_link_icon {\n    opacity: .5;\n    width: 10;\n    height: 10px;\n}\n\n@media screen and (max-width: 996px) {\n    .repo {\n        min-width: 300px;\n    }\n}"
  },
  {
    "path": "docs/src/theme/NavbarItem/ComponentTypes.js",
    "content": "import ComponentTypes from '@theme-original/NavbarItem/ComponentTypes';\nimport SvgNavbarItem from '@site/src/components/NavbarItems/SvgNavbarItem';\nimport SeparatorNavbarItem from '@site/src/components/NavbarItems/SeparatorNavbarItem';\n\nexport default {\n    ...ComponentTypes,\n    'custom-icon': SvgNavbarItem,\n    'custom-separator': SeparatorNavbarItem,\n};"
  },
  {
    "path": "docs/src/utils/prismDark.mjs",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\nimport {themes} from 'prism-react-renderer';\nconst darkTheme = themes.vsDark;\n\nexport default {\n  plain: {\n    color: '#D4D4D4',\n    backgroundColor: '#272727',\n  },\n  styles: [\n    ...darkTheme.styles,\n  ],\n};"
  },
  {
    "path": "docs/static/.nojekyll",
    "content": ""
  },
  {
    "path": "sandbox/stashbox.assemblyload/Program.cs",
    "content": "﻿using Stashbox;\nusing System.Reflection;\nusing System.Runtime.CompilerServices;\nusing System.Runtime.Loader;\n\nIStashboxContainer container = new StashboxContainer();\n\nLoadAndUnload(container, out var weakContext);\n\nfor (var i = 0; weakContext.TryGetTarget(out _) && i < 10; i++)\n{\n    GC.Collect();\n    GC.WaitForPendingFinalizers();\n}\n\nConsole.WriteLine(weakContext.TryGetTarget(out _));\n\n[MethodImpl(MethodImplOptions.NoInlining)]\nstatic void LoadAndUnload(IStashboxContainer container, out WeakReference<AssemblyLoadContext> weakContext)\n{\n    var context = new AssemblyLoadContext(name: \"context\", isCollectible: true);\n    weakContext = new WeakReference<AssemblyLoadContext>(context, trackResurrection: true);\n    var assembly =\n        context.LoadFromAssemblyPath(Path.Combine(Path.GetDirectoryName(container.GetType().Assembly.Location),\n            \"TestAssembly.dll\"));\n\n    container.RegisterAssembly(assembly);\n\n    var instances = assembly.GetExportedTypes().Where(t => !t.IsGenericType).Select(exportedType => container.Resolve(exportedType)).ToList();\n\n    Console.WriteLine(instances.Count);\n    Console.WriteLine(container.GetRegistrationDiagnostics().Count());\n\n    context.Unload();\n}"
  },
  {
    "path": "sandbox/stashbox.assemblyload/stashbox.assemblyload.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n    <PropertyGroup>\n        <OutputType>Exe</OutputType>\n        <TargetFramework>net6.0</TargetFramework>\n        <ImplicitUsings>enable</ImplicitUsings>\n        <Nullable>enable</Nullable>\n        <AssemblyName>Stashbox.AssemblyLoad</AssemblyName>\n        <RootNamespace>Stashbox.AssemblyLoad</RootNamespace>\n    </PropertyGroup>\n\n    <ItemGroup>\n        <ProjectReference Include=\"..\\..\\src\\stashbox.csproj\" />\n    </ItemGroup>\n\n    <ItemGroup>\n      <None Update=\"TestAssembly.dll\">\n        <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>\n      </None>\n    </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "sandbox/stashbox.benchmarks/BeginScopeBenchmarks.cs",
    "content": "﻿extern alias from_nuget;\nextern alias from_project;\nusing BenchmarkDotNet.Attributes;\n\nnamespace Stashbox.Benchmarks\n{\n    [MemoryDiagnoser]\n    public class BeginScopeBenchmarks\n    {\n        private readonly from_nuget::Stashbox.IStashboxContainer oldContainer =\n           new from_nuget::Stashbox.StashboxContainer();\n\n        private readonly from_project::Stashbox.IStashboxContainer newContainer =\n            new from_project::Stashbox.StashboxContainer();\n\n        [Benchmark(Baseline = true)]\n        public object Old()\n        {\n            return this.oldContainer.BeginScope();\n        }\n\n        [Benchmark]\n        public object New()\n        {\n            return this.newContainer.BeginScope();\n        }\n    }\n}\n"
  },
  {
    "path": "sandbox/stashbox.benchmarks/ChildContainerBenchmarks.cs",
    "content": "﻿extern alias from_nuget;\nextern alias from_project;\nusing BenchmarkDotNet.Attributes;\n\nnamespace Stashbox.Benchmarks\n{\n    [MemoryDiagnoser]\n    public class ChildContainerBenchmarks\n    {\n        private readonly from_nuget::Stashbox.IStashboxContainer oldContainer =\n            new from_nuget::Stashbox.StashboxContainer();\n\n        private readonly from_project::Stashbox.IStashboxContainer newContainer =\n            new from_project::Stashbox.StashboxContainer();\n\n        [GlobalSetup]\n        public void Setup()\n        {\n            this.oldContainer.Register<A>()\n                .Register<B>()\n                .Register<C>();\n\n            this.newContainer.Register<A>()\n                .Register<B>()\n                .Register<C>();\n        }\n\n        [Benchmark(Baseline = true)]\n        public object Old()\n        {\n            var child = this.oldContainer.CreateChildContainer();\n            child.Register<B>();\n            return this.oldContainer.Resolve(typeof(A));\n        }\n\n        [Benchmark]\n        public object New()\n        {\n            var child = this.newContainer.CreateChildContainer();\n            child.Register<B>();\n            return this.newContainer.Resolve(typeof(A));\n        }\n\n        class A\n        {\n            public A(B b, C c)\n            { }\n        }\n\n        class B\n        {\n            public B(C c)\n            { }\n        }\n\n        class C { }\n    }\n}\n"
  },
  {
    "path": "sandbox/stashbox.benchmarks/DecoratorBenchmarks.cs",
    "content": "﻿extern alias from_nuget;\nextern alias from_project;\nusing BenchmarkDotNet.Attributes;\n\nnamespace Stashbox.Benchmarks\n{\n    [MemoryDiagnoser]\n    public class DecoratorBenchmarks\n    {\n        private readonly from_nuget::Stashbox.IStashboxContainer oldContainer =\n            new from_nuget::Stashbox.StashboxContainer();\n\n        private readonly from_project::Stashbox.IStashboxContainer newContainer =\n            new from_project::Stashbox.StashboxContainer();\n\n        [GlobalSetup]\n        public void Setup()\n        {\n            this.oldContainer.Register<IA, A>()\n                .RegisterDecorator<IA, ADec>();\n\n            this.newContainer.Register<IA, A>()\n                .RegisterDecorator<IA, ADec>();\n        }\n\n        [Benchmark(Baseline = true)]\n        public object Old()\n        {\n            return this.oldContainer.Resolve(typeof(IA));\n        }\n\n        [Benchmark]\n        public object New()\n        {\n            return this.newContainer.Resolve(typeof(IA));\n        }\n\n        interface IA { }\n\n        class A : IA { }\n\n        class ADec : IA\n        {\n            public ADec(IA a) { }\n        }\n    }\n}\n"
  },
  {
    "path": "sandbox/stashbox.benchmarks/DisposeBenchmarks.cs",
    "content": "﻿extern alias from_nuget;\nextern alias from_project;\nusing BenchmarkDotNet.Attributes;\nusing System;\n\nnamespace Stashbox.Benchmarks\n{\n    [MemoryDiagnoser]\n    public class DisposeBenchmarks\n    {\n        private readonly from_nuget::Stashbox.IStashboxContainer oldContainer =\n            new from_nuget::Stashbox.StashboxContainer(c => c.WithDisposableTransientTracking()\n            .WithDefaultLifetime(from_nuget::Stashbox.Lifetime.Lifetimes.Scoped));\n\n        private readonly from_project::Stashbox.IStashboxContainer newContainer =\n            new from_project::Stashbox.StashboxContainer(c => c.WithDisposableTransientTracking()\n            .WithDefaultLifetime(from_project::Stashbox.Lifetime.Lifetimes.Scoped));\n\n        [GlobalSetup]\n        public void Setup()\n        {\n            this.oldContainer.Register<DisposableObj2>()\n                .Register<DisposableObj1>()\n                .Register<DisposableObj3>()\n                .Register<DisposableObj4>();\n\n            this.newContainer.Register<DisposableObj2>()\n                .Register<DisposableObj1>()\n                .Register<DisposableObj3>()\n                .Register<DisposableObj4>();\n        }\n\n        [Benchmark(Baseline = true)]\n        public object Old()\n        {\n            using var scope1 = this.oldContainer.BeginScope();\n            scope1.Resolve(typeof(DisposableObj2));\n\n            using var scope2 = this.oldContainer.BeginScope();\n            scope2.Resolve(typeof(DisposableObj2));\n\n            using var scope3 = this.oldContainer.BeginScope();\n            return scope3.Resolve(typeof(DisposableObj2));\n        }\n\n        [Benchmark]\n        public object New()\n        {\n            using var scope1 = this.newContainer.BeginScope();\n            scope1.Resolve(typeof(DisposableObj2));\n\n            using var scope2 = this.newContainer.BeginScope();\n            scope2.Resolve(typeof(DisposableObj2));\n\n            using var scope3 = this.newContainer.BeginScope();\n            return scope3.Resolve(typeof(DisposableObj2));\n        }\n\n        private class DisposableObj1 : IDisposable\n        {\n            public void Dispose()\n            { }\n        }\n\n        private class DisposableObj3 : IDisposable\n        {\n            private readonly DisposableObj4 obj4;\n            private readonly DisposableObj1 obj1;\n\n            public DisposableObj3(DisposableObj4 obj4, DisposableObj1 obj1)\n            {\n                this.obj4 = obj4;\n                this.obj1 = obj1;\n            }\n\n            public void Dispose()\n            { }\n        }\n\n        private class DisposableObj4 : IDisposable\n        {\n            private readonly DisposableObj1 obj1;\n\n            public DisposableObj4(DisposableObj1 obj1)\n            {\n                this.obj1 = obj1;\n            }\n\n            public void Dispose()\n            { }\n        }\n\n        private class DisposableObj2 : IDisposable\n        {\n            private readonly DisposableObj1 obj1;\n            private readonly DisposableObj3 obj3;\n\n            public DisposableObj2(DisposableObj1 obj1, DisposableObj3 obj3)\n            {\n                this.obj1 = obj1;\n                this.obj3 = obj3;\n            }\n\n            public void Dispose()\n            { }\n        }\n    }\n}\n"
  },
  {
    "path": "sandbox/stashbox.benchmarks/EnumerableBenchmarks.cs",
    "content": "﻿extern alias from_nuget;\nextern alias from_project;\nusing System.Collections.Generic;\nusing BenchmarkDotNet.Attributes;\n\nnamespace Stashbox.Benchmarks\n{\n    [MemoryDiagnoser]\n    public class EnumerableBenchmarks\n    {\n        private readonly from_nuget::Stashbox.IStashboxContainer oldContainer =\n            new from_nuget::Stashbox.StashboxContainer();\n\n        private readonly from_project::Stashbox.IStashboxContainer newContainer =\n            new from_project::Stashbox.StashboxContainer();\n\n        [GlobalSetup]\n        public void Setup()\n        {\n            this.oldContainer.Register<IA, A>()\n                .Register<IA, AA>()\n                .Register<IA, AAA>()\n                .Register<B>();\n\n            this.newContainer.Register<IA, A>()\n                .Register<IA, AA>()\n                .Register<IA, AAA>()\n                .Register<B>();\n        }\n\n        [Benchmark(Baseline = true)]\n        public object Old()\n        {\n            return this.oldContainer.Resolve(typeof(IEnumerable<IA>));\n        }\n\n        [Benchmark]\n        public object New()\n        {\n            return this.newContainer.Resolve(typeof(IEnumerable<IA>));\n        }\n\n        interface IA { }\n\n        class A : IA\n        {\n            public A(B b)\n            { }\n        }\n\n        class AA : IA\n        {\n            public AA(B b)\n            { }\n        }\n\n        class AAA : IA\n        {\n            public AAA(B b)\n            { }\n        }\n\n        class B { }\n    }\n}\n"
  },
  {
    "path": "sandbox/stashbox.benchmarks/FinalizerBenchmarks.cs",
    "content": "﻿extern alias from_nuget;\nextern alias from_project;\nusing BenchmarkDotNet.Attributes;\n\nnamespace Stashbox.Benchmarks\n{\n    [MemoryDiagnoser]\n    public class FinalizerBenchmarks\n    {\n        private readonly from_nuget::Stashbox.IStashboxContainer oldContainer =\n            new from_nuget::Stashbox.StashboxContainer();\n\n        private readonly from_project::Stashbox.IStashboxContainer newContainer =\n            new from_project::Stashbox.StashboxContainer();\n\n        [GlobalSetup]\n        public void Setup()\n        {\n            this.oldContainer.Register<A>(c => c.WithFinalizer(a => a.FinalizeA()).WithScopedLifetime());\n\n            this.newContainer.Register<A>(c => c.WithFinalizer(a => a.FinalizeA()).WithScopedLifetime());\n        }\n\n        [Benchmark(Baseline = true)]\n        public object Old()\n        {\n            using var scope = this.oldContainer.BeginScope();\n            scope.Resolve(typeof(A));\n            scope.Resolve(typeof(A));\n            scope.Resolve(typeof(A));\n            scope.Resolve(typeof(A));\n\n            using var scope2 = this.oldContainer.BeginScope();\n            scope2.Resolve(typeof(A));\n            scope2.Resolve(typeof(A));\n            scope2.Resolve(typeof(A));\n            return scope2.Resolve(typeof(A));\n        }\n\n        [Benchmark]\n        public object New()\n        {\n            using var scope = this.newContainer.BeginScope();\n            scope.Resolve(typeof(A));\n            scope.Resolve(typeof(A));\n            scope.Resolve(typeof(A));\n            scope.Resolve(typeof(A));\n\n            using var scope2 = this.newContainer.BeginScope();\n            scope2.Resolve(typeof(A));\n            scope2.Resolve(typeof(A));\n            scope2.Resolve(typeof(A));\n            return scope2.Resolve(typeof(A));\n        }\n\n        class A\n        {\n            private bool isFinalized;\n\n            public void FinalizeA()\n            {\n                this.isFinalized = true;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "sandbox/stashbox.benchmarks/FuncBenchmarks.cs",
    "content": "﻿extern alias from_nuget;\nextern alias from_project;\nusing BenchmarkDotNet.Attributes;\nusing System;\n\nnamespace Stashbox.Benchmarks\n{\n    [MemoryDiagnoser]\n    public class FuncBenchmarks\n    {\n        private readonly from_nuget::Stashbox.IStashboxContainer oldContainer =\n            new from_nuget::Stashbox.StashboxContainer();\n\n        private readonly from_project::Stashbox.IStashboxContainer newContainer =\n            new from_project::Stashbox.StashboxContainer();\n\n        [GlobalSetup]\n        public void Setup()\n        {\n            this.oldContainer.Register<A>()\n                .Register<B>();\n\n            this.newContainer.Register<A>()\n                .Register<B>();\n        }\n\n        [Benchmark(Baseline = true)]\n        public object Old()\n        {\n            var factory = (Func<B, A>)this.oldContainer.Resolve(typeof(Func<B, A>));\n            return factory((B)this.oldContainer.Resolve(typeof(B)));\n        }\n\n        [Benchmark]\n        public object New()\n        {\n            var factory = (Func<B, A>)this.newContainer.Resolve(typeof(Func<B, A>));\n            return factory((B)this.newContainer.Resolve(typeof(B)));\n        }\n\n        class A\n        {\n            public A(B b)\n            { }\n        }\n\n        class B { }\n    }\n}\n"
  },
  {
    "path": "sandbox/stashbox.benchmarks/NullableBenchmarks.cs",
    "content": "﻿extern alias from_nuget;\nextern alias from_project;\nusing BenchmarkDotNet.Attributes;\n\nnamespace Stashbox.Benchmarks\n{\n    [MemoryDiagnoser]\n    public class NullableBenchmarks\n    {\n        private readonly from_nuget::Stashbox.IStashboxContainer oldContainer =\n            new from_nuget::Stashbox.StashboxContainer();\n\n        private readonly from_project::Stashbox.IStashboxContainer newContainer =\n            new from_project::Stashbox.StashboxContainer();\n\n        [Benchmark(Baseline = true)]\n        public object Old()\n        {\n            return this.oldContainer.ResolveOrDefault(typeof(object));\n        }\n\n        [Benchmark]\n        public object New()\n        {\n            return this.newContainer.ResolveOrDefault(typeof(object));\n        }\n    }\n}\n"
  },
  {
    "path": "sandbox/stashbox.benchmarks/Program.cs",
    "content": "﻿using System;\nusing BenchmarkDotNet.Configs;\nusing BenchmarkDotNet.Running;\n\nnamespace Stashbox.Benchmarks\n{\n    class Program\n    {\n        static void Main()\n        {\n            var config = ManualConfig.Create(DefaultConfig.Instance)\n             .WithOptions(ConfigOptions.JoinSummary)\n             .WithOptions(ConfigOptions.DisableLogFile);\n\n            BenchmarkRunner.Run(\n                new[]\n                {\n                    // BenchmarkConverter.TypeToBenchmarks( typeof(DisposeBenchmarks), config),\n                    // BenchmarkConverter.TypeToBenchmarks( typeof(EnumerableBenchmarks), config),\n                    // BenchmarkConverter.TypeToBenchmarks( typeof(PropertyBenchmarks), config),\n                    // BenchmarkConverter.TypeToBenchmarks( typeof(RegisterBenchmarks), config),\n                    // BenchmarkConverter.TypeToBenchmarks( typeof(ResolveBenchmarks), config),\n                    // BenchmarkConverter.TypeToBenchmarks( typeof(ScopedBenchmarks), config),\n                    // BenchmarkConverter.TypeToBenchmarks( typeof(FuncBenchmarks), config),\n                    // BenchmarkConverter.TypeToBenchmarks( typeof(FinalizerBenchmarks), config),\n                    // BenchmarkConverter.TypeToBenchmarks( typeof(NullableBenchmarks), config),\n                    // BenchmarkConverter.TypeToBenchmarks( typeof(BeginScopeBenchmarks), config),\n                    BenchmarkConverter.TypeToBenchmarks( typeof(TreeBenchmarks), config),\n                    // BenchmarkConverter.TypeToBenchmarks( typeof(SingletonBenchmarks), config),\n                    // BenchmarkConverter.TypeToBenchmarks( typeof(DecoratorBenchmarks), config),\n                    // BenchmarkConverter.TypeToBenchmarks( typeof(ChildContainerBenchmarks), config),\n                });\n\n            Console.ReadKey();\n        }\n    }\n}\n"
  },
  {
    "path": "sandbox/stashbox.benchmarks/PropertyBenchmarks.cs",
    "content": "﻿extern alias from_nuget;\nextern alias from_project;\nusing BenchmarkDotNet.Attributes;\n\nnamespace Stashbox.Benchmarks\n{\n    [MemoryDiagnoser]\n    public class PropertyBenchmarks\n    {\n        private readonly from_nuget::Stashbox.IStashboxContainer oldContainer =\n            new from_nuget::Stashbox.StashboxContainer();\n\n        private readonly from_project::Stashbox.IStashboxContainer newContainer =\n            new from_project::Stashbox.StashboxContainer();\n\n        [GlobalSetup]\n        public void Setup()\n        {\n            this.oldContainer.Register<A>(c => c.WithAutoMemberInjection())\n                .Register<B>();\n\n            this.newContainer.Register<A>(c => c.WithAutoMemberInjection())\n                .Register<B>();\n        }\n\n        [Benchmark(Baseline = true)]\n        public object Old()\n        {\n            return this.oldContainer.Resolve(typeof(A));\n        }\n\n        [Benchmark]\n        public object New()\n        {\n            return this.newContainer.Resolve(typeof(A));\n        }\n\n        class A\n        {\n            public B B { get; set; }\n        }\n\n        class B { }\n    }\n}\n"
  },
  {
    "path": "sandbox/stashbox.benchmarks/RegisterBenchmarks.cs",
    "content": "﻿extern alias from_nuget;\nextern alias from_project;\nusing BenchmarkDotNet.Attributes;\n\nnamespace Stashbox.Benchmarks\n{\n    [MemoryDiagnoser]\n    public class RegisterBenchmarks\n    {\n        private readonly from_nuget::Stashbox.IStashboxContainer oldContainer =\n            new from_nuget::Stashbox.StashboxContainer();\n\n        private readonly from_project::Stashbox.IStashboxContainer newContainer =\n            new from_project::Stashbox.StashboxContainer();\n\n        [Benchmark(Baseline = true)]\n        public object Old()\n        {\n            return this.oldContainer.Register<A>().Register<B>();\n        }\n\n        [Benchmark]\n        public object New()\n        {\n            return this.newContainer.Register<A>().Register<B>();\n        }\n\n        class A { }\n\n        class B { }\n    }\n}\n"
  },
  {
    "path": "sandbox/stashbox.benchmarks/ResolveBenchmarks.cs",
    "content": "﻿extern alias from_nuget;\nextern alias from_project;\nusing BenchmarkDotNet.Attributes;\n\nnamespace Stashbox.Benchmarks\n{\n    [MemoryDiagnoser]\n    public class ResolveBenchmarks\n    {\n        private readonly from_nuget::Stashbox.IStashboxContainer oldContainer =\n            new from_nuget::Stashbox.StashboxContainer();\n\n        private readonly from_project::Stashbox.IStashboxContainer newContainer =\n            new from_project::Stashbox.StashboxContainer();\n\n        [GlobalSetup]\n        public void Setup()\n        {\n            this.oldContainer.Register<A>()\n                .Register<B>()\n                .Register<C>();\n\n            this.newContainer.Register<A>()\n                .Register<B>()\n                .Register<C>();\n        }\n\n        [Benchmark(Baseline = true)]\n        public object Old()\n        {\n            return this.oldContainer.Resolve(typeof(A));\n        }\n\n        [Benchmark]\n        public object New()\n        {\n            return this.newContainer.Resolve(typeof(A));\n        }\n\n        class A\n        {\n            public A(B b, C c)\n            { }\n        }\n\n        class B\n        {\n            public B(C c)\n            { }\n        }\n\n        class C { }\n    }\n}\n"
  },
  {
    "path": "sandbox/stashbox.benchmarks/ScopedBenchmarks.cs",
    "content": "﻿extern alias from_nuget;\nextern alias from_project;\nusing BenchmarkDotNet.Attributes;\n\nnamespace Stashbox.Benchmarks\n{\n    [MemoryDiagnoser]\n    public class ScopedBenchmarks\n    {\n        private readonly from_nuget::Stashbox.IStashboxContainer oldContainer =\n            new from_nuget::Stashbox.StashboxContainer(c => c\n            .WithDefaultLifetime(from_nuget::Stashbox.Lifetime.Lifetimes.Scoped));\n\n        private readonly from_project::Stashbox.IStashboxContainer newContainer =\n            new from_project::Stashbox.StashboxContainer(c => c\n            .WithDefaultLifetime(from_project::Stashbox.Lifetime.Lifetimes.Scoped));\n\n        [GlobalSetup]\n        public void Setup()\n        {\n            this.oldContainer.Register<A>()\n                .Register<B>();\n\n            this.newContainer.Register<A>()\n                .Register<B>();\n        }\n\n        [Benchmark(Baseline = true)]\n        public object Old()\n        {\n            using var scope = this.oldContainer.BeginScope();\n            return scope.Resolve(typeof(A));\n        }\n\n        [Benchmark]\n        public object New()\n        {\n            using var scope = this.newContainer.BeginScope();\n            return scope.Resolve(typeof(A));\n        }\n\n        class A\n        {\n            public A(B b)\n            { }\n        }\n\n        class B { }\n    }\n}\n"
  },
  {
    "path": "sandbox/stashbox.benchmarks/SingletonBenchmarks.cs",
    "content": "﻿extern alias from_nuget;\nextern alias from_project;\nusing BenchmarkDotNet.Attributes;\n\nnamespace Stashbox.Benchmarks\n{\n    [MemoryDiagnoser]\n    public class SingletonBenchmarks\n    {\n        private readonly from_nuget::Stashbox.IStashboxContainer oldContainer =\n            new from_nuget::Stashbox.StashboxContainer();\n\n        private readonly from_project::Stashbox.IStashboxContainer newContainer =\n            new from_project::Stashbox.StashboxContainer();\n\n        [GlobalSetup]\n        public void Setup()\n        {\n            this.oldContainer.Register<A>()\n                .Register<B>()\n                .Register<C>(c => c.WithSingletonLifetime());\n\n            this.newContainer.Register<A>()\n                .Register<B>()\n                .Register<C>(c => c.WithSingletonLifetime());\n        }\n\n        [Benchmark(Baseline = true)]\n        public object Old()\n        {\n            return this.oldContainer.Resolve(typeof(A));\n        }\n\n        [Benchmark]\n        public object New()\n        {\n            return this.newContainer.Resolve(typeof(A));\n        }\n\n        class A\n        {\n            public A(B b, C c)\n            { }\n        }\n\n        class B\n        {\n            public B(C c)\n            { }\n        }\n\n        class C { }\n    }\n}\n"
  },
  {
    "path": "sandbox/stashbox.benchmarks/Stashbox.Benchmarks.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net8.0</TargetFramework>\n    <RootNamespace>Stashbox.Benchmarks</RootNamespace>\n    <AssemblyName>Stashbox.Benchmarks</AssemblyName>\n    <Configurations>Debug;Release;Benchmark</Configurations>\n    <LangVersion>latest</LangVersion>\n    <SignAssembly>true</SignAssembly>\n    <AssemblyOriginatorKeyFile>../../sn.snk</AssemblyOriginatorKeyFile>\n  </PropertyGroup>\n\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Benchmark|AnyCPU'\">\n    <Optimize>true</Optimize>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"BenchmarkDotNet\" Version=\"0.13.5\" />\n    <PackageReference Include=\"Stashbox\" Version=\"5.14.1\" />\n  </ItemGroup>\n\n  <ItemGroup Condition=\"'$(TargetFramework)' == 'net8.0'\">\n    <Reference Include=\"Stashbox.Benchmark\">\n      <HintPath>..\\..\\src\\bin\\Benchmark\\net8.0\\Stashbox.Benchmark.dll</HintPath>\n      <Aliases>from_project</Aliases>\n      <Private>true</Private>\n    </Reference>\n  </ItemGroup>\n\n  <Target Name=\"ChangeAliasOfNugetReferencedStashbox\" BeforeTargets=\"FindReferenceAssembliesForReferences;ResolveReferences\">\n    <ItemGroup>\n      <ReferencePath Condition=\"'%(FileName)' == 'Stashbox'\">\n        <Aliases>from_nuget</Aliases>\n      </ReferencePath>\n    </ItemGroup>\n  </Target>\n\n</Project>\n"
  },
  {
    "path": "sandbox/stashbox.benchmarks/TreeBenchmarks.cs",
    "content": "﻿extern alias from_project;\nusing System;\nusing System.Collections.Generic;\nusing System.Collections.Immutable;\nusing System.Linq;\nusing BenchmarkDotNet.Attributes;\nusing from_project::Stashbox.Utils.Data.Immutable;\n\nnamespace Stashbox.Benchmarks;\n\n[MemoryDiagnoser]\npublic class TreeBenchmarks\n{\n    private Type[] keys;\n        \n    private ImmutableDictionary<Type, string> imDict;\n\n    private ImmutableTree<Type, string> imTree;\n\n    [Params(10, 100, 1000)]\n    public int Count;\n    \n    [GlobalSetup]\n    public void Setup()\n    {\n        imDict = ImmutableDictionary<Type, string>.Empty;\n        imTree = ImmutableTree<Type, string>.Empty;\n        keys = typeof(Dictionary<,>).Assembly.GetTypes().Take(Count).ToArray();\n\n        foreach (var key in keys)\n        {\n            imDict = imDict.Add(key, \"value\");\n            imTree = imTree.AddOrUpdate(key, \"value\", true);\n        }\n    }\n\n    [Benchmark]\n    public object ImmutableDictionary_Add()\n    {\n        var imDictToAdd = ImmutableDictionary<Type, string>.Empty;\n        \n        foreach (var key in keys)\n        {\n            imDictToAdd = imDictToAdd.Add(key, \"value\");\n        }\n        return imDictToAdd;\n    }\n\n    [Benchmark]\n    public object ImmutableTree_AddOrUpdate()\n    {\n        var imTreeToAdd = ImmutableTree<Type, string>.Empty;\n        \n        foreach (var key in keys)\n        {\n            imTreeToAdd = imTreeToAdd.AddOrUpdate(key, \"value\", true);\n        }\n\n        return imTreeToAdd;\n    }\n    \n    [Benchmark]\n    public void ImmutableDictionary_TryGetValue()\n    {\n        foreach (var key in keys)\n        {\n            imDict.TryGetValue(key, out _);\n        }\n    }\n\n    [Benchmark]\n    public void ImmutableTree_GetOrDefault()\n    {\n        foreach (var key in keys)\n        {\n            imTree.GetOrDefaultByRef(key);\n        }\n    }\n}"
  },
  {
    "path": "sandbox/stashbox.sandbox.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 17\nVisualStudioVersion = 17.1.32421.90\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"stashbox.benchmarks\", \"stashbox.benchmarks\\stashbox.benchmarks.csproj\", \"{AF205E54-7B55-436A-81DB-5B010B7E9CD6}\"\n\tProjectSection(ProjectDependencies) = postProject\n\t\t{FB1985B6-E9A5-4662-89D7-87BEF62D94FB} = {FB1985B6-E9A5-4662-89D7-87BEF62D94FB}\n\tEndProjectSection\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"stashbox\", \"..\\src\\stashbox.csproj\", \"{FB1985B6-E9A5-4662-89D7-87BEF62D94FB}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"stashbox.trimmed\", \"stashbox.trimmed\\stashbox.trimmed.csproj\", \"{DFC8FD7D-E4DF-49D8-ACA3-517144EC1D34}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"stashbox.assemblyload\", \"stashbox.assemblyload\\stashbox.assemblyload.csproj\", \"{A76BE134-DE84-4CC1-87E3-B91577710249}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tBenchmark|Any CPU = Benchmark|Any CPU\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{AF205E54-7B55-436A-81DB-5B010B7E9CD6}.Benchmark|Any CPU.ActiveCfg = Benchmark|Any CPU\n\t\t{AF205E54-7B55-436A-81DB-5B010B7E9CD6}.Benchmark|Any CPU.Build.0 = Benchmark|Any CPU\n\t\t{AF205E54-7B55-436A-81DB-5B010B7E9CD6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{AF205E54-7B55-436A-81DB-5B010B7E9CD6}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{AF205E54-7B55-436A-81DB-5B010B7E9CD6}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{AF205E54-7B55-436A-81DB-5B010B7E9CD6}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{FB1985B6-E9A5-4662-89D7-87BEF62D94FB}.Benchmark|Any CPU.ActiveCfg = Benchmark|Any CPU\n\t\t{FB1985B6-E9A5-4662-89D7-87BEF62D94FB}.Benchmark|Any CPU.Build.0 = Benchmark|Any CPU\n\t\t{FB1985B6-E9A5-4662-89D7-87BEF62D94FB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{FB1985B6-E9A5-4662-89D7-87BEF62D94FB}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{FB1985B6-E9A5-4662-89D7-87BEF62D94FB}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{FB1985B6-E9A5-4662-89D7-87BEF62D94FB}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{DFC8FD7D-E4DF-49D8-ACA3-517144EC1D34}.Benchmark|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{DFC8FD7D-E4DF-49D8-ACA3-517144EC1D34}.Benchmark|Any CPU.Build.0 = Debug|Any CPU\n\t\t{DFC8FD7D-E4DF-49D8-ACA3-517144EC1D34}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{DFC8FD7D-E4DF-49D8-ACA3-517144EC1D34}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{DFC8FD7D-E4DF-49D8-ACA3-517144EC1D34}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{DFC8FD7D-E4DF-49D8-ACA3-517144EC1D34}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{A76BE134-DE84-4CC1-87E3-B91577710249}.Benchmark|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{A76BE134-DE84-4CC1-87E3-B91577710249}.Benchmark|Any CPU.Build.0 = Debug|Any CPU\n\t\t{A76BE134-DE84-4CC1-87E3-B91577710249}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{A76BE134-DE84-4CC1-87E3-B91577710249}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{A76BE134-DE84-4CC1-87E3-B91577710249}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{A76BE134-DE84-4CC1-87E3-B91577710249}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {8C4CB567-7FB6-49BA-9AE4-4FE30BF21021}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "sandbox/stashbox.trimmed/Program.cs",
    "content": "﻿using Stashbox;\nusing System.Reflection;\nusing System.Runtime.CompilerServices;\n\ntry\n{\n    new A(new B());\n    Console.WriteLine(Runner.Run());\n}\ncatch (TypeLoadException ex)\n{\n    Console.WriteLine(ex.TypeName);\n    Console.WriteLine(ex.Message);\n}\n\nclass A\n{\n    public A(B b)\n    {\n\n    }\n}\n\nclass B\n{\n    public B()\n    {\n\n    }\n}\n\nclass Runner\n{\n    [MethodImpl((short)MethodImplAttributes.NoInlining)]\n    public static object? Run()\n    {\n        IStashboxContainer container = new StashboxContainer();\n        container.RegisterScoped<A>()\n            .RegisterScoped<A>(\"A\")\n            .Register<B>(\"B\")\n            .Register<B>()\n            .RegisterSingleton<B>()\n            .RegisterSingleton<B>(\"BB\")\n            .Register(typeof(A))\n            .Register(typeof(A), c => { })\n            .Register<A>(typeof(A))\n            .Register<A>(typeof(A), c => { })\n            .Register<A, A>()\n            .Register<A, A>(c => { })\n            .Register<A>(c => { })\n            .RegisterDecorator<A>()\n            .RegisterDecorator<A>(c => { });\n        \n        container.Resolve<A>();\n        container.Resolve<A>(\"A\");\n        container.Resolve(typeof(A));\n        container.Resolve(typeof(A), \"A\");\n        container.ResolveOrDefault<A>();\n        container.ResolveOrDefault<A>(\"A\");\n        container.ResolveOrDefault(typeof(A));\n        container.ResolveOrDefault(typeof(A), \"A\");\n        container.ResolveAll<A>();\n        container.ResolveAll<A>(\"A\");\n        container.ResolveAll(typeof(A));\n        container.ResolveAll(typeof(A), \"A\");\n\n        IDependencyResolver scope = container.BeginScope();\n        scope.Resolve<A>();\n        scope.Resolve<A>(\"A\");\n        scope.Resolve(typeof(A));\n        scope.Resolve(typeof(A), \"A\");\n        scope.ResolveOrDefault<A>();\n        scope.ResolveOrDefault<A>(\"A\");\n        scope.ResolveOrDefault(typeof(A));\n        scope.ResolveOrDefault(typeof(A), \"A\");\n        scope.ResolveAll<A>();\n        scope.ResolveAll<A>(\"A\");\n        scope.ResolveAll(typeof(A));\n        scope.ResolveAll(typeof(A), \"A\");\n\n        return scope.Resolve<A>();\n    }\n}\n"
  },
  {
    "path": "sandbox/stashbox.trimmed/stashbox.trimmed.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <OutputType>Exe</OutputType>\n    <TargetFramework>net6.0</TargetFramework>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <Nullable>enable</Nullable>\n    <PublishTrimmed>true</PublishTrimmed>\n    <TrimmerDefaultAction>link</TrimmerDefaultAction>\n    <PublishSingleFile>true</PublishSingleFile>\n    <AssemblyName>Stashbox.Trimmed</AssemblyName>\n    <RootNamespace>Stashbox.Trimmed</RootNamespace>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\src\\stashbox.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "src/Attributes/DependencyAttribute.cs",
    "content": "﻿using System;\n\nnamespace Stashbox.Attributes;\n\n/// <summary>\n/// Represents an attribute for tracking dependencies.\n/// </summary>\n[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.Field)]\npublic class DependencyAttribute : Attribute\n{\n    /// <summary>\n    /// The name of the dependency.\n    /// </summary>\n    public object? Name { get; set; }\n\n    /// <summary>\n    /// Constructs a <see cref=\"DependencyAttribute\"/>\n    /// </summary>\n    /// <param name=\"name\">The name of the dependency.</param>\n    public DependencyAttribute(object? name = null)\n    {\n        this.Name = name;\n    }\n}"
  },
  {
    "path": "src/Attributes/DependencyNameAttribute.cs",
    "content": "﻿using System;\n\nnamespace Stashbox.Attributes;\n\n/// <summary>\n/// When a parameter is marked with this attribute, the container will pass the given dependency's name to it.\n/// </summary>\n[AttributeUsage(AttributeTargets.Parameter)]\npublic class DependencyNameAttribute : Attribute;"
  },
  {
    "path": "src/Attributes/InjectionMethodAttribute.cs",
    "content": "﻿using System;\n\nnamespace Stashbox.Attributes;\n\n/// <summary>\n/// Represents an attribute for tracking injection methods.\n/// </summary>\n[AttributeUsage(AttributeTargets.Method)]\npublic sealed class InjectionMethodAttribute : Attribute;"
  },
  {
    "path": "src/Configuration/ContainerConfiguration.cs",
    "content": "﻿using Stashbox.Attributes;\nusing Stashbox.Lifetime;\nusing Stashbox.Registration.Fluent;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq.Expressions;\nusing System.Reflection;\nusing Stashbox.Exceptions;\nusing Stashbox.Utils;\nusing Stashbox.Utils.Data;\n\nnamespace Stashbox.Configuration;\n\n/// <summary>\n/// Represents a container configuration\n/// </summary>\npublic class ContainerConfiguration\n{\n    /// <summary>\n    /// If it's set to true the container will track transient objects for disposal.\n    /// </summary>\n    public bool TrackTransientsForDisposalEnabled { get; internal set; }\n\n    /// <summary>\n    /// The actual behavior used when a new service is going to be registered into the container. See the <see cref=\"Rules.RegistrationBehavior\"/> enum for available options.\n    /// </summary>\n    public Rules.RegistrationBehavior RegistrationBehavior { get; internal set; }\n\n    /// <summary>\n    /// If it's set to true, the container will inject optional and default values for missing dependencies and primitive types.\n    /// </summary>\n    public bool DefaultValueInjectionEnabled { get; internal set; }\n\n    /// <summary>\n    /// If it's set to true the container will try to register the unknown type during the activation.\n    /// </summary>\n    public bool UnknownTypeResolutionEnabled { get; internal set; }\n\n    /// <summary>\n    /// If it's set to true, the container will inject members even without <see cref=\"DependencyAttribute\"/>.\n    /// </summary>\n    public bool AutoMemberInjectionEnabled { get; internal set; }\n\n    /// <summary>\n    /// If it's set to true, the container will inject required fields and properties.\n    /// </summary>\n    public bool RequiredMemberInjectionEnabled { get; internal set; } = true;\n\n    /// <summary>\n    /// If it's set to true, the container will treat the name of a constructor/method parameter or member name as a dependency name used by named resolution.\n    /// </summary>\n    public bool TreatingParameterAndMemberNameAsDependencyNameEnabled { get; internal set; }\n\n    /// <summary>\n    /// If it's set to true, the container will use an unnamed registration when a named one not found for a request with a dependency name.\n    /// </summary>\n    public bool NamedDependencyResolutionForUnNamedRequestsEnabled { get; internal set; }\n\n    /// <summary>\n    /// If it's set to true, the container will use an unnamed registration when a named one not found for a request with a dependency name.\n    /// </summary>\n    public bool NamedDependencyResolutionForUnNamedCollectionRequestsEnabled { get; internal set; } = true;\n    \n    /// <summary>\n    /// If it's set to true, the container won't select services with <see cref=\"ContainerConfiguration.UniversalName\"/> for a universal name resolution request.\n    /// </summary>\n    public bool IgnoreServicesWithUniversalNameForUniversalNamedRequests { get; internal set; }\n\n    /// <summary>\n    /// If it's set to true, the container will throw a <see cref=\"ResolutionFailedException\"/> when a named dependency is not resolvable even for requests initiated by <see cref=\"IDependencyResolver.ResolveOrDefault(Type)\" />.\n    /// </summary>\n    public bool ForceThrowWhenNamedDependencyIsNotResolvable { get; internal set; }\n    \n    /// <summary>\n    /// If it's set to true, in a child-parent container case singletons will be rebuilt with the dependencies overridden in the child, not affecting the already built instance in the parent.\n    /// </summary>\n    public bool ReBuildSingletonsInChildContainerEnabled { get; internal set; }\n\n    /// <summary>\n    /// The member injection rule.\n    /// </summary>\n    public Rules.AutoMemberInjectionRules AutoMemberInjectionRule { get; internal set; }\n\n    /// <summary>\n    /// The constructor selection rule.\n    /// </summary>\n    public Func<IEnumerable<ConstructorInfo>, IEnumerable<ConstructorInfo>> ConstructorSelectionRule { get; internal set; } = Rules.ConstructorSelection.PreferMostParameters;\n\n    /// <summary>\n    /// Represents the configuration which will be invoked when an unknown type being registered.\n    /// </summary>\n    public Action<UnknownRegistrationConfigurator>? UnknownTypeConfigurator { get; internal set; }\n\n    /// <summary>\n    /// The action which will be invoked when the container configuration changes.\n    /// </summary>\n    public Action<ContainerConfiguration>? ConfigurationChangedEvent { get; internal set; }\n\n    /// <summary>\n    /// A filter delegate used to determine which members should be auto-injected and which are not.\n    /// </summary>\n    public Func<MemberInfo, bool>? AutoMemberInjectionFilter { get; internal set; }\n\n    /// <summary>\n    /// The default lifetime, used when a service isn't configured with a lifetime.\n    /// </summary>\n    public LifetimeDescriptor DefaultLifetime { get; internal set; } = Lifetimes.Transient;\n\n    /// <summary>\n    /// When it's true, the container validates the lifetime configuration of the resolution\n    /// graph via the <see cref=\"LifetimeDescriptor.LifeSpan\"/> value,\n    /// and checks that scoped services are not resolved from the root scope.\n    /// </summary>\n    public bool LifetimeValidationEnabled { get; internal set; }\n\n    /// <summary>\n    /// When it's true, the container checks for generic covariance and contravariance during the resolution of generic type collections.\n    /// </summary>\n    public bool VariantGenericTypesEnabled { get; internal set; } = true;\n    \n    /// <summary>\n    /// When it's true, the container throws a <see cref=\"ResolutionFailedException\"/> when no services are found for a collection resolution request.\n    /// </summary>\n    public bool ExceptionOverEmptyCollectionEnabled { get; internal set; }\n    \n    internal object? UniversalName { get; set; }\n\n    internal Type? ExternalResolutionFailedExceptionType { get; set; }\n    \n    internal ExpandableArray<Type>? AdditionalDependencyNameAttributeTypes { get; set; }\n    \n    internal ExpandableArray<Type>? AdditionalDependencyAttributeTypes { get; set; }\n\n    /// <summary>\n    /// A delegate to use external expression compilers.\n    /// </summary>\n    public Func<LambdaExpression, Delegate>? ExternalExpressionCompiler { get; internal set; }\n\n    internal ContainerConfiguration() { }\n\n    private ContainerConfiguration(bool trackTransientsForDisposalEnabled,\n        Rules.RegistrationBehavior registrationBehavior,\n        bool defaultValueInjectionEnabled,\n        bool unknownTypeResolutionEnabled,\n        bool autoMemberInjectionEnabled,\n        bool treatingParameterAndMemberNameAsDependencyNameEnabled,\n        bool namedDependencyResolutionForUnNamedRequestsEnabled,\n        bool namedDependencyResolutionForUnNamedCollectionRequestsEnabled,\n        bool reBuildSingletonsInChildContainerEnabled,\n        bool variantGenericTypesEnabled,\n        bool exceptionOverEmptyCollectionEnabled,\n        Rules.AutoMemberInjectionRules autoMemberInjectionRule,\n        Func<IEnumerable<ConstructorInfo>, IEnumerable<ConstructorInfo>> constructorSelectionRule,\n        Action<UnknownRegistrationConfigurator>? unknownTypeConfigurator,\n        Action<ContainerConfiguration>? configurationChangedEvent,\n        Func<MemberInfo, bool>? autoMemberInjectionFilter,\n        LifetimeDescriptor defaultLifetime,\n        bool lifetimeValidationEnabled,\n        Func<LambdaExpression, Delegate>? externalExpressionCompiler,\n        object? universalName,\n        Type? externalResolutionFailedExceptionType,\n        ExpandableArray<Type>? additionalDependencyNameAttributeTypes,\n        ExpandableArray<Type>? additionalDependencyAttributeTypes)\n    {\n        this.TrackTransientsForDisposalEnabled = trackTransientsForDisposalEnabled;\n        this.RegistrationBehavior = registrationBehavior;\n        this.DefaultValueInjectionEnabled = defaultValueInjectionEnabled;\n        this.UnknownTypeResolutionEnabled = unknownTypeResolutionEnabled;\n        this.AutoMemberInjectionEnabled = autoMemberInjectionEnabled;\n        this.TreatingParameterAndMemberNameAsDependencyNameEnabled = treatingParameterAndMemberNameAsDependencyNameEnabled;\n        this.NamedDependencyResolutionForUnNamedRequestsEnabled = namedDependencyResolutionForUnNamedRequestsEnabled;\n        this.NamedDependencyResolutionForUnNamedCollectionRequestsEnabled = namedDependencyResolutionForUnNamedCollectionRequestsEnabled;\n        this.ReBuildSingletonsInChildContainerEnabled = reBuildSingletonsInChildContainerEnabled;\n        this.VariantGenericTypesEnabled = variantGenericTypesEnabled;\n        this.ExceptionOverEmptyCollectionEnabled = exceptionOverEmptyCollectionEnabled;\n        this.AutoMemberInjectionRule = autoMemberInjectionRule;\n        this.ConstructorSelectionRule = constructorSelectionRule;\n        this.UnknownTypeConfigurator = unknownTypeConfigurator;\n        this.ConfigurationChangedEvent = configurationChangedEvent;\n        this.AutoMemberInjectionFilter = autoMemberInjectionFilter;\n        this.DefaultLifetime = defaultLifetime;\n        this.LifetimeValidationEnabled = lifetimeValidationEnabled;\n        this.ExternalExpressionCompiler = externalExpressionCompiler;\n        this.UniversalName = universalName;\n        this.AdditionalDependencyNameAttributeTypes = additionalDependencyNameAttributeTypes;\n        this.AdditionalDependencyAttributeTypes = additionalDependencyAttributeTypes;\n        this.ExternalResolutionFailedExceptionType = externalResolutionFailedExceptionType;\n    }\n\n    internal ContainerConfiguration Clone() =>\n        new(this.TrackTransientsForDisposalEnabled,\n            this.RegistrationBehavior,\n            this.DefaultValueInjectionEnabled,\n            this.UnknownTypeResolutionEnabled,\n            this.AutoMemberInjectionEnabled,\n            this.TreatingParameterAndMemberNameAsDependencyNameEnabled,\n            this.NamedDependencyResolutionForUnNamedRequestsEnabled,\n            this.NamedDependencyResolutionForUnNamedCollectionRequestsEnabled,\n            this.ReBuildSingletonsInChildContainerEnabled,\n            this.VariantGenericTypesEnabled,\n            this.ExceptionOverEmptyCollectionEnabled,\n            this.AutoMemberInjectionRule,\n            this.ConstructorSelectionRule,\n            this.UnknownTypeConfigurator,\n            this.ConfigurationChangedEvent,\n            this.AutoMemberInjectionFilter,\n            this.DefaultLifetime,\n            this.LifetimeValidationEnabled,\n            this.ExternalExpressionCompiler,\n            this.UniversalName,\n            this.ExternalResolutionFailedExceptionType,\n            this.AdditionalDependencyNameAttributeTypes,\n            this.AdditionalDependencyAttributeTypes);\n}"
  },
  {
    "path": "src/Configuration/ContainerConfigurator.cs",
    "content": "﻿using Stashbox.Lifetime;\nusing Stashbox.Registration.Fluent;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq.Expressions;\nusing System.Reflection;\nusing Stashbox.Attributes;\nusing Stashbox.Exceptions;\nusing Stashbox.Utils.Data;\n\nnamespace Stashbox.Configuration;\n\n/// <summary>\n/// Represents a container configurator.\n/// </summary>\npublic class ContainerConfigurator\n{\n    /// <summary>\n    /// The container configuration.\n    /// </summary>\n    public ContainerConfiguration ContainerConfiguration { get; }\n\n    internal ContainerConfigurator(ContainerConfiguration? containerConfiguration = null)\n    {\n        this.ContainerConfiguration = containerConfiguration ?? new ContainerConfiguration();\n    }\n\n    /// <summary>\n    /// Enables or disables the tracking of disposable transient objects.\n    /// It's disabled by default.\n    /// </summary>\n    /// <param name=\"enabled\">True when the feature should be enabled, otherwise false.</param>\n    /// <returns>The container configurator.</returns>\n    public ContainerConfigurator WithDisposableTransientTracking(bool enabled = true)\n    {\n        this.ContainerConfiguration.TrackTransientsForDisposalEnabled = enabled;\n        return this;\n    }\n\n    /// <summary>\n    /// Sets the actual behavior used when a new service is registered into the container. These options do not affect named registrations. See the <see cref=\"Rules.RegistrationBehavior\"/> enum for available options.\n    /// </summary>\n    /// <param name=\"registrationBehavior\">The actual registration behavior.</param>\n    /// <returns>The container configurator.</returns>\n    public ContainerConfigurator WithRegistrationBehavior(Rules.RegistrationBehavior registrationBehavior)\n    {\n        this.ContainerConfiguration.RegistrationBehavior = registrationBehavior;\n        return this;\n    }\n\n    /// <summary>\n    /// Enables or disables the default value injection.\n    /// It's disabled by default.\n    /// </summary>\n    /// <param name=\"enabled\">True when the feature should be enabled, otherwise false.</param>\n    /// <returns>The container configurator.</returns>\n    public ContainerConfigurator WithDefaultValueInjection(bool enabled = true)\n    {\n        this.ContainerConfiguration.DefaultValueInjectionEnabled = enabled;\n        return this;\n    }\n\n    /// <summary>\n    /// Enables or disables the unknown type resolution.\n    /// It's disabled by default.\n    /// </summary>\n    /// <param name=\"configurator\">An optional configuration action used during the registration of the unknown type.</param>\n    /// <param name=\"enabled\">True when the feature should be enabled, otherwise false.</param>\n    /// <returns>The container configurator.</returns>\n    public ContainerConfigurator WithUnknownTypeResolution(Action<UnknownRegistrationConfigurator>? configurator = null, bool enabled = true)\n    {\n        this.ContainerConfiguration.UnknownTypeResolutionEnabled = enabled;\n        this.ContainerConfiguration.UnknownTypeConfigurator = configurator;\n        return this;\n    }\n\n    /// <summary>\n    /// Enables or disables the auto member-injection without annotation.\n    /// </summary>\n    /// <param name=\"rule\">The rule used to determine what kind of members (properties / fields) should be auto injected.</param>\n    /// <param name=\"filter\">An optional filter predicate used to select which properties or fields of a type should be auto injected.</param>\n    /// <param name=\"enabled\">True when the feature should be enabled, otherwise false.</param>\n    /// <returns>The container configurator.</returns>\n    public ContainerConfigurator WithAutoMemberInjection(Rules.AutoMemberInjectionRules rule = Rules.AutoMemberInjectionRules.PropertiesWithPublicSetter, Func<MemberInfo, bool>? filter = null, bool enabled = true)\n    {\n        this.ContainerConfiguration.AutoMemberInjectionEnabled = enabled;\n        this.ContainerConfiguration.AutoMemberInjectionRule = rule;\n        this.ContainerConfiguration.AutoMemberInjectionFilter = filter;\n        return this;\n    }\n    \n    /// <summary>\n    /// Enables or disables required member injection.\n    /// It's disabled by default.\n    /// </summary>\n    /// <param name=\"enabled\">True when the feature should be enabled, otherwise false.</param>\n    /// <returns>The container configurator.</returns>\n    public ContainerConfigurator WithRequiredMemberInjection(bool enabled = true)\n    {\n        this.ContainerConfiguration.RequiredMemberInjectionEnabled = enabled;\n        return this;\n    }\n\n    /// <summary>\n    /// Sets the constructor selection rule used to determine which constructor the container should use for instantiation\n    /// </summary>\n    /// <returns>The container configurator.</returns>\n    public ContainerConfigurator WithConstructorSelectionRule(Func<IEnumerable<ConstructorInfo>, IEnumerable<ConstructorInfo>> selectionRule)\n    {\n        this.ContainerConfiguration.ConstructorSelectionRule = selectionRule;\n        return this;\n    }\n\n    /// <summary>\n    /// Sets a callback delegate to call when the container configuration changes.\n    /// </summary>\n    /// <returns>The container configurator.</returns>\n    public ContainerConfigurator OnContainerConfigurationChanged(Action<ContainerConfiguration> configurationChanged)\n    {\n        this.ContainerConfiguration.ConfigurationChangedEvent = configurationChanged;\n        return this;\n    }\n\n    /// <summary>\n    /// Enables or disables conventional resolution, which means the container treats the constructor/method parameter or member names as dependency names used by named resolution.\n    /// It's disabled by default.\n    /// </summary>\n    /// <param name=\"enabled\">True when the feature should be enabled, otherwise false.</param>\n    /// <returns>The container configurator.</returns>\n    public ContainerConfigurator TreatParameterAndMemberNameAsDependencyName(bool enabled = true)\n    {\n        this.ContainerConfiguration.TreatingParameterAndMemberNameAsDependencyNameEnabled = enabled;\n        return this;\n    }\n\n    /// <summary>\n    /// Enables or disables the selection of named registrations when the resolution request is unnamed.\n    /// It's disabled by default.\n    /// </summary>\n    /// <param name=\"enabled\">True when the feature should be enabled, otherwise false.</param>\n    /// <param name=\"enabledForCollectionRequests\">Enables or disables the selection of named registrations when a collection resolution request is unnamed. It's enabled by default.</param>\n    /// <returns>The container configurator.</returns>\n    public ContainerConfigurator WithNamedDependencyResolutionForUnNamedRequests(bool enabled = true, bool enabledForCollectionRequests = true)\n    {\n        this.ContainerConfiguration.NamedDependencyResolutionForUnNamedRequestsEnabled = enabled;\n        this.ContainerConfiguration.NamedDependencyResolutionForUnNamedCollectionRequestsEnabled = enabledForCollectionRequests;\n        return this;\n    }\n    \n    /// <summary>\n    /// Enables or disables the selection of services with <see cref=\"ContainerConfiguration.UniversalName\"/> for a universal named resolution request.\n    /// It's disabled by default.\n    /// </summary>\n    /// <param name=\"enabled\">True when the feature should be enabled, otherwise false.</param>\n    /// <returns>The container configurator.</returns>\n    public ContainerConfigurator WithIgnoreServicesWithUniversalNameForUniversalNamedRequests(bool enabled = true)\n    {\n        this.ContainerConfiguration.IgnoreServicesWithUniversalNameForUniversalNamedRequests = enabled;\n        return this;\n    }\n    \n    /// <summary>\n    /// Enables or disables throwing a <see cref=\"ResolutionFailedException\"/> when a named dependency is not resolvable even for requests initiated by <see cref=\"IDependencyResolver.ResolveOrDefault(Type)\" />.\n    /// It's disabled by default.\n    /// </summary>\n    /// <param name=\"enabled\">True when the feature should be enabled, otherwise false.</param>\n    /// <returns>The container configurator.</returns>\n    public ContainerConfigurator WithForceThrowWhenNamedDependencyIsNotResolvable(bool enabled = true)\n    {\n        this.ContainerConfiguration.ForceThrowWhenNamedDependencyIsNotResolvable = enabled;\n        return this;\n    }\n    \n    /// <summary>\n    /// Sets the default lifetime used when a service doesn't have a configured one.\n    /// </summary>\n    /// <param name=\"lifetime\">The default lifetime.</param>\n    /// <returns>The container configurator.</returns>\n    public ContainerConfigurator WithDefaultLifetime(LifetimeDescriptor lifetime)\n    {\n        this.ContainerConfiguration.DefaultLifetime = lifetime;\n        return this;\n    }\n\n    /// <summary>\n    /// Enables or disables the life-span and root resolution validation on the dependency tree.\n    /// It's disabled by default.\n    /// </summary>\n    /// <param name=\"enabled\">True when the feature should be enabled, otherwise false.</param>\n    /// <returns>The container configurator.</returns>\n    public ContainerConfigurator WithLifetimeValidation(bool enabled = true)\n    {\n        this.ContainerConfiguration.LifetimeValidationEnabled = enabled;\n        return this;\n    }\n\n    /// <summary>\n    /// Enables or disables the re-building of singletons in child containers.\n    /// It allows the child containers to effectively override singleton dependencies in the parent.\n    /// This feature is not affecting the already built singleton instances in the parent.\n    /// It's disabled by default.\n    /// </summary>\n    /// <param name=\"enabled\">True when the feature should be enabled, otherwise false.</param>\n    /// <returns>The container configurator.</returns>\n    public ContainerConfigurator WithReBuildSingletonsInChildContainer(bool enabled = true)\n    {\n        this.ContainerConfiguration.ReBuildSingletonsInChildContainerEnabled = enabled;\n        return this;\n    }\n    \n    /// <summary>\n    /// Enables or disables the check for generic covariance and contravariance during the resolution of generic type collections.\n    /// It's disabled by default.\n    /// </summary>\n    /// <param name=\"enabled\">True when the feature should be enabled, otherwise false.</param>\n    /// <returns>The container configurator.</returns>\n    public ContainerConfigurator WithVariantGenericTypes(bool enabled = true)\n    {\n        this.ContainerConfiguration.VariantGenericTypesEnabled = enabled;\n        return this;\n    }\n\n    /// <summary>\n    /// Enables or disables the throwing of a <see cref=\"ResolutionFailedException\"/> when no services are found for a collection resolution request.\n    /// When this feature is disabled (default), the container returns an empty array for the collection resolution request.\n    /// It's disabled by default.\n    /// </summary>\n    /// <param name=\"enabled\">True when the feature should be enabled, otherwise false.</param>\n    /// <returns>The container configurator.</returns>\n    public ContainerConfigurator WithExceptionOverEmptyCollection(bool enabled = true)\n    {\n        this.ContainerConfiguration.ExceptionOverEmptyCollectionEnabled = enabled;\n        return this;\n    }\n\n    /// <summary>\n    /// Sets an external expression tree compiler used by the container to compile the generated expressions.\n    /// </summary>\n    /// <param name=\"compilerDelegate\">The compiler delegate used to compile expression trees.</param>\n    /// <returns>The container configurator.</returns>\n    public ContainerConfigurator WithExpressionCompiler(Func<LambdaExpression, Delegate> compilerDelegate)\n    {\n        this.ContainerConfiguration.ExternalExpressionCompiler = compilerDelegate;\n        return this;\n    }\n    \n    /// <summary>\n    /// Sets the universal name that represents a special name which allows named resolution work for any given name.\n    /// </summary>\n    /// <param name=\"name\">The universal name.</param>\n    /// <returns>The container configurator.</returns>\n    public ContainerConfigurator WithUniversalName(object name)\n    {\n        this.ContainerConfiguration.UniversalName = name;\n        return this;\n    }\n    \n    /// <summary>\n    /// Adds an attribute type that is considered a dependency name indicator just like <see cref=\"DependencyNameAttribute\"/>. \n    /// </summary>\n    /// <typeparam name=\"TAttribute\">The attribute type.</typeparam>\n    /// <returns>The container configurator.</returns>\n    public ContainerConfigurator WithAdditionalDependencyNameAttribute<TAttribute>()\n        where TAttribute : Attribute\n    {\n        this.ContainerConfiguration.AdditionalDependencyNameAttributeTypes ??= [];\n        this.ContainerConfiguration.AdditionalDependencyNameAttributeTypes.Add(typeof(TAttribute));\n        return this;\n    }\n    \n    /// <summary>\n    /// Adds an attribute type that is considered a dependency indicator just like <see cref=\"DependencyAttribute\"/>. \n    /// </summary>\n    /// <typeparam name=\"TAttribute\">The attribute type.</typeparam>\n    /// <returns>The container configurator.</returns>\n    public ContainerConfigurator WithAdditionalDependencyAttribute<TAttribute>()\n        where TAttribute : Attribute\n    {\n        this.ContainerConfiguration.AdditionalDependencyAttributeTypes ??= [];\n        this.ContainerConfiguration.AdditionalDependencyAttributeTypes.Add(typeof(TAttribute));\n        return this;\n    }\n    \n    /// <summary>\n    /// Wraps each <see cref=\"ResolutionFailedException\"/> with the given exception type. \n    /// </summary>\n    /// <typeparam name=\"TException\">The exception type.</typeparam>\n    /// <returns>The container configurator.</returns>\n    public ContainerConfigurator OverrideResolutionFailedExceptionWith<TException>()\n        where TException : Exception\n    {\n        this.ContainerConfiguration.ExternalResolutionFailedExceptionType = typeof(TException);\n        return this;\n    }\n}"
  },
  {
    "path": "src/Configuration/Rules.cs",
    "content": "﻿using Stashbox.Exceptions;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Linq.Expressions;\nusing System.Reflection;\n\nnamespace Stashbox.Configuration;\n\n/// <summary>\n/// Represents the predefined configuration rules of the <see cref=\"StashboxContainer\"/>.\n/// </summary>\npublic static class Rules\n{\n    /// <summary>\n    /// Represents the rules related to registration filters used in <see cref=\"IDependencyCollectionRegistrator.RegisterTypes(IEnumerable{Type}, Func{Type, bool}, Func{Type, Type, bool}, bool, Action{Registration.Fluent.RegistrationConfigurator})\"/>.\n    /// </summary>\n    public static class ServiceRegistrationFilters\n    {\n        /// <summary>\n        /// Includes only interface types.\n        /// </summary>\n        public static readonly Func<Type, Type, bool> Interfaces = (_, t) => t.IsInterface;\n\n        /// <summary>\n        /// Includes only abstract types.\n        /// </summary>\n        public static readonly Func<Type, Type, bool> AbstractClasses = (_, t) => t.IsAbstract && !t.IsInterface;\n    }\n\n    /// <summary>\n    /// Represents the actual behavior used when a new service is going to be registered into the container. These options does not affect named registrations.\n    /// </summary>\n    public enum RegistrationBehavior\n    {\n        /// <summary>\n        /// The container will skip new registrations when the given implementation type is already registered.\n        /// </summary>\n        SkipDuplications,\n\n        /// <summary>\n        /// The container will throw a <see cref=\"ServiceAlreadyRegisteredException\"/> when the given implementation type is already registered.\n        /// </summary>\n        ThrowException,\n\n        /// <summary>\n        /// The container will replace the already registered service with the given one when they have the same implementation type.\n        /// </summary>\n        ReplaceExisting,\n\n        /// <summary>\n        /// The container will keep registering the new services with the same implementation type.\n        /// </summary>\n        PreserveDuplications\n    }\n\n    /// <summary>\n    /// Represents the rules for auto-injecting members.\n    /// </summary>\n    [Flags]\n    public enum AutoMemberInjectionRules\n    {\n        /// <summary>\n        /// None will be injected.\n        /// </summary>\n        None = 1 << 1,\n\n        /// <summary>\n        /// With this flag the container will perform auto-injection on properties which has a public setter.\n        /// </summary>\n        PropertiesWithPublicSetter = 1 << 2,\n\n        /// <summary>\n        /// With this flag the container will perform auto-injection on properties which has a non-public setter as well.\n        /// </summary>\n        PropertiesWithLimitedAccess = 1 << 3,\n\n        /// <summary>\n        /// With this flag the container will perform auto-injection on private fields too.\n        /// </summary>\n        PrivateFields = 1 << 4\n    }\n\n    /// <summary>\n    /// Represents the constructor selection rules.\n    /// </summary>\n    public static class ConstructorSelection\n    {\n        /// <summary>\n        /// Prefers the constructor which has the longest parameter list.\n        /// </summary>\n        public static readonly Func<IEnumerable<ConstructorInfo>, IEnumerable<ConstructorInfo>> PreferMostParameters =\n            constructors => constructors.OrderByDescending(constructor => constructor.GetParameters().Length);\n\n        /// <summary>\n        /// Prefers the constructor which has the shortest parameter list.\n        /// </summary>\n        public static readonly Func<IEnumerable<ConstructorInfo>, IEnumerable<ConstructorInfo>> PreferLeastParameters =\n            constructors => constructors.OrderBy(constructor => constructor.GetParameters().Length);\n    }\n\n    /// <summary>\n    /// Pre-defined expression compiler delegates.\n    /// </summary>\n    public static class ExpressionCompilers\n    {\n        /// <summary>\n        /// The standard Microsoft expression compiler.\n        /// </summary>\n        public static readonly Func<LambdaExpression, Delegate>\n            MicrosoftExpressionCompiler = lambda => lambda.Compile();\n\n        /// <summary>\n        /// The built-in Stashbox expression compiler.\n        /// </summary>\n        public static readonly Func<LambdaExpression, Delegate>\n            StashboxExpressionCompiler = lambda => lambda.CompileDelegate();\n    }\n}"
  },
  {
    "path": "src/ContainerContext.cs",
    "content": "﻿using Stashbox.Configuration;\nusing Stashbox.Registration;\nusing Stashbox.Resolution;\n\nnamespace Stashbox;\n\ninternal class ContainerContext : IContainerContext\n{\n    public ContainerContext(IContainerContext? parentContext,\n        IResolutionStrategy resolutionStrategy, ContainerConfiguration containerConfiguration)\n    {\n        this.ContainerConfiguration = containerConfiguration;\n        this.ParentContext = parentContext;\n        this.RootScope = new ResolutionScope(this);\n        this.RegistrationRepository = new RegistrationRepository(containerConfiguration);\n        this.DecoratorRepository = new DecoratorRepository(containerConfiguration);\n        this.ResolutionStrategy = resolutionStrategy;\n    }\n\n    public IRegistrationRepository RegistrationRepository { get; }\n\n    public IDecoratorRepository DecoratorRepository { get; }\n\n    public IContainerContext? ParentContext { get; }\n\n    public IResolutionScope RootScope { get; }\n\n    public IResolutionStrategy ResolutionStrategy { get; }\n\n    public ContainerConfiguration ContainerConfiguration { get; }\n\n}"
  },
  {
    "path": "src/Exceptions/CompositionRootNotFoundException.cs",
    "content": "﻿using System;\nusing System.Reflection;\nusing System.Runtime.Serialization;\n\nnamespace Stashbox.Exceptions;\n\n/// <summary>\n/// Occurs when composing requested but no <see cref=\"ICompositionRoot\"/> is present in the given assembly.\n/// </summary>\n[Serializable]\npublic class CompositionRootNotFoundException : Exception\n{\n    /// <summary>\n    /// Constructs a <see cref=\"CompositionRootNotFoundException\"/>.\n    /// </summary>\n    /// <param name=\"assembly\">The scanned assembly.</param>\n    /// <param name=\"innerException\">The inner exception.</param>\n    public CompositionRootNotFoundException(Assembly assembly, Exception? innerException = null)\n        : base($\"No ICompositionRoot found in the given assembly: {assembly.FullName}.\", innerException)\n    { }\n\n    /// <inheritdoc />\n#if NET8_0_OR_GREATER\n    [Obsolete(DiagnosticId = \"SYSLIB0051\")] // add this attribute to the serialization ctor\n#endif\n    protected CompositionRootNotFoundException(SerializationInfo info, StreamingContext context)\n        : base(info, context)\n    { }\n}"
  },
  {
    "path": "src/Exceptions/ConstructorNotFoundException.cs",
    "content": "﻿using System;\nusing System.Linq;\nusing System.Runtime.Serialization;\n\nnamespace Stashbox.Exceptions;\n\n/// <summary>\n/// Represents a constructor not found exception.\n/// </summary>\n[Serializable]\npublic class ConstructorNotFoundException : Exception\n{\n    /// <summary>\n    /// Constructs a <see cref=\"ConstructorNotFoundException\"/>.\n    /// </summary>\n    /// <param name=\"type\">The type on the constructor was not found.</param>\n    /// <param name=\"argumentTypes\">The arguments.</param>\n    /// <param name=\"innerException\">The inner exception</param>\n    public ConstructorNotFoundException(Type type, Type[] argumentTypes, Exception? innerException = null) :\n        base($\"Constructor not found for '{type.FullName}' with the given argument types: {argumentTypes.Select(t => t.FullName).Aggregate((t1, t2) => $\"{t1}, {t2}\")}.\", innerException)\n    { }\n\n    /// <summary>\n    /// Constructs a <see cref=\"ConstructorNotFoundException\"/>.\n    /// </summary>\n    /// <param name=\"type\">The type on the constructor was not found.</param>\n    /// <param name=\"innerException\">The inner exception</param>\n    public ConstructorNotFoundException(Type type, Exception? innerException = null) :\n        base($\"Constructor not found for '{type.FullName}' with no arguments.\", innerException)\n    { }\n\n    /// <summary>\n    /// Constructs a <see cref=\"ConstructorNotFoundException\"/>.\n    /// </summary>\n    /// <param name=\"type\">The type on the constructor was not found.</param>\n    /// <param name=\"argument\">The argument type.</param>\n    /// <param name=\"innerException\">The inner exception</param>\n    public ConstructorNotFoundException(Type type, Type argument, Exception? innerException = null) :\n        base($\"Constructor not found for '{type.FullName}' with the argument type: {argument.FullName}.\", innerException)\n    { }\n\n    /// <inheritdoc />\n#if NET8_0_OR_GREATER\n    [Obsolete(DiagnosticId = \"SYSLIB0051\")] // add this attribute to the serialization ctor\n#endif\n    protected ConstructorNotFoundException(SerializationInfo info, StreamingContext context)\n        : base(info, context)\n    { }\n}"
  },
  {
    "path": "src/Exceptions/InvalidRegistrationException.cs",
    "content": "﻿using System;\nusing System.Runtime.Serialization;\n\nnamespace Stashbox.Exceptions;\n\n/// <summary>\n/// Represents an exception the container throws when it detects an invalid registration.\n/// </summary>\n[Serializable]\npublic class InvalidRegistrationException : Exception\n{\n    /// <summary>\n    /// The type the container is trying to register.\n    /// </summary>\n    public Type? Type { get; }\n\n    /// <summary>\n    /// Constructs a <see cref=\"InvalidRegistrationException\"/>.\n    /// </summary>\n    /// <param name=\"type\">The type of the service.</param>\n    /// <param name=\"message\">The exception message.</param>\n    /// <param name=\"innerException\">The inner exception.</param>\n    public InvalidRegistrationException(Type? type, string message, Exception? innerException = null)\n        : base($\"Invalid registration with type '{type?.FullName}'. Details: {message}\", innerException)\n    {\n        this.Type = type;\n    }\n\n    /// <inheritdoc />\n#if NET8_0_OR_GREATER\n    [Obsolete(DiagnosticId = \"SYSLIB0051\")] // add this attribute to the serialization ctor\n#endif\n    protected InvalidRegistrationException(SerializationInfo info, StreamingContext context)\n        : base(info, context)\n    { }\n}"
  },
  {
    "path": "src/Exceptions/LifetimeValidationFailedException.cs",
    "content": "﻿using System;\nusing System.Runtime.Serialization;\n\nnamespace Stashbox.Exceptions;\n\n/// <summary>\n/// Represents the exception the container throws when the lifetime validation is failed.\n/// </summary>\n[Serializable]\npublic class LifetimeValidationFailedException : Exception\n{\n    /// <summary>\n    /// The type the container is currently resolving.\n    /// </summary>\n    public Type? Type { get; }\n\n    /// <summary>\n    /// Constructs a <see cref=\"LifetimeValidationFailedException\"/>.\n    /// </summary>\n    /// <param name=\"type\">The type of the service.</param>\n    /// <param name=\"message\">The exception message.</param>\n    public LifetimeValidationFailedException(Type? type, string message)\n        : base(message)\n    {\n        this.Type = type;\n    }\n\n    /// <inheritdoc />\n#if NET8_0_OR_GREATER\n    [Obsolete(DiagnosticId = \"SYSLIB0051\")] // add this attribute to the serialization ctor\n#endif\n    protected LifetimeValidationFailedException(SerializationInfo info, StreamingContext context)\n        : base(info, context)\n    { }\n}"
  },
  {
    "path": "src/Exceptions/ResolutionFailedException.cs",
    "content": "﻿using System;\nusing System.Runtime.Serialization;\n\nnamespace Stashbox.Exceptions;\n\n/// <summary>\n/// Represents the exception the container throws when a service resolution is failed.\n/// </summary>\n[Serializable]\npublic class ResolutionFailedException : Exception\n{\n    private const string DefaultMessage = \"Service is not registered properly or unresolvable type requested.\";\n    \n    /// <summary>\n    /// The type the container is currently resolving.\n    /// </summary>\n    public Type? Type { get; }\n\n    /// <summary>\n    /// Constructs a <see cref=\"ResolutionFailedException\"/>.\n    /// </summary>\n    /// <param name=\"type\">The type of the service.</param>\n    /// <param name=\"name\">The name of the service.</param>\n    /// <param name=\"message\">The exception message.</param>\n    /// <param name=\"innerException\">The inner exception.</param>\n    public ResolutionFailedException(Type? type,\n        object? name = null,\n        string? message = null,\n        Exception? innerException = null)\n        : base(ConstructMessage(type, name, message), innerException)\n    {\n        this.Type = type;\n    }\n\n    /// <inheritdoc />\n#if NET8_0_OR_GREATER\n    [Obsolete(DiagnosticId = \"SYSLIB0051\")] // add this attribute to the serialization ctor\n#endif\n    protected ResolutionFailedException(SerializationInfo info, StreamingContext context)\n        : base(info, context)\n    { }\n\n    private static string ConstructMessage(Type? serviceType,\n        object? name = null,\n        string? message = null) =>\n        $\"Unable to resolve type '{serviceType?.FullName}'{(name != null ? \" with name \\'\" + name + \"\\'\" : \"\")}.{Environment.NewLine}{message ?? DefaultMessage}\";\n    \n    internal static Exception CreateWithDesiredExceptionType(Type? serviceType,\n        object? name = null,\n        string? message = null,\n        Exception? innerException = null,\n        Type? externalExceptionType = null)\n    {\n        if (externalExceptionType == null) \n            return new ResolutionFailedException(serviceType, name, message, innerException);\n\n        return (Exception)(Activator.CreateInstance(externalExceptionType, ConstructMessage(serviceType, name, message), innerException) ?? new ResolutionFailedException(serviceType, name, message, innerException));\n    }\n}"
  },
  {
    "path": "src/Exceptions/ServiceAlreadyRegisteredException.cs",
    "content": "﻿using Stashbox.Configuration;\nusing System;\nusing System.Runtime.Serialization;\n\nnamespace Stashbox.Exceptions;\n\n/// <summary>\n/// Represents the exception the container throws when a registration process fails due to service duplication.\n/// Occurs when the container is configured with <see cref=\"Rules.RegistrationBehavior.ThrowException\"/>.\n/// </summary>\n[Serializable]\npublic class ServiceAlreadyRegisteredException : Exception\n{\n    /// <summary>\n    /// The type the container is trying to register.\n    /// </summary>\n    public Type? Type { get; }\n\n    /// <summary>\n    /// Constructs a <see cref=\"ServiceAlreadyRegisteredException\"/>.\n    /// </summary>\n    /// <param name=\"type\">The type of the service.</param>\n    /// <param name=\"innerException\">The inner exception.</param>\n    public ServiceAlreadyRegisteredException(Type? type, Exception? innerException = null)\n        : base($\"The type '{type?.FullName}' is already registered.\", innerException)\n    {\n        this.Type = type;\n    }\n\n    /// <inheritdoc />\n#if NET8_0_OR_GREATER\n    [Obsolete(DiagnosticId = \"SYSLIB0051\")] // add this attribute to the serialization ctor\n#endif\n    protected ServiceAlreadyRegisteredException(SerializationInfo info, StreamingContext context)\n        : base(info, context)\n    { }\n}"
  },
  {
    "path": "src/Expressions/Compile/Closure.cs",
    "content": "﻿using System.Reflection;\nusing Stashbox.Utils;\n\nnamespace Stashbox.Expressions.Compile;\n\ninternal class Closure\n{\n    public static readonly FieldInfo ConstantsField = TypeCache<Closure>.Type.GetField(nameof(Constants))!;\n\n    public readonly object[] Constants;\n\n    public Closure(object[] constants)\n    {\n        this.Constants = constants;\n    }\n}"
  },
  {
    "path": "src/Expressions/Compile/CompilerContext.cs",
    "content": "﻿using Stashbox.Utils.Data;\nusing System.Linq.Expressions;\nusing System.Reflection.Emit;\n\nnamespace Stashbox.Expressions.Compile;\n\ninternal class CompilerContext\n{\n    public readonly ExpandableArray<Expression> DefinedVariables;\n\n    public readonly bool HasCapturedVariablesArgument;\n\n    public readonly bool IsNestedLambda;\n\n    public readonly ExpandableArray<object> Constants;\n\n    public readonly ExpandableArray<Expression> CapturedArguments;\n\n    public readonly Closure? Target;\n\n    public LocalBuilder[]? LocalBuilders;\n\n    public LocalBuilder? CapturedArgumentsHolderVariable;\n\n    public readonly ExpandableArray<LambdaExpression, NestedLambda> NestedLambdas;\n\n    public readonly bool HasClosure;\n\n    public CompilerContext(Closure? target,\n        ExpandableArray<object> constants,\n        ExpandableArray<Expression> definedVariables,\n        ExpandableArray<Expression> capturedArguments,\n        ExpandableArray<LambdaExpression, NestedLambda> nestedLambdas)\n    {\n        this.Target = target;\n        this.Constants = constants;\n        this.DefinedVariables = definedVariables;\n        this.CapturedArguments = capturedArguments;\n        this.NestedLambdas = nestedLambdas;\n        this.HasClosure = target != null;\n        this.HasCapturedVariablesArgument = capturedArguments.Length > 0;\n    }\n\n    private CompilerContext(ExpandableArray<Expression> definedVariables,\n        bool hasCapturedVariablesArgument,\n        bool isNestedLambda,\n        ExpandableArray<object> constants,\n        ExpandableArray<Expression> capturedArguments,\n        Closure? target,\n        LocalBuilder[]? localBuilders,\n        LocalBuilder? capturedArgumentsHolderVariable,\n        ExpandableArray<LambdaExpression, NestedLambda> nestedLambdas,\n        bool hasClosure)\n    {\n        DefinedVariables = definedVariables;\n        HasCapturedVariablesArgument = hasCapturedVariablesArgument;\n        IsNestedLambda = isNestedLambda;\n        Constants = constants;\n        CapturedArguments = capturedArguments;\n        Target = target;\n        LocalBuilders = localBuilders;\n        CapturedArgumentsHolderVariable = capturedArgumentsHolderVariable;\n        NestedLambdas = nestedLambdas;\n        HasClosure = hasClosure;\n    }\n\n    public CompilerContext Clone(ExpandableArray<Expression> definedVariables, bool isNestedLambda, bool hasCapturedArgument) =>\n        new(definedVariables,\n            hasCapturedArgument,\n            isNestedLambda,\n            this.Constants,\n            this.CapturedArguments,\n            this.Target,\n            this.LocalBuilders,\n            this.CapturedArgumentsHolderVariable,\n            this.NestedLambdas,\n            this.HasClosure);\n}"
  },
  {
    "path": "src/Expressions/Compile/Emitters/Emitter.Assign.cs",
    "content": "﻿using Stashbox.Expressions.Compile.Extensions;\nusing System.Linq.Expressions;\nusing System.Reflection.Emit;\n\nnamespace Stashbox.Expressions.Compile.Emitters;\n\ninternal static partial class Emitter\n{\n    private static bool TryEmit(this BinaryExpression expression, ILGenerator generator, CompilerContext context, params ParameterExpression[] parameters)\n    {\n        switch (expression.Left.NodeType)\n        {\n            case ExpressionType.Parameter:\n\n                var localIndex = context.DefinedVariables.IndexOf(expression.Left);\n                if (localIndex == -1 || context.LocalBuilders == null) return false;\n\n                if (!expression.Right.TryEmit(generator, context, parameters))\n                    return false;\n\n                generator.Emit(OpCodes.Stloc, context.LocalBuilders[localIndex]);\n\n                if (!context.HasCapturedVariablesArgument) return true;\n\n                var paramIndex = context.CapturedArguments.IndexOf(expression.Left);\n                if (paramIndex == -1) return true;\n\n                generator.LoadCapturedArgumentHolder(context);\n                generator.EmitInteger(paramIndex);\n                generator.Emit(OpCodes.Ldloc, context.LocalBuilders[localIndex]);\n                if (expression.Type.IsValueType)\n                    generator.Emit(OpCodes.Box, expression.Type);\n                generator.Emit(OpCodes.Stelem_Ref);\n\n                return true;\n\n            case ExpressionType.MemberAccess:\n                var memberExpression = (MemberExpression)expression.Left;\n\n                if (memberExpression.Expression != null && !memberExpression.Expression.TryEmit(generator, context, parameters))\n                    return false;\n\n                return expression.Right.TryEmit(generator, context, parameters) && memberExpression.Member.EmitMemberAssign(generator);\n\n            default:\n                return false;\n        }\n    }\n}"
  },
  {
    "path": "src/Expressions/Compile/Emitters/Emitter.Call.cs",
    "content": "﻿using Stashbox.Expressions.Compile.Extensions;\nusing System.Linq.Expressions;\nusing System.Reflection.Emit;\n\nnamespace Stashbox.Expressions.Compile.Emitters;\n\ninternal static partial class Emitter\n{\n    private static bool TryEmit(this MethodCallExpression expression, ILGenerator generator, CompilerContext context, params ParameterExpression[] parameters)\n    {\n        if (expression.Object != null && !expression.Object.TryEmit(generator, context, parameters))\n            return false;\n\n        return expression.Arguments.TryEmit(generator, context, parameters) &&\n               generator.EmitMethod(expression.Method);\n    }\n}"
  },
  {
    "path": "src/Expressions/Compile/Emitters/Emitter.Constant.cs",
    "content": "﻿using Stashbox.Expressions.Compile.Extensions;\nusing System;\nusing System.Linq.Expressions;\nusing System.Reflection.Emit;\nusing Stashbox.Utils;\n\nnamespace Stashbox.Expressions.Compile.Emitters;\n\ninternal static partial class Emitter\n{\n    private static bool TryEmit(this ConstantExpression expression, ILGenerator generator, CompilerContext context)\n    {\n        var value = expression.Value;\n        var type = expression.Type;\n\n        if (value == null)\n        {\n            if (expression.Type.IsValueType)\n                generator.InitValueType(expression.Type);\n            else\n                generator.Emit(OpCodes.Ldnull);\n            return true;\n        }\n\n        if (context.HasClosure && !Utils.IsInPlaceEmittableConstant(type, value))\n        {\n            var constantIndex = context.Constants.IndexOf(value);\n            if (constantIndex == -1) return false;\n\n            generator.Emit(OpCodes.Ldarg_0);\n            generator.Emit(OpCodes.Ldfld, Closure.ConstantsField);\n            generator.EmitInteger(constantIndex);\n            generator.Emit(OpCodes.Ldelem_Ref);\n            if (type.IsValueType)\n                generator.Emit(OpCodes.Unbox_Any, type);\n            return true;\n        }\n\n        if (generator.TryEmitNumberConstant(type, value))\n            return true;\n\n        if (type.IsEnum)\n            return generator.TryEmitNumberConstant(Enum.GetUnderlyingType(type), value);\n\n        switch (value)\n        {\n            case string stringValue:\n                generator.Emit(OpCodes.Ldstr, stringValue);\n                break;\n            case Type typeValue:\n                generator.Emit(OpCodes.Ldtoken, typeValue);\n                generator.Emit(OpCodes.Call, TypeCache<Type>.Type.GetMethod(\"GetTypeFromHandle\")!);\n                break;\n            default:\n                return false;\n        }\n\n        return true;\n    }\n}"
  },
  {
    "path": "src/Expressions/Compile/Emitters/Emitter.Convert.cs",
    "content": "﻿using System;\nusing System.Linq.Expressions;\nusing System.Reflection;\nusing System.Reflection.Emit;\nusing Stashbox.Utils;\n\nnamespace Stashbox.Expressions.Compile.Emitters;\n\ninternal static partial class Emitter\n{\n    private static bool TryEmit(this UnaryExpression expression, ILGenerator generator, CompilerContext context, params ParameterExpression[] parameters)\n    {\n        var typeFrom = expression.Operand.Type;\n        var typeTo = expression.Type;\n\n        if (!expression.Operand.TryEmit(generator, context, parameters))\n            return false;\n\n        if (typeFrom == typeTo)\n            return true;\n\n        var typeToIsNullable = typeTo.IsNullableType();\n        var typeToUnderlyingType = Nullable.GetUnderlyingType(typeTo);\n\n        ConstructorInfo? constructor;\n        if (typeToIsNullable && typeFrom == typeToUnderlyingType && (constructor = typeTo.GetFirstConstructor()) != null)\n        {\n            generator.Emit(OpCodes.Newobj, constructor);\n            return true;\n        }\n\n        switch (typeFrom.IsValueType)\n        {\n            case false when typeTo.IsValueType:\n                generator.Emit(OpCodes.Unbox_Any, typeTo);\n                break;\n            case true when typeTo == TypeCache<object>.Type:\n                generator.Emit(OpCodes.Box, typeFrom);\n                break;\n            default:\n                generator.Emit(OpCodes.Castclass, typeTo);\n                break;\n        }\n\n        return true;\n    }\n}"
  },
  {
    "path": "src/Expressions/Compile/Emitters/Emitter.Default.cs",
    "content": "﻿using Stashbox.Expressions.Compile.Extensions;\nusing Stashbox.Utils;\nusing System.Linq.Expressions;\nusing System.Reflection.Emit;\n\nnamespace Stashbox.Expressions.Compile.Emitters;\n\ninternal static partial class Emitter\n{\n    private static bool TryEmit(this DefaultExpression expression, ILGenerator generator)\n    {\n        var type = expression.Type;\n\n        if (type == TypeCache.VoidType)\n            return true;\n\n        if (type == TypeCache<string>.Type)\n            generator.Emit(OpCodes.Ldnull);\n        else if (type == TypeCache<bool>.Type ||\n                 type == TypeCache<byte>.Type ||\n                 type == TypeCache<char>.Type ||\n                 type == TypeCache<sbyte>.Type ||\n                 type == TypeCache<int>.Type ||\n                 type == TypeCache<uint>.Type ||\n                 type == TypeCache<short>.Type ||\n                 type == TypeCache<ushort>.Type)\n            generator.Emit(OpCodes.Ldc_I4_0);\n        else if (type == TypeCache<long>.Type ||\n                 type == TypeCache<ulong>.Type)\n        {\n            generator.Emit(OpCodes.Ldc_I4_0);\n            generator.Emit(OpCodes.Conv_I8);\n        }\n        else if (type == TypeCache<float>.Type)\n            generator.Emit(OpCodes.Ldc_R4, default(float));\n        else if (type == TypeCache<double>.Type)\n            generator.Emit(OpCodes.Ldc_R8, default(double));\n        else if (type.IsValueType)\n            generator.InitValueType(type);\n        else\n            generator.Emit(OpCodes.Ldnull);\n\n        return true;\n    }\n}"
  },
  {
    "path": "src/Expressions/Compile/Emitters/Emitter.Invoke.cs",
    "content": "﻿using Stashbox.Expressions.Compile.Extensions;\nusing System.Linq.Expressions;\nusing System.Reflection.Emit;\n\nnamespace Stashbox.Expressions.Compile.Emitters;\n\ninternal static partial class Emitter\n{\n    private static bool TryEmit(this InvocationExpression expression, ILGenerator generator, CompilerContext context, params ParameterExpression[] parameters)\n    {\n        if (!expression.Expression.TryEmit(generator, context, parameters) || !expression.Arguments.TryEmit(generator, context, parameters))\n            return false;\n\n        var invokeMethod = expression.Expression.Type.GetMethod(\"Invoke\")!;\n        generator.EmitMethod(invokeMethod);\n\n        return true;\n    }\n}"
  },
  {
    "path": "src/Expressions/Compile/Emitters/Emitter.Lambda.cs",
    "content": "﻿using Stashbox.Expressions.Compile.Extensions;\nusing System.Linq;\nusing System.Linq.Expressions;\nusing System.Reflection.Emit;\nusing Stashbox.Utils;\n\nnamespace Stashbox.Expressions.Compile.Emitters;\n\ninternal static partial class Emitter\n{\n    private static bool TryEmit(this LambdaExpression expression, ILGenerator generator, CompilerContext context)\n    {\n        var lambdaIndex = context.NestedLambdas.IndexAndValueOf(expression, out var lambda);\n\n        if (lambdaIndex == -1 || context.Target == null || lambda == null) return false;\n\n        var lambdaClosureIndex = lambdaIndex + (context.Target.Constants.Length - context.NestedLambdas.Length);\n\n        generator.Emit(OpCodes.Ldarg_0);\n        generator.Emit(OpCodes.Ldfld, Closure.ConstantsField);\n        generator.EmitInteger(lambdaClosureIndex);\n        generator.Emit(OpCodes.Ldelem_Ref);\n\n        if (lambda.UsesCapturedArgument)\n        {\n            if (context is { IsNestedLambda: false, CapturedArgumentsHolderVariable: { } })\n                generator.Emit(OpCodes.Ldloc, context.CapturedArgumentsHolderVariable);\n            else\n                generator.Emit(OpCodes.Ldarg_1);\n        }\n\n        var variables = lambda.ParameterExpressions;\n        var nestedParameters = expression.Parameters.CastToArray();\n\n        var nestedContext = context.Clone(variables, true, lambda.UsesCapturedArgument);\n        if (nestedContext.Target == null) return false;\n\n        var method = new DynamicMethod(string.Empty,\n            expression.ReturnType,\n            nestedContext.HasCapturedVariablesArgument\n                ? new[] { TypeCache<Closure>.Type, TypeCache<object[]>.Type }.Append(nestedParameters.GetTypes())\n                : TypeCache<Closure>.Type.Append(nestedParameters.GetTypes()),\n            TypeCache<Closure>.Type,\n            true);\n\n        var nestedGenerator = method.GetILGenerator();\n\n        if (variables.Length > 0)\n            nestedContext.LocalBuilders = variables.BuildLocals(nestedGenerator);\n\n        if (nestedContext.HasCapturedVariablesArgument)\n            nestedGenerator.CopyParametersToCapturedArgumentsIfAny(nestedContext, nestedParameters);\n\n        if (!expression.Body.TryEmit(nestedGenerator, nestedContext, nestedParameters))\n            return false;\n\n        nestedGenerator.Emit(OpCodes.Ret);\n\n        if (nestedContext.HasCapturedVariablesArgument)\n        {\n            var delegateArgs = TypeCache<object[]>.Type\n                .Append(nestedParameters.GetTypes())\n                .Append(expression.ReturnType);\n\n            var resultDelegate = method.CreateDelegate(Utils.MapDelegateType(delegateArgs),\n                nestedContext.Target);\n\n            nestedContext.Target.Constants[lambdaClosureIndex] = resultDelegate;\n            generator.EmitMethod(Utils.GetPartialApplicationMethodInfo(delegateArgs));\n        }\n        else\n        {\n            var resultDelegate = method.CreateDelegate(expression.Type, nestedContext.Target);\n            nestedContext.Target.Constants[lambdaClosureIndex] = resultDelegate;\n        }\n\n        return true;\n    }\n}"
  },
  {
    "path": "src/Expressions/Compile/Emitters/Emitter.MemberAccess.cs",
    "content": "﻿using Stashbox.Expressions.Compile.Extensions;\nusing System.Linq.Expressions;\nusing System.Reflection;\nusing System.Reflection.Emit;\n\nnamespace Stashbox.Expressions.Compile.Emitters;\n\ninternal static partial class Emitter\n{\n    private static bool TryEmit(this MemberExpression expression, ILGenerator generator, CompilerContext context,\n        params ParameterExpression[] parameters)\n    {\n        if (expression.Expression == null)\n            return false;\n\n        return expression.Expression.TryEmit(generator, context, parameters) && expression.Member.EmitMemberAccess(generator);\n    }\n\n\n    private static bool EmitMemberAssign(this MemberInfo member, ILGenerator generator)\n    {\n        switch (member)\n        {\n            case PropertyInfo property:\n            {\n                var setMethod = property.GetSetMethod(true);\n                if (setMethod == null)\n                    return false;\n                generator.EmitMethod(setMethod);\n                break;\n            }\n            case FieldInfo field:\n                generator.Emit(field.IsStatic ? OpCodes.Stsfld : OpCodes.Stfld, field);\n                break;\n        }\n\n        return true;\n    }\n\n    private static bool EmitMemberAccess(this MemberInfo member, ILGenerator generator)\n    {\n        switch (member)\n        {\n            case PropertyInfo property:\n            {\n                var getMethod = property.GetGetMethod(true);\n                if (getMethod == null)\n                    return false;\n                generator.EmitMethod(getMethod);\n                break;\n            }\n            case FieldInfo field:\n                generator.Emit(field.IsStatic ? OpCodes.Ldsfld : OpCodes.Ldfld, field);\n                break;\n        }\n\n        return true;\n    }\n}"
  },
  {
    "path": "src/Expressions/Compile/Emitters/Emitter.MemberInit.cs",
    "content": "﻿using System.Linq.Expressions;\nusing System.Reflection.Emit;\n\nnamespace Stashbox.Expressions.Compile.Emitters;\n\ninternal static partial class Emitter\n{\n    private static bool TryEmit(this MemberInitExpression expression, ILGenerator generator, CompilerContext context, params ParameterExpression[] parameters)\n    {\n        if (!expression.NewExpression.TryEmit(generator, context, parameters))\n            return false;\n\n        var length = expression.Bindings.Count;\n        for (var i = 0; i < length; i++)\n        {\n            var binding = expression.Bindings[i];\n            if (binding.BindingType != MemberBindingType.Assignment)\n                return false;\n\n            generator.Emit(OpCodes.Dup);\n\n            if (!((MemberAssignment)binding).Expression.TryEmit(generator, context, parameters))\n                return false;\n\n            if (!binding.Member.EmitMemberAssign(generator))\n                return false;\n        }\n\n        return true;\n    }\n}"
  },
  {
    "path": "src/Expressions/Compile/Emitters/Emitter.New.cs",
    "content": "﻿using System.Linq.Expressions;\nusing System.Reflection.Emit;\n\nnamespace Stashbox.Expressions.Compile.Emitters;\n\ninternal static partial class Emitter\n{\n    private static bool TryEmit(this NewExpression expression, ILGenerator generator, CompilerContext context, params ParameterExpression[] parameters)\n    {\n        if (!expression.Arguments.TryEmit(generator, context, parameters))\n            return false;\n\n        generator.Emit(OpCodes.Newobj, expression.Constructor!);\n\n        return true;\n    }\n}"
  },
  {
    "path": "src/Expressions/Compile/Emitters/Emitter.NewArrayInit.cs",
    "content": "﻿using Stashbox.Expressions.Compile.Extensions;\nusing System;\nusing System.Linq.Expressions;\nusing System.Reflection.Emit;\n\nnamespace Stashbox.Expressions.Compile.Emitters;\n\ninternal static partial class Emitter\n{\n    private static bool TryEmit(this NewArrayExpression expression, ILGenerator generator, CompilerContext context, params ParameterExpression[] parameters)\n    {\n        var type = expression.Type;\n        var itemType = type.GetEnumerableType();\n        if (itemType == null) return false;\n\n        var length = expression.Expressions.Count;\n\n        generator.EmitInteger(length);\n        generator.Emit(OpCodes.Newarr, itemType);\n\n        for (var i = 0; i < length; i++)\n        {\n            generator.Emit(OpCodes.Dup);\n            generator.EmitInteger(i);\n\n            if (!expression.Expressions[i].TryEmit(generator, context, parameters))\n                return false;\n\n            if (itemType.IsValueType)\n                generator.Emit(OpCodes.Stelem, itemType);\n            else\n                generator.Emit(OpCodes.Stelem_Ref);\n        }\n\n        return true;\n    }\n}"
  },
  {
    "path": "src/Expressions/Compile/Emitters/Emitter.Parameter.cs",
    "content": "﻿using Stashbox.Expressions.Compile.Extensions;\nusing System.Linq;\nusing System.Linq.Expressions;\nusing System.Reflection.Emit;\n\nnamespace Stashbox.Expressions.Compile.Emitters;\n\ninternal static partial class Emitter\n{\n    private static bool TryEmit(this ParameterExpression expression, ILGenerator generator, CompilerContext context, params ParameterExpression[] parameters)\n    {\n        var index = parameters.GetReferenceIndex(expression);\n        if (index != -1)\n        {\n            if (context is { HasClosure: true, HasCapturedVariablesArgument: true })\n                index += 2;\n            else if (context.HasClosure || context.HasCapturedVariablesArgument)\n                index++;\n\n            if (context is { IsNestedLambda: false, HasCapturedVariablesArgument: true })\n                index--;\n\n            generator.LoadParameter(index);\n            return true;\n        }\n\n        var definedVariableIndex = context.DefinedVariables.IndexOf(expression);\n        if (definedVariableIndex != -1 && context.LocalBuilders != null)\n        {\n            generator.Emit(OpCodes.Ldloc, context.LocalBuilders[definedVariableIndex]);\n            return true;\n        }\n\n        var capturedVariableIndex = context.CapturedArguments.IndexOf(expression);\n        if (capturedVariableIndex == -1) return true;\n\n        generator.Emit(OpCodes.Ldarg_1);\n        generator.EmitInteger(capturedVariableIndex);\n        generator.Emit(OpCodes.Ldelem_Ref);\n        if (expression.Type.IsValueType)\n            generator.Emit(OpCodes.Unbox_Any, expression.Type);\n        return true;\n    }\n}"
  },
  {
    "path": "src/Expressions/Compile/Emitters/Emitter.cs",
    "content": "﻿using Stashbox.Expressions.Compile.Extensions;\nusing Stashbox.Utils.Data;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq.Expressions;\nusing System.Reflection.Emit;\nusing Stashbox.Utils;\n\nnamespace Stashbox.Expressions.Compile.Emitters;\n\ninternal static partial class Emitter\n{\n    public static bool TryEmit(this Expression expression, ILGenerator generator, CompilerContext context, params ParameterExpression[] parameters)\n    {\n        return expression.NodeType switch\n        {\n            ExpressionType.Call => ((MethodCallExpression)expression).TryEmit(generator, context, parameters),\n            ExpressionType.MemberAccess => ((MemberExpression)expression).TryEmit(generator, context, parameters),\n            ExpressionType.Invoke => ((InvocationExpression)expression).TryEmit(generator, context, parameters),\n            ExpressionType.Parameter => ((ParameterExpression)expression).TryEmit(generator, context, parameters),\n            ExpressionType.Lambda => ((LambdaExpression)expression).TryEmit(generator, context),\n            ExpressionType.Convert => ((UnaryExpression)expression).TryEmit(generator, context, parameters),\n            ExpressionType.Constant => ((ConstantExpression)expression).TryEmit(generator, context),\n            ExpressionType.MemberInit => ((MemberInitExpression)expression).TryEmit(generator, context, parameters),\n            ExpressionType.New => ((NewExpression)expression).TryEmit(generator, context, parameters),\n            ExpressionType.Block => ((BlockExpression)expression).Expressions.TryEmit(generator, context, parameters),\n            ExpressionType.NewArrayInit => ((NewArrayExpression)expression).TryEmit(generator, context, parameters),\n            ExpressionType.Assign => ((BinaryExpression)expression).TryEmit(generator, context, parameters),\n            ExpressionType.Default => ((DefaultExpression)expression).TryEmit(generator),\n            _ => false\n        };\n    }\n\n    public static DynamicMethod CreateDynamicMethod(CompilerContext context, Type returnType, params ParameterExpression[] parameters)\n    {\n        return !context.HasClosure\n            ? new DynamicMethod(string.Empty, returnType, parameters.GetTypes(), TypeCache.ExpressionEmitterType, true)\n            : new DynamicMethod(string.Empty, returnType, TypeCache<Closure>.Type.Append(parameters.GetTypes()), TypeCache<Closure>.Type, true);\n    }\n\n    private static bool TryEmit(this IList<Expression> expressions, ILGenerator generator, CompilerContext context, params ParameterExpression[] parameters)\n    {\n        var length = expressions.Count;\n        for (var i = 0; i < length; i++)\n            if (!expressions[i].TryEmit(generator, context, parameters))\n                return false;\n\n        return true;\n    }\n\n    internal static LocalBuilder[] BuildLocals(this ExpandableArray<Expression> variables, ILGenerator ilGenerator)\n    {\n        var length = variables.Length;\n        var locals = new LocalBuilder[length];\n        for (var i = 0; i < length; i++)\n            locals[i] = ilGenerator.DeclareLocal(variables[i].Type);\n\n        return locals;\n    }\n}"
  },
  {
    "path": "src/Expressions/Compile/ExpressionEmitter.cs",
    "content": "﻿using Stashbox.Expressions.Compile.Emitters;\nusing Stashbox.Expressions.Compile.Extensions;\nusing System;\nusing System.Linq;\nusing System.Linq.Expressions;\nusing System.Reflection.Emit;\n\nnamespace Stashbox.Expressions.Compile;\n\ninternal static class ExpressionEmitter\n{\n    public static bool TryEmit(this LambdaExpression expression, out Delegate? resultDelegate) =>\n        TryEmit(expression.Body, out resultDelegate, expression.Type, expression.ReturnType,\n            expression.Parameters.ToArray());\n\n    public static bool TryEmit(this Expression expression, out Delegate? resultDelegate, Type delegateType,\n        Type returnType, params ParameterExpression[] parameters)\n    {\n        resultDelegate = null;\n\n        var analyzer = new TreeAnalyzer();\n        if (!analyzer.Analyze(expression, parameters))\n            return false;\n\n        var storedObjects = analyzer.Constants.AsArray();\n\n        if (analyzer.NestedLambdas.Length > 0)\n            storedObjects = storedObjects.Append(new object[analyzer.NestedLambdas.Length]);\n\n        var closure = storedObjects.Length == 0\n            ? null\n            : new Closure(storedObjects);\n\n        var context = new CompilerContext(closure,\n            analyzer.Constants,\n            analyzer.DefinedVariables,\n            analyzer.CapturedParameters,\n            analyzer.NestedLambdas);\n\n        var method = Emitter.CreateDynamicMethod(context, returnType, parameters);\n        var generator = method.GetILGenerator();\n\n        if (context.HasCapturedVariablesArgument)\n        {\n            context.CapturedArgumentsHolderVariable = generator.PrepareCapturedArgumentsHolderVariable(analyzer.CapturedParameters.Length);\n            generator.CopyParametersToCapturedArgumentsIfAny(context, parameters);\n        }\n\n        if (analyzer.DefinedVariables.Length > 0)\n            context.LocalBuilders = analyzer.DefinedVariables.BuildLocals(generator);\n\n        if (!expression.TryEmit(generator, context, parameters))\n            return false;\n\n        generator.Emit(OpCodes.Ret);\n\n        resultDelegate = context.HasClosure\n            ? method.CreateDelegate(delegateType, context.Target)\n            : method.CreateDelegate(delegateType);\n\n        return true;\n    }\n}"
  },
  {
    "path": "src/Expressions/Compile/Extensions/CollectionExtensions.cs",
    "content": "﻿using Stashbox.Utils;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq.Expressions;\n\nnamespace Stashbox.Expressions.Compile.Extensions;\n\ninternal static class CollectionExtensions\n{\n    public static Type[] GetTypes(this IList<ParameterExpression> parameters)\n    {\n        var count = parameters.Count;\n        switch (count)\n        {\n            case 0:\n                return TypeCache.EmptyTypes;\n            case 1:\n                return [parameters[0].Type];\n        }\n\n        var types = new Type[count];\n        for (var i = 0; i < count; i++)\n            types[i] = parameters[i].Type;\n        return types;\n    }\n\n    public static Type[] Append(this Type type, Type[] types)\n    {\n        var count = types.Length;\n        if (count == 0)\n            return [type];\n\n        var arr = new Type[count + 1];\n        arr[0] = type;\n        Array.Copy(types, 0, arr, 1, count);\n        return arr;\n    }\n\n    public static Type[] Append(this Type[] types, Type type)\n    {\n        var count = types.Length;\n        if (count == 0)\n            return [type];\n\n        var arr = new Type[count + 1];\n        Array.Copy(types, 0, arr, 0, count);\n        arr[count] = type;\n        return arr;\n    }\n\n    public static TItem[] Append<TItem>(this TItem[] types, TItem[] others)\n    {\n        if (others.Length == 0)\n            return types;\n\n        if (types.Length == 0)\n            return others;\n\n        var length = others.Length + types.Length;\n        var arr = new TItem[length];\n        Array.Copy(types, 0, arr, 0, types.Length);\n        Array.Copy(others, 0, arr, types.Length, others.Length);\n        return arr;\n    }\n}"
  },
  {
    "path": "src/Expressions/Compile/Extensions/ILGeneratorExtensions.cs",
    "content": "﻿using System;\nusing System.Linq;\nusing System.Linq.Expressions;\nusing System.Reflection;\nusing System.Reflection.Emit;\nusing Stashbox.Utils;\n\nnamespace Stashbox.Expressions.Compile.Extensions;\n\ninternal static class ILGeneratorExtensions\n{\n    public static LocalBuilder PrepareCapturedArgumentsHolderVariable(this ILGenerator generator, int capturedArgumentsCount)\n    {\n        var local = generator.DeclareLocal(TypeCache<object[]>.Type);\n        generator.EmitInteger(capturedArgumentsCount);\n        generator.Emit(OpCodes.Newarr, TypeCache<object>.Type);\n        generator.Emit(OpCodes.Stloc, local);\n\n        return local;\n    }\n\n    public static void CopyParametersToCapturedArgumentsIfAny(this ILGenerator generator, CompilerContext context, Expression[] parameters)\n    {\n        var length = context.CapturedArguments.Length;\n        for (var i = 0; i < length; i++)\n        {\n            var arg = context.CapturedArguments[i];\n            var paramIndex = parameters.GetReferenceIndex(arg);\n            if (paramIndex == -1) continue;\n\n            generator.LoadCapturedArgumentHolder(context);\n            generator.EmitInteger(i);\n            generator.LoadParameter(paramIndex + (context.IsNestedLambda ? 2 : 1));\n            if (arg.Type.IsValueType)\n                generator.Emit(OpCodes.Box, arg.Type);\n            generator.Emit(OpCodes.Stelem_Ref);\n        }\n    }\n\n    public static bool EmitMethod(this ILGenerator generator, MethodInfo info)\n    {\n        generator.Emit(info.IsVirtual ? OpCodes.Callvirt : OpCodes.Call, info);\n        return true;\n    }\n\n    public static void LoadCapturedArgumentHolder(this ILGenerator generator, CompilerContext context)\n    {\n        if (context is { IsNestedLambda: false, CapturedArgumentsHolderVariable: { } })\n            generator.Emit(OpCodes.Ldloc, context.CapturedArgumentsHolderVariable);\n        else\n            generator.Emit(context.HasClosure ? OpCodes.Ldarg_1 : OpCodes.Ldarg_0);\n    }\n\n    public static void EmitInteger(this ILGenerator generator, int intValue)\n    {\n        switch (intValue)\n        {\n            case 0: generator.Emit(OpCodes.Ldc_I4_0); break;\n            case 1: generator.Emit(OpCodes.Ldc_I4_1); break;\n            case 2: generator.Emit(OpCodes.Ldc_I4_2); break;\n            case 3: generator.Emit(OpCodes.Ldc_I4_3); break;\n            case 4: generator.Emit(OpCodes.Ldc_I4_4); break;\n            case 5: generator.Emit(OpCodes.Ldc_I4_5); break;\n            case 6: generator.Emit(OpCodes.Ldc_I4_6); break;\n            case 7: generator.Emit(OpCodes.Ldc_I4_7); break;\n            case 8: generator.Emit(OpCodes.Ldc_I4_8); break;\n            default:\n                if (intValue is >= sbyte.MinValue and <= sbyte.MaxValue)\n                    generator.Emit(OpCodes.Ldc_I4_S, (sbyte)intValue);\n                else\n                    generator.Emit(OpCodes.Ldc_I4, intValue);\n                break;\n        }\n    }\n\n    public static void LoadParameter(this ILGenerator generator, int index)\n    {\n        switch (index)\n        {\n            case 0: generator.Emit(OpCodes.Ldarg_0); break;\n            case 1: generator.Emit(OpCodes.Ldarg_1); break;\n            case 2: generator.Emit(OpCodes.Ldarg_2); break;\n            case 3: generator.Emit(OpCodes.Ldarg_3); break;\n            default:\n                if (index <= byte.MaxValue)\n                    generator.Emit(OpCodes.Ldarg_S, (byte)index);\n                else\n                    generator.Emit(OpCodes.Ldarg, index);\n                break;\n        }\n    }\n\n    public static void InitValueType(this ILGenerator generator, Type type)\n    {\n        var lb = generator.DeclareLocal(type);\n        generator.Emit(OpCodes.Ldloca, lb);\n        generator.Emit(OpCodes.Initobj, type);\n        generator.Emit(OpCodes.Ldloc, lb);\n    }\n\n    public static bool TryEmitNumberConstant(this ILGenerator generator, Type type, object value)\n    {\n        if (type == TypeCache<int>.Type)\n            generator.EmitInteger((int)value);\n        else if (type == TypeCache<uint>.Type)\n            unchecked\n            {\n                generator.EmitInteger((int)(uint)value);\n            }\n        else if (type == TypeCache<char>.Type)\n            generator.EmitInteger((char)value);\n        else if (type == TypeCache<short>.Type)\n            generator.EmitInteger((short)value);\n        else if (type == TypeCache<byte>.Type)\n            generator.EmitInteger((byte)value);\n        else if (type == TypeCache<ushort>.Type)\n            generator.EmitInteger((ushort)value);\n        else if (type == TypeCache<sbyte>.Type)\n            generator.EmitInteger((sbyte)value);\n        else if (type == TypeCache<long>.Type)\n            generator.Emit(OpCodes.Ldc_I8, (long)value);\n        else if (type == TypeCache<ulong>.Type)\n            unchecked\n            {\n                generator.Emit(OpCodes.Ldc_I8, (long)(ulong)value);\n            }\n        else if (type == TypeCache<float>.Type)\n            generator.Emit(OpCodes.Ldc_R4, (float)value);\n        else if (type == TypeCache<bool>.Type)\n            generator.Emit((bool)value ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);\n        else if (type == TypeCache<double>.Type)\n            generator.Emit(OpCodes.Ldc_R8, (double)value);\n        else\n            return false;\n\n        return true;\n    }\n}"
  },
  {
    "path": "src/Expressions/Compile/NestedLambda.cs",
    "content": "﻿using Stashbox.Utils.Data;\nusing System.Linq.Expressions;\n\nnamespace Stashbox.Expressions.Compile;\n\ninternal class NestedLambda\n{\n    public readonly ExpandableArray<Expression> ParameterExpressions;\n    public readonly bool UsesCapturedArgument;\n\n    public NestedLambda(ExpandableArray<Expression> parameterExpressions, bool usesCapturedArgument)\n    {\n        this.ParameterExpressions = parameterExpressions;\n        this.UsesCapturedArgument = usesCapturedArgument;\n    }\n}"
  },
  {
    "path": "src/Expressions/Compile/TreeAnalyzer.cs",
    "content": "﻿using Stashbox.Utils.Data;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Linq.Expressions;\n\nnamespace Stashbox.Expressions.Compile;\n\ninternal class TreeAnalyzer\n{\n    private readonly bool isNestedLambda;\n\n    public readonly ExpandableArray<Expression> CapturedParameters;\n\n    public readonly ExpandableArray<Expression> DefinedVariables;\n\n    public readonly ExpandableArray<LambdaExpression, NestedLambda> NestedLambdas;\n\n    public readonly ExpandableArray<object> Constants;\n\n    public TreeAnalyzer()\n    {\n        this.CapturedParameters = [];\n        this.DefinedVariables = [];\n        this.NestedLambdas = [];\n        this.Constants = [];\n    }\n\n    private TreeAnalyzer(bool isNestedLambda,\n        ExpandableArray<Expression> capturedParameters,\n        ExpandableArray<Expression> definedVariables,\n        ExpandableArray<LambdaExpression, NestedLambda> nestedLambdas,\n        ExpandableArray<object> constants)\n    {\n        this.isNestedLambda = isNestedLambda;\n        CapturedParameters = capturedParameters;\n        DefinedVariables = definedVariables;\n        NestedLambdas = nestedLambdas;\n        Constants = constants;\n    }\n\n    public bool Analyze(Expression expression, params ParameterExpression[] parameters)\n    {\n        switch (expression.NodeType)\n        {\n            case ExpressionType.Parameter:\n\n                if (parameters.ContainsReference(expression) || this.DefinedVariables.IndexOf(expression) != -1) return true;\n                if (!this.isNestedLambda) return false;\n\n                this.CapturedParameters.AddOrKeep((ParameterExpression)expression);\n                return true;\n\n            case ExpressionType.Lambda:\n                var lambda = (LambdaExpression)expression;\n\n                var analyzer = this.Clone(true);\n                if (!analyzer.Analyze(lambda.Body, lambda.Parameters.CastToArray()))\n                    return false;\n\n                this.NestedLambdas.AddOrKeep(lambda, new NestedLambda(analyzer.DefinedVariables,\n                    analyzer.CapturedParameters.Length > 0));\n                return true;\n\n            case ExpressionType.MemberAccess when expression is MemberExpression memberExpression && memberExpression.Expression != null:\n                return this.Analyze(memberExpression.Expression, parameters);\n\n            case ExpressionType.Constant:\n                var constant = (ConstantExpression)expression;\n                if (constant.Value == null || Utils.IsInPlaceEmittableConstant(constant.Type, constant.Value)) return true;\n                this.Constants.AddOrKeep(constant.Value);\n                return true;\n\n            case ExpressionType.New:\n                return this.Analyze(((NewExpression)expression).Arguments, parameters);\n\n            case ExpressionType.MemberInit:\n                var memberInit = (MemberInitExpression)expression;\n                return this.Analyze(memberInit.NewExpression, parameters) &&\n                       this.Analyze(memberInit.Bindings, parameters);\n\n            case ExpressionType.Block:\n                var block = (BlockExpression)expression;\n                var blockVarLength = block.Variables.Count;\n                for (var i = 0; i < blockVarLength; i++)\n                    this.DefinedVariables.AddOrKeep(block.Variables[i]);\n\n                return this.Analyze(block.Expressions, parameters);\n\n            case ExpressionType.Conditional:\n                var condition = (ConditionalExpression)expression;\n                return this.Analyze(condition.Test, parameters) &&\n                       this.Analyze(condition.IfTrue, parameters) &&\n                       this.Analyze(condition.IfFalse, parameters);\n\n            case ExpressionType.Default:\n                return true;\n            case ExpressionType.Call:\n                var call = (MethodCallExpression)expression;\n                return (call.Object == null || this.Analyze(call.Object, parameters)) &&\n                       this.Analyze(call.Arguments, parameters);\n            case ExpressionType.Invoke:\n                var invoke = (InvocationExpression)expression;\n                return this.Analyze(invoke.Expression, parameters) &&\n                       this.Analyze(invoke.Arguments, parameters);\n            case ExpressionType.NewArrayInit:\n                return this.Analyze(((NewArrayExpression)expression).Expressions, parameters);\n            default:\n                switch (expression)\n                {\n                    case UnaryExpression unaryExpression:\n                        return this.Analyze(unaryExpression.Operand, parameters);\n                    case BinaryExpression binaryExpression:\n                        return this.Analyze(binaryExpression.Left, parameters) &&\n                               this.Analyze(binaryExpression.Right, parameters);\n                }\n\n                break;\n        }\n\n        return false;\n    }\n\n    private TreeAnalyzer Clone(bool isLambda = false) =>\n        new(isLambda, this.CapturedParameters, [], this.NestedLambdas, this.Constants);\n\n    private bool Analyze(IList<Expression> expressions, params ParameterExpression[] parameters)\n    {\n        var length = expressions.Count;\n        for (var i = 0; i < length; i++)\n            if (!this.Analyze(expressions[i], parameters))\n                return false;\n\n        return true;\n    }\n\n    private bool Analyze(IList<MemberBinding> bindings, params ParameterExpression[] parameters)\n    {\n        var length = bindings.Count;\n        for (var i = 0; i < length; i++)\n        {\n            var binding = bindings[i];\n            if (binding.BindingType != MemberBindingType.Assignment ||\n                !this.Analyze(((MemberAssignment)binding).Expression, parameters))\n                return false;\n        }\n\n        return true;\n    }\n}"
  },
  {
    "path": "src/Expressions/Compile/Utils.cs",
    "content": "﻿using System;\nusing System.Linq;\nusing System.Reflection;\nusing Stashbox.Utils;\n\nnamespace Stashbox.Expressions.Compile;\n\ninternal static class Utils\n{\n    public static bool IsInPlaceEmittableConstant(Type type, object value) =>\n        type.IsPrimitive ||\n        type.IsEnum ||\n        value is string or Type;\n    \n    public static Type MapDelegateType(Type[] paramTypes)\n    {\n        return paramTypes.Length switch\n        {\n            1 => typeof(Func<>).MakeGenericType(paramTypes),\n            2 => typeof(Func<,>).MakeGenericType(paramTypes),\n            3 => typeof(Func<,,>).MakeGenericType(paramTypes),\n            4 => typeof(Func<,,,>).MakeGenericType(paramTypes),\n            5 => typeof(Func<,,,,>).MakeGenericType(paramTypes),\n            6 => typeof(Func<,,,,,>).MakeGenericType(paramTypes),\n            7 => typeof(Func<,,,,,,>).MakeGenericType(paramTypes),\n            8 => typeof(Func<,,,,,,,>).MakeGenericType(paramTypes),\n            _ => throw new NotSupportedException($\"Too many func parameters {paramTypes.Length}.\")\n        };\n    }\n\n    internal static MethodInfo GetPartialApplicationMethodInfo(Type[] types) =>\n        PartialApplication.Methods[types.Length - 2].MakeGenericMethod(types);\n}\n\ninternal static class PartialApplication\n{\n    public static readonly MethodInfo[] Methods = typeof(PartialApplication)\n        .GetMethods().CastToArray();\n\n    public static Func<TR> ApplyPartial<TV, TR>(Func<TV, TR> f, TV v) => () => f(v);\n    public static Func<T1, TR> ApplyPartial<TV, T1, TR>(Func<TV, T1, TR> f, TV v) => t1 => f(v, t1);\n    public static Func<T1, T2, TR> ApplyPartial<TV, T1, T2, TR>(Func<TV, T1, T2, TR> f, TV v) => (t1, t2) => f(v, t1, t2);\n    public static Func<T1, T2, T3, TR> ApplyPartial<TV, T1, T2, T3, TR>(Func<TV, T1, T2, T3, TR> f, TV v) => (t1, t2, t3) => f(v, t1, t2, t3);\n    public static Func<T1, T2, T3, T4, TR> ApplyPartial<TV, T1, T2, T3, T4, TR>(Func<TV, T1, T2, T3, T4, TR> f, TV v) => (t1, t2, t3, t4) => f(v, t1, t2, t3, t4);\n    public static Func<T1, T2, T3, T4, T5, TR> ApplyPartial<TV, T1, T2, T3, T4, T5, TR>(Func<TV, T1, T2, T3, T4, T5, TR> f, TV v) => (t1, t2, t3, t4, t5) => f(v, t1, t2, t3, t4, t5);\n    public static Func<T1, T2, T3, T4, T5, T6, TR> ApplyPartial<TV, T1, T2, T3, T4, T5, T6, TR>(Func<TV, T1, T2, T3, T4, T5, T6, TR> f, TV v) => (t1, t2, t3, t4, t5, t6) => f(v, t1, t2, t3, t4, t5, t6);\n}"
  },
  {
    "path": "src/Expressions/ExpressionBuilder.Default.cs",
    "content": "﻿using Stashbox.Exceptions;\nusing Stashbox.Registration;\nusing Stashbox.Resolution;\nusing Stashbox.Utils;\nusing System.Collections.Generic;\nusing System.Linq.Expressions;\n\nnamespace Stashbox.Expressions;\n\ninternal static partial class ExpressionBuilder\n{\n    private static Expression? GetExpressionForDefault(ServiceRegistration serviceRegistration, ResolutionContext resolutionContext, TypeInformation typeInformation)\n    {\n        if (resolutionContext.CircularDependencyBarrier.Contains(serviceRegistration.RegistrationId))\n            throw ResolutionFailedException.CreateWithDesiredExceptionType(serviceRegistration.ImplementationType, serviceRegistration.Name, \n                $\"Circular dependency was detected while resolving '{serviceRegistration.ImplementationType.FullName}'.\",\n                externalExceptionType: resolutionContext.CurrentContainerContext.ContainerConfiguration.ExternalResolutionFailedExceptionType);\n\n        resolutionContext.CircularDependencyBarrier.Add(serviceRegistration.RegistrationId);\n        var result = PrepareDefaultExpression(serviceRegistration, resolutionContext, typeInformation);\n        resolutionContext.CircularDependencyBarrier.Pop();\n        return result;\n    }\n\n    private static Expression? PrepareDefaultExpression(ServiceRegistration serviceRegistration, ResolutionContext resolutionContext, TypeInformation typeInformation)\n    {\n        var definedScopeName = serviceRegistration.Options.GetOrDefault(RegistrationOption.DefinedScopeName);\n        if (definedScopeName != null)\n        {\n            var variable = TypeCache<IResolutionScope>.Type.AsVariable();\n\n            var newScope = resolutionContext.CurrentScopeParameter\n                .CallMethod(Constants.BeginScopeMethod,\n                    definedScopeName.AsConstant(),\n                    true.AsConstant());\n\n            var newScopeContext = resolutionContext.BeginNewScopeContext(new ReadOnlyKeyValue<object, ParameterExpression>(definedScopeName, variable));\n\n            resolutionContext.AddDefinedVariable(variable);\n            resolutionContext.AddInstruction(variable.AssignTo(newScope.ConvertTo(TypeCache<IResolutionScope>.Type)));\n\n            var expression = ExpressionFactory.ConstructExpression(serviceRegistration, newScopeContext, typeInformation);\n\n            foreach (var definedVariable in newScopeContext.DefinedVariables.Walk())\n                resolutionContext.AddDefinedVariable(definedVariable);\n\n            foreach (var instruction in newScopeContext.SingleInstructions)\n                resolutionContext.AddInstruction(instruction);\n\n            return expression;\n        }\n\n        return ExpressionFactory.ConstructExpression(serviceRegistration, resolutionContext, typeInformation);\n    }\n}"
  },
  {
    "path": "src/Expressions/ExpressionBuilder.Factory.cs",
    "content": "﻿using Stashbox.Exceptions;\nusing Stashbox.Registration;\nusing Stashbox.Resolution;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq.Expressions;\nusing Stashbox.Utils;\n\nnamespace Stashbox.Expressions;\n\ninternal static partial class ExpressionBuilder\n{\n    private static Expression GetExpressionForFactory(ServiceRegistration serviceRegistration, FactoryOptions factoryOptions, ResolutionContext resolutionContext, TypeInformation typeInformation)\n    {\n        if (resolutionContext.CircularDependencyBarrier.Contains(serviceRegistration.RegistrationId))\n            throw ResolutionFailedException.CreateWithDesiredExceptionType(serviceRegistration.ImplementationType, serviceRegistration.Name, \n                $\"Circular dependency was detected while resolving '{serviceRegistration.ImplementationType.FullName}'.\",\n                externalExceptionType: resolutionContext.CurrentContainerContext.ContainerConfiguration.ExternalResolutionFailedExceptionType);\n\n        resolutionContext.CircularDependencyBarrier.Add(serviceRegistration.RegistrationId);\n\n        var parameters = GetFactoryParameters(factoryOptions, resolutionContext, typeInformation);\n        var expression = ConstructFactoryExpression(factoryOptions, parameters);\n        var result = ExpressionFactory.ConstructBuildUpExpression(serviceRegistration, resolutionContext, expression, typeInformation);\n\n        resolutionContext.CircularDependencyBarrier.Pop();\n        return result;\n    }\n\n    private static Expression ConstructFactoryExpression(FactoryOptions factoryOptions, IEnumerable<Expression> parameters)\n    {\n        if (factoryOptions.IsFactoryDelegateACompiledLambda || factoryOptions.Factory.IsCompiledLambda())\n            return factoryOptions.Factory.InvokeDelegate(parameters);\n\n        var method = factoryOptions.Factory.GetMethod();\n        return method.IsStatic\n            ? method.CallStaticMethod(parameters)\n            : method.CallMethod(factoryOptions.Factory.Target.AsConstant(), parameters);\n    }\n\n    private static IEnumerable<Expression> GetFactoryParameters(FactoryOptions factoryOptions, ResolutionContext resolutionContext, TypeInformation typeInformation)\n    {\n        var length = factoryOptions.FactoryParameters.Length;\n        for (var i = 0; i < length - 1; i++)\n        {\n            var type = factoryOptions.FactoryParameters[i];\n            if (type == TypeCache<TypeInformation>.Type)\n            {\n                yield return typeInformation.AsConstant();\n            }\n            else\n            {\n                var typeInfo = new TypeInformation(factoryOptions.FactoryParameters[i], null);\n                yield return resolutionContext.CurrentContainerContext.ResolutionStrategy.BuildExpressionForType(resolutionContext, typeInfo).ServiceExpression;\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Expressions/ExpressionBuilder.Func.cs",
    "content": "﻿using Stashbox.Registration;\nusing Stashbox.Resolution;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Linq.Expressions;\nusing System.Reflection;\n\nnamespace Stashbox.Expressions;\n\ninternal static partial class ExpressionBuilder\n{\n    private static Expression GetExpressionForFunc(ServiceRegistration serviceRegistration, Delegate func, ResolutionContext resolutionContext)\n    {\n        var internalMethodInfo = func.GetMethod();\n\n        var parameters = GetFuncParametersWithScope(serviceRegistration.ImplementationType.GetMethod(\"Invoke\")!.GetParameters(), resolutionContext);\n        if (func.IsCompiledLambda())\n            return func.InvokeDelegate(parameters)\n                .AsLambda(parameters.Take(parameters.Length - 1).Cast<ParameterExpression>());\n\n        var expr = internalMethodInfo.IsStatic\n            ? internalMethodInfo.CallStaticMethod(parameters)\n            : func.Target.AsConstant().CallMethod(internalMethodInfo, parameters);\n\n        return expr.AsLambda(parameters.Take(parameters.Length - 1).Cast<ParameterExpression>());\n    }\n\n    private static Expression[] GetFuncParametersWithScope(IList<ParameterInfo> parameterInfos, ResolutionContext resolutionContext)\n    {\n        var length = parameterInfos.Count;\n        var expressions = new Expression[length + 1];\n\n        for (var i = 0; i < length; i++)\n        {\n            expressions[i] = parameterInfos[i].ParameterType.AsParameter();\n        }\n#if NET5_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER\n        expressions[^1] = resolutionContext.CurrentScopeParameter;\n#else\n        expressions[expressions.Length - 1] = resolutionContext.CurrentScopeParameter;\n#endif\n        return expressions;\n    }\n}"
  },
  {
    "path": "src/Expressions/ExpressionBuilder.cs",
    "content": "﻿using Stashbox.Lifetime;\nusing Stashbox.Registration;\nusing Stashbox.Resolution;\nusing Stashbox.Utils;\nusing System;\nusing System.Linq.Expressions;\nusing System.Collections.Generic;\n\nnamespace Stashbox.Expressions;\n\ninternal static partial class ExpressionBuilder\n{\n    internal static Expression? BuildExpressionForRegistration(ServiceRegistration serviceRegistration,\n        ResolutionContext resolutionContext, TypeInformation typeInformation)\n    {\n        var expression = BuildExpressionByRegistrationType(serviceRegistration, resolutionContext, typeInformation);\n        if (expression == null)\n            return null;\n\n        if (serviceRegistration.Options != null && !serviceRegistration.IsInstance())\n        {\n            if (serviceRegistration.Options.TryGetValue(RegistrationOption.AsyncInitializer, out var asyncInitializer))\n                expression = resolutionContext.CurrentScopeParameter.CallMethod(Constants.AddWithAsyncInitializerMethod, expression,\n                    asyncInitializer.AsConstant());\n\n            if (serviceRegistration.Options.TryGetValue(RegistrationOption.Finalizer, out var finalizer))\n                expression = resolutionContext.CurrentScopeParameter.CallMethod(Constants.AddWithFinalizerMethod, expression,\n                    finalizer.AsConstant());\n        }\n\n        if (!ShouldHandleDisposal(resolutionContext.CurrentContainerContext, serviceRegistration) || !expression.Type.IsDisposable())\n            return expression;\n\n        return resolutionContext.RequestConfiguration.RequiresRequestContext\n            ? resolutionContext.CurrentScopeParameter.CallMethod(Constants.AddRequestContextAwareDisposalMethod,\n                expression, resolutionContext.RequestContextParameter)\n            : resolutionContext.CurrentScopeParameter.CallMethod(Constants.AddDisposalMethod, expression);\n    }\n\n    private static Expression? BuildExpressionByRegistrationType(ServiceRegistration serviceRegistration, ResolutionContext resolutionContext, TypeInformation typeInformation)\n    {\n        resolutionContext = resolutionContext.FallBackToRequestInitiatorIfNeeded();\n\n        var options = serviceRegistration.Options?.GetOrDefault(RegistrationOption.RegistrationTypeOptions);\n\n        return options switch\n        {\n            FactoryOptions factoryOptions => GetExpressionForFactory(serviceRegistration, factoryOptions, resolutionContext, typeInformation),\n            InstanceOptions instanceRegistration => instanceRegistration.IsWireUp\n                ? ExpressionFactory.ConstructBuildUpExpression(serviceRegistration,\n                    resolutionContext, instanceRegistration.ExistingInstance.AsConstant(),\n                    typeInformation)\n                : instanceRegistration.ExistingInstance.AsConstant(),\n            Delegate func => GetExpressionForFunc(serviceRegistration, func, resolutionContext),\n            _ => GetExpressionForDefault(serviceRegistration, resolutionContext, typeInformation)\n        };\n    }\n\n    private static bool ShouldHandleDisposal(IContainerContext containerContext, ServiceRegistration serviceRegistration)\n    {\n        if (serviceRegistration.Options.IsOn(RegistrationOption.IsLifetimeExternallyOwned) ||\n            serviceRegistration.IsInstance())\n            return false;\n\n        return containerContext.ContainerConfiguration.TrackTransientsForDisposalEnabled ||\n               serviceRegistration.Lifetime is not TransientLifetime;\n    }\n}"
  },
  {
    "path": "src/Expressions/ExpressionFactory.Member.cs",
    "content": "﻿using Stashbox.Exceptions;\nusing Stashbox.Registration;\nusing Stashbox.Resolution;\nusing Stashbox.Resolution.Extensions;\nusing Stashbox.Utils.Data;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Linq.Expressions;\nusing System.Reflection;\n\nnamespace Stashbox.Expressions;\n\ninternal static partial class ExpressionFactory\n{\n    private static IEnumerable<Expression> GetMemberExpressions(\n        IEnumerable<MemberInfo> members,\n        ServiceRegistration? serviceRegistration,\n        ResolutionContext resolutionContext,\n        Expression instance,\n        TypeInformation typeInformation) =>\n        from member in members\n        let expression = GetMemberExpression(member, serviceRegistration, resolutionContext, typeInformation)\n        where expression != null\n        select instance.Member(member).AssignTo(expression);\n\n    private static IEnumerable<MemberBinding> GetMemberBindings(\n        IEnumerable<MemberInfo> members,\n        ServiceRegistration? serviceRegistration,\n        ResolutionContext resolutionContext,\n        TypeInformation typeInformation) =>\n        from member in members\n        let expression = GetMemberExpression(member, serviceRegistration, resolutionContext, typeInformation)\n        where expression != null\n        select member.AssignTo(expression);\n\n\n    private static Expression GetMemberExpression(\n        MemberInfo member,\n        ServiceRegistration? serviceRegistration,\n        ResolutionContext resolutionContext,\n        TypeInformation typeInformation)\n    {\n        var memberTypeInfo = member.AsTypeInformation(serviceRegistration, typeInformation,\n            resolutionContext.CurrentContainerContext.ContainerConfiguration);\n\n        var injectionParameter = serviceRegistration?.Options.GetOrDefault<ExpandableArray<KeyValuePair<string, object?>>>(RegistrationOption.InjectionParameters)?.SelectInjectionParameterOrDefault(memberTypeInfo);\n        if (injectionParameter != null) return injectionParameter;\n\n        var serviceContext = resolutionContext.CurrentContainerContext\n            .ResolutionStrategy.BuildExpressionForType(resolutionContext, memberTypeInfo);\n\n        if (!serviceContext.IsEmpty() || resolutionContext.NullResultAllowed) return serviceContext.ServiceExpression;\n\n        var memberType = member is PropertyInfo ? \"property\" : \"field\";\n        throw ResolutionFailedException.CreateWithDesiredExceptionType(memberTypeInfo.ParentType, null,\n            $\"Unresolvable {memberType}: ({memberTypeInfo.Type.FullName}){memberTypeInfo.ParameterOrMemberName}{(memberTypeInfo.DependencyName != null ? $\" with name '{memberTypeInfo.DependencyName}'\" : string.Empty)}.\",\n            externalExceptionType: resolutionContext.CurrentContainerContext.ContainerConfiguration.ExternalResolutionFailedExceptionType);\n    }\n}"
  },
  {
    "path": "src/Expressions/ExpressionFactory.Method.cs",
    "content": "﻿using Stashbox.Exceptions;\nusing Stashbox.Registration;\nusing Stashbox.Resolution;\nusing Stashbox.Resolution.Extensions;\nusing Stashbox.Utils;\nusing Stashbox.Utils.Data;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Linq.Expressions;\nusing System.Reflection;\nusing System.Text;\n\nnamespace Stashbox.Expressions;\n\ninternal static partial class ExpressionFactory\n{\n    private static IEnumerable<Expression> CreateParameterExpressionsForMethod(\n        ServiceRegistration? serviceRegistration,\n        ResolutionContext resolutionContext,\n        MethodBase method,\n        TypeInformation typeInformation)\n    {\n        var parameters = method.GetParameters();\n        var paramLength = parameters.Length;\n        for (var i = 0; i < paramLength; i++)\n        {\n            var parameter = parameters[i].AsTypeInformation(method.DeclaringType, typeInformation, serviceRegistration,\n                resolutionContext.CurrentContainerContext.ContainerConfiguration);\n\n            var injectionParameter = serviceRegistration?.Options.GetOrDefault<ExpandableArray<KeyValuePair<string, object?>>>(RegistrationOption.InjectionParameters)?.SelectInjectionParameterOrDefault(parameter);\n            if (injectionParameter != null) yield return injectionParameter;\n\n            yield return resolutionContext.CurrentContainerContext.ResolutionStrategy.BuildExpressionForType(\n                resolutionContext, parameter).ServiceExpression ?? throw ResolutionFailedException.CreateWithDesiredExceptionType(method.DeclaringType, serviceRegistration?.Name,\n                $\"Method {method} found with unresolvable parameter: ({parameter.Type}){parameter.ParameterOrMemberName}\",\n                externalExceptionType: resolutionContext.CurrentContainerContext.ContainerConfiguration.ExternalResolutionFailedExceptionType);\n        }\n    }\n\n    private static ConstructorInfo? SelectConstructor(\n        Type typeToConstruct,\n        ServiceRegistration? serviceRegistration,\n        TypeInformation typeInformation,\n        ResolutionContext resolutionContext,\n        IEnumerable<ConstructorInfo> constructorsEnumerable,\n        out Expression[] parameterExpressions)\n    {\n        ConstructorInfo[]? resultConstructors;\n        parameterExpressions = TypeCache.EmptyArray<Expression>();\n        if (resolutionContext.ParameterExpressions.Length > 0)\n        {\n            var constructors = constructorsEnumerable.CastToArray();\n            var containingFactoryParameter = constructors\n                .Where(c => Array.Exists(c.GetParameters(),p => resolutionContext.ParameterExpressions\n                        .Any(pe => Array.Exists(pe, item => item.I2.Type == p.ParameterType || item.I2.Type.Implements(p.ParameterType)))))\n                .CastToArray();\n\n            var everythingElse = constructors.Except(containingFactoryParameter);\n            resultConstructors = containingFactoryParameter.Concat(everythingElse).CastToArray();\n        }\n        else\n            resultConstructors = constructorsEnumerable.CastToArray();\n\n        if (resultConstructors.Length == 0)\n            throw ResolutionFailedException.CreateWithDesiredExceptionType(typeToConstruct,\n                serviceRegistration?.Name,\n                \"No public constructor found. Make sure there is at least one public constructor on the type.\",\n                externalExceptionType: resolutionContext.CurrentContainerContext.ContainerConfiguration.ExternalResolutionFailedExceptionType);\n\n        var checkedConstructors = new Dictionary<MethodBase, TypeInformation>();\n\n        var unknownTypeCheckDisabledContext = resolutionContext.CurrentContainerContext.ContainerConfiguration.UnknownTypeResolutionEnabled\n            ? resolutionContext.BeginUnknownTypeCheckDisabledContext()\n            : resolutionContext;\n\n        var length = resultConstructors.Length;\n        for (var i = 0; i < length; i++)\n        {\n            var constructor = resultConstructors[i];\n            if (TryBuildMethod(constructor, serviceRegistration, unknownTypeCheckDisabledContext, typeInformation,\n                    out var failedParameter, out parameterExpressions)) return constructor;\n\n            checkedConstructors.Add(constructor, failedParameter);\n        }\n\n        if (resolutionContext.CurrentContainerContext.ContainerConfiguration.UnknownTypeResolutionEnabled)\n        {\n            for (var i = 0; i < length; i++)\n            {\n                var constructor = resultConstructors[i];\n                if (TryBuildMethod(constructor, serviceRegistration, resolutionContext, typeInformation, out _, out parameterExpressions))\n                    return constructor;\n            }\n        }\n\n        var mustThrowBecauseOfUnresolvableNamedDependency = resolutionContext.CurrentContainerContext.ContainerConfiguration.ForceThrowWhenNamedDependencyIsNotResolvable\n                                                            && checkedConstructors.Any(ctor => ctor.Value.DependencyName != null || ctor.Value.HasDependencyNameAttribute);\n\n        if (!mustThrowBecauseOfUnresolvableNamedDependency && resolutionContext.NullResultAllowed) return null;\n        \n        var stringBuilder = new StringBuilder();\n        foreach (var checkedConstructor in checkedConstructors)\n            stringBuilder.AppendLine($\"Constructor {checkedConstructor.Key} found with unresolvable parameter: ({checkedConstructor.Value.Type.FullName}){checkedConstructor.Value.ParameterOrMemberName}.\");\n\n        throw ResolutionFailedException.CreateWithDesiredExceptionType(typeToConstruct, serviceRegistration?.Name, stringBuilder.ToString(), externalExceptionType: resolutionContext.CurrentContainerContext.ContainerConfiguration.ExternalResolutionFailedExceptionType);\n    }\n\n    private static IEnumerable<Expression> CreateMethodExpressions(\n        IEnumerable<MethodInfo> methods,\n        ServiceRegistration? serviceRegistration,\n        ResolutionContext resolutionContext,\n        Expression instance,\n        TypeInformation typeInformation)\n    {\n        foreach (var method in methods)\n        {\n            var parameters = method.GetParameters();\n            if (parameters.Length == 0)\n                yield return instance.CallMethod(method);\n            else\n                yield return instance.CallMethod(method,\n                    CreateParameterExpressionsForMethod(\n                        serviceRegistration, resolutionContext, method, typeInformation));\n        }\n    }\n\n    private static bool TryBuildMethod(\n        MethodBase method,\n        ServiceRegistration? serviceRegistration,\n        ResolutionContext resolutionContext,\n        TypeInformation typeInformation,\n        out TypeInformation failedParameter,\n        out Expression[] parameterExpressions)\n    {\n        var parameters = method.GetParameters();\n        var paramLength = parameters.Length;\n        parameterExpressions = new Expression[paramLength];\n        failedParameter = TypeInformation.Empty;\n        for (var i = 0; i < paramLength; i++)\n        {\n            var parameter = parameters[i].AsTypeInformation(method.DeclaringType, typeInformation, serviceRegistration,\n                resolutionContext.CurrentContainerContext.ContainerConfiguration);\n\n            var injectionParameter = serviceRegistration?.Options.GetOrDefault<ExpandableArray<KeyValuePair<string, object?>>>(RegistrationOption.InjectionParameters)?.SelectInjectionParameterOrDefault(parameter);\n            if (injectionParameter != null)\n            {\n                parameterExpressions[i] = injectionParameter;\n                continue;\n            }\n\n            var serviceContext = resolutionContext.CurrentContainerContext.ResolutionStrategy\n                .BuildExpressionForType(resolutionContext, parameter);\n\n            if (!serviceContext.IsEmpty())\n            {\n                parameterExpressions[i] = serviceContext.ServiceExpression;\n                continue;\n            }\n\n            failedParameter = parameter;\n            return false;\n        }\n\n        return true;\n    }\n}"
  },
  {
    "path": "src/Expressions/ExpressionFactory.cs",
    "content": "﻿using Stashbox.Registration;\nusing Stashbox.Resolution;\nusing Stashbox.Utils.Data;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Linq.Expressions;\nusing System.Reflection;\n\nnamespace Stashbox.Expressions;\n\ninternal static partial class ExpressionFactory\n{\n    public static Expression ConstructBuildUpExpression(\n        ServiceRegistration serviceRegistration,\n        ResolutionContext resolutionContext,\n        Expression instance,\n        TypeInformation typeInformation)\n    {\n        if (instance.Type != serviceRegistration.ImplementationType)\n            instance = instance.ConvertTo(serviceRegistration.ImplementationType);\n\n        var methods = serviceRegistration.ImplementationType.GetUsableMethods();\n        var members = serviceRegistration.ImplementationType.GetUsableMembers(serviceRegistration,\n            resolutionContext.CurrentContainerContext.ContainerConfiguration);\n\n        var initializer = serviceRegistration.Options.GetOrDefault(RegistrationOption.Initializer);\n\n        if (members.Length == 0 && methods.Length == 0 &&\n            initializer == null) return instance;\n\n        var variable = instance.Type.AsVariable();\n        var assign = variable.AssignTo(instance);\n\n        var lines = new ExpandableArray<Expression> { assign };\n\n        lines.AddRange(GetMemberExpressions(members,\n            serviceRegistration, resolutionContext, variable, typeInformation));\n\n        lines.AddRange(CreateMethodExpressions(methods,\n            serviceRegistration, resolutionContext, variable, typeInformation));\n\n        if (initializer != null)\n            lines.Add(initializer.AsConstant()\n                .CallMethod(initializer.GetType().GetMethod(\"Invoke\")!,\n                    variable, resolutionContext.CurrentScopeParameter));\n\n        lines.Add(variable);\n\n        return lines.AsBlock(variable);\n    }\n\n    public static Expression ConstructBuildUpExpression(\n        ResolutionContext resolutionContext,\n        Expression instance,\n        TypeInformation typeInformation)\n    {\n        var type = instance.Type;\n\n        var methods = type.GetUsableMethods();\n        var members = type.GetUsableMembers(null,\n            resolutionContext.CurrentContainerContext.ContainerConfiguration);\n\n        if (members.Length == 0 && methods.Length == 0) return instance;\n\n        var variable = type.AsVariable();\n        var assign = variable.AssignTo(instance);\n\n        var lines = new ExpandableArray<Expression> { assign };\n\n        lines.AddRange(GetMemberExpressions(members,\n            null, resolutionContext, variable, typeInformation));\n\n        lines.AddRange(CreateMethodExpressions(methods,\n            null, resolutionContext, instance, typeInformation));\n\n        lines.Add(variable);\n\n        return lines.AsBlock(variable);\n    }\n\n    public static Expression? ConstructExpression(\n        ServiceRegistration serviceRegistration,\n        ResolutionContext resolutionContext,\n        TypeInformation typeInformation)\n    {\n        var constructors = serviceRegistration.ImplementationType.GetConstructors();\n\n        var initExpression = CreateInitExpression(\n            serviceRegistration.ImplementationType,\n            serviceRegistration,\n            typeInformation,\n            resolutionContext,\n            constructors);\n        if (initExpression == null)\n            return null;\n\n        var methods = serviceRegistration.ImplementationType.GetUsableMethods();\n        var members = serviceRegistration.ImplementationType.GetUsableMembers(serviceRegistration,\n            resolutionContext.CurrentContainerContext.ContainerConfiguration);\n\n        if (members.Length > 0)\n            initExpression = initExpression.InitMembers(GetMemberBindings(members,\n                serviceRegistration, resolutionContext, typeInformation));\n\n        var initializer = serviceRegistration.Options.GetOrDefault(RegistrationOption.Initializer);\n\n        if (methods.Length == 0 && initializer == null)\n            return initExpression;\n\n        var variable = initExpression.Type.AsVariable();\n        var assign = variable.AssignTo(initExpression);\n\n        var lines = new ExpandableArray<Expression> { assign };\n\n        lines.AddRange(CreateMethodExpressions(methods,\n            serviceRegistration, resolutionContext, variable, typeInformation));\n\n        if (initializer != null)\n            lines.Add(initializer.AsConstant()\n                .CallMethod(initializer.GetType().GetMethod(\"Invoke\")!,\n                    variable, resolutionContext.CurrentScopeParameter));\n\n        lines.Add(variable);\n\n        return lines.AsBlock(variable);\n    }\n\n    public static Expression? ConstructExpression(\n        ResolutionContext resolutionContext, TypeInformation typeInformation)\n    {\n        var methods = typeInformation.Type.GetUsableMethods();\n        var members = typeInformation.Type.GetUsableMembers(null,\n            resolutionContext.CurrentContainerContext.ContainerConfiguration);\n\n        if (SelectConstructor(\n                typeInformation.Type,\n                null,\n                typeInformation,\n                resolutionContext,\n                typeInformation.Type.GetConstructors(),\n                out var parameters)?.MakeNew(parameters) is not Expression initExpression)\n            return null;\n\n        if (members.Length > 0)\n            initExpression = initExpression.InitMembers(GetMemberBindings(members,\n                null, resolutionContext, typeInformation));\n\n        if (methods.Length == 0) return initExpression;\n\n        var variable = initExpression.Type.AsVariable();\n        var assign = variable.AssignTo(initExpression);\n\n        var lines = new ExpandableArray<Expression> { assign };\n        lines.AddRange(CreateMethodExpressions(methods, null, resolutionContext, variable, typeInformation));\n        lines.Add(variable);\n\n        return lines.AsBlock(variable);\n    }\n\n    private static Expression? CreateInitExpression(\n        Type typeToConstruct,\n        ServiceRegistration serviceRegistration,\n        TypeInformation typeInformation,\n        ResolutionContext resolutionContext,\n        IEnumerable<ConstructorInfo> constructors)\n    {\n        var rule = resolutionContext.CurrentContainerContext.ContainerConfiguration.ConstructorSelectionRule;\n        var constructorOptions = serviceRegistration.Options.GetOrDefault<ConstructorOptions>(RegistrationOption.ConstructorOptions);\n        if (constructorOptions != null)\n        {\n            if (constructorOptions.ConstructorArguments != null)\n                return constructorOptions.SelectedConstructor\n                    .MakeNew(constructorOptions.ConstructorArguments.Select(Expression.Constant));\n\n            return constructorOptions.SelectedConstructor.MakeNew(\n                CreateParameterExpressionsForMethod(\n                    serviceRegistration,\n                    resolutionContext, constructorOptions.SelectedConstructor, typeInformation));\n        }\n\n        var constructorSelectionRule = serviceRegistration.Options.GetOrDefault<Func<IEnumerable<ConstructorInfo>, IEnumerable<ConstructorInfo>>>(RegistrationOption.ConstructorSelectionRule);\n        if (constructorSelectionRule != null)\n            rule = constructorSelectionRule;\n\n        constructors = rule(constructors);\n\n        return SelectConstructor(typeToConstruct, serviceRegistration, typeInformation, resolutionContext,\n            constructors, out var parameters)?.MakeNew(parameters);\n    }\n}"
  },
  {
    "path": "src/Extensions/AssemblyExtensions.cs",
    "content": "﻿using System.Collections.Generic;\nusing System.Linq;\n\nnamespace System.Reflection;\n\ninternal static class AssemblyExtensions\n{\n    public static IEnumerable<Type> CollectTypes(this Assembly assembly) =>\n        assembly.ExportedTypes.Concat(assembly.DefinedTypes.Select(typeInfo => typeInfo.AsType())).Distinct();\n}"
  },
  {
    "path": "src/Extensions/CollectionExtensions.cs",
    "content": "﻿using Stashbox.Registration;\n\nnamespace System.Collections.Generic;\n\ninternal static class CollectionExtensions\n{\n    public static TResult? GetOrDefault<TResult>(this Dictionary<RegistrationOption, object?>? dict, RegistrationOption key)\n    {\n        if ((dict?.TryGetValue(key, out var value) ?? false) && value is TResult result)\n            return result;\n\n        return default;\n    }\n\n    public static object? GetOrDefault(this Dictionary<RegistrationOption, object?>? dict, RegistrationOption key)\n    {\n        if ((dict?.TryGetValue(key, out var value) ?? false))\n            return value;\n\n        return default;\n    }\n\n    public static bool TryGet(this Dictionary<RegistrationOption, object?>? dict, RegistrationOption key, out object? value)\n    {\n        if (dict?.TryGetValue(key, out var objValue) ?? false)\n        {\n            value = objValue;\n            return true;\n        }\n\n        value = default;\n        return false;\n    }\n\n    public static bool IsOn(this Dictionary<RegistrationOption, object?>? dict, RegistrationOption key) => (dict?.ContainsKey(key) ?? false) && dict[key] is true;\n}"
  },
  {
    "path": "src/Extensions/EnumerableExtensions.cs",
    "content": "﻿using Stashbox.Utils.Data;\nusing System.Collections.Generic;\nusing System.Linq.Expressions;\n\nnamespace System.Linq;\n\ninternal static class EnumerableExtensions\n{\n    public static TEnumerable[] CastToArray<TEnumerable>(this IEnumerable<TEnumerable> enumerable) =>\n        enumerable is TEnumerable[] array ? array : enumerable.ToArray();\n\n    public static T[] Append<T>(this T[] array, T item)\n    {\n        var count = array.Length;\n        if (count == 0)\n            return [item];\n\n        var arr = new T[count + 1];\n        Array.Copy(array, arr, count);\n        arr[count] = item;\n        return arr;\n    }\n\n    public static bool ContainsReference<TElement>(this TElement[] array, TElement element) where TElement : class =>\n        array.GetReferenceIndex(element) != -1;\n\n    public static int GetReferenceIndex<TElement>(this TElement[] array, TElement element) where TElement : class\n    {\n        if (array.Length == 0) return -1;\n\n        var length = array.Length;\n        if (length == 1) return ReferenceEquals(array[0], element) ? 0 : -1;\n\n        for (var i = 0; i < length; i++)\n            if (ReferenceEquals(array[i], element))\n                return i;\n\n        return -1;\n    }\n\n    public static TResult LastElement<TResult>(this TResult[] source) =>\n#if NET5_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER\n            source[^1];\n#else\n        source[source.Length - 1];\n#endif\n\n    public static ParameterExpression[] AsParameters(this Type[] source)\n    {\n        var length = source.Length;\n        var result = new ParameterExpression[length];\n\n        for (var i = 0; i < length; i++)\n            result[i] = source[i].AsParameter();\n\n        return result;\n    }\n\n    public static Pair<bool, ParameterExpression>[] AsParameterPairs(this ParameterExpression[] source)\n    {\n        var length = source.Length;\n        var result = new Pair<bool, ParameterExpression>[length];\n\n        for (var i = 0; i < length; i++)\n            result[i] = new Pair<bool, ParameterExpression>(false, source[i]);\n\n        return result;\n    }\n\n    public static Stashbox.Utils.Data.Stack<TItem> AsStack<TItem>(this IEnumerable<TItem> enumerable) =>\n        Stashbox.Utils.Data.Stack<TItem>.FromEnumerable(enumerable);\n}"
  },
  {
    "path": "src/Extensions/ExpressionExtensions.cs",
    "content": "﻿using Stashbox;\nusing Stashbox.Configuration;\nusing Stashbox.Expressions.Compile;\nusing Stashbox.Registration;\nusing Stashbox.Resolution;\nusing Stashbox.Utils;\nusing Stashbox.Utils.Data;\nusing System.Collections.Generic;\nusing System.Reflection;\n\nnamespace System.Linq.Expressions;\n\n/// <summary>\n/// Holds the <see cref=\"Expression\"/> extension methods.\n/// </summary>\npublic static class ExpressionExtensions\n{\n    private static Expression PostProcess(this Expression expression)\n    {\n        if (expression.NodeType == ExpressionType.Convert &&\n            expression is UnaryExpression unaryExpression &&\n            unaryExpression.Operand.Type == TypeCache<object>.Type)\n            return unaryExpression;\n\n        return expression.Type.IsValueType ? expression.ConvertTo(TypeCache<object>.Type) : expression;\n    }\n\n    /// <summary>\n    /// Compiles an <see cref=\"Expression\"/> to a <see cref=\"Func{T1, T2, TResult}\"/> of <see cref=\"IResolutionScope\"/>, <see cref=\"IRequestContext\"/>, and <see cref=\"object\"/>.\n    /// </summary>\n    /// <param name=\"expression\">The expression.</param>\n    /// <param name=\"resolutionContext\">The resolution context.</param>\n    /// <param name=\"containerConfiguration\">The container configuration.</param>\n    /// <returns>The compiled delegate.</returns>\n    public static Func<IResolutionScope, IRequestContext, object> CompileDelegate(this Expression expression,\n        ResolutionContext resolutionContext, ContainerConfiguration containerConfiguration)\n    {\n        expression = expression.PostProcess();\n        if (expression is ConstantExpression { Value: { } } constantExpression)\n        {\n            var instance = constantExpression.Value;\n            return (_, _) => instance;\n        }\n\n        if (!resolutionContext.DefinedVariables.IsEmpty)\n        {\n            resolutionContext.SingleInstructions.Add(expression);\n            expression = resolutionContext.SingleInstructions.AsBlock(resolutionContext.DefinedVariables.Walk());\n        }\n\n        if (containerConfiguration.ExternalExpressionCompiler != null)\n            return (Func<IResolutionScope, IRequestContext, object>)containerConfiguration.ExternalExpressionCompiler(\n                expression.AsLambda(resolutionContext.CurrentScopeParameter, resolutionContext.RequestContextParameter));\n\n        if (!expression.TryEmit(out var factory, TypeCache<Func<IResolutionScope, IRequestContext, object>>.Type, TypeCache<object>.Type,\n                resolutionContext.CurrentScopeParameter, resolutionContext.RequestContextParameter))\n            factory = expression.AsLambda(resolutionContext.CurrentScopeParameter, resolutionContext.RequestContextParameter).Compile();\n\n        return (Func<IResolutionScope, IRequestContext, object>)factory!;\n    }\n\n    /// <summary>\n    /// Compiles a <see cref=\"LambdaExpression\"/> to a <see cref=\"Delegate\"/>. For testing purposes.\n    /// </summary>\n    /// <param name=\"expression\">The expression.</param>\n    /// <returns>The delegate.</returns>\n    public static Delegate CompileDelegate(this LambdaExpression expression)\n    {\n        if (!expression.TryEmit(out var result))\n            throw new InvalidOperationException(\"Could not compile the given expression!\");\n\n        return result!;\n    }\n\n    /// <summary>\n    /// Compiles an <see cref=\"Expression\"/> to a <see cref=\"Func{T,R}\"/> of <see cref=\"IResolutionScope\"/>, <see cref=\"IRequestContext\"/>, and <see cref=\"Delegate\"/>.\n    /// </summary>\n    /// <param name=\"expression\">The expression.</param>\n    /// <param name=\"resolutionContext\">The resolution context.</param>\n    /// <param name=\"containerConfiguration\">The container configuration.</param>\n    /// <returns>The compiled delegate.</returns>\n    public static Func<IResolutionScope, IRequestContext, Delegate> CompileDynamicDelegate(this Expression expression,\n        ResolutionContext resolutionContext, ContainerConfiguration containerConfiguration)\n    {\n        expression = expression.PostProcess();\n        if (!resolutionContext.DefinedVariables.IsEmpty)\n        {\n            resolutionContext.SingleInstructions.Add(expression);\n            expression = resolutionContext.SingleInstructions.AsBlock(resolutionContext.DefinedVariables.Walk());\n        }\n\n        if (containerConfiguration.ExternalExpressionCompiler != null)\n            return (Func<IResolutionScope, IRequestContext, Delegate>)containerConfiguration.ExternalExpressionCompiler(\n                expression.AsLambda(resolutionContext.CurrentScopeParameter, resolutionContext.RequestContextParameter));\n\n        if (!expression.TryEmit(out var factory, TypeCache<Func<IResolutionScope, IRequestContext, Delegate>>.Type, TypeCache<Delegate>.Type,\n                resolutionContext.CurrentScopeParameter, resolutionContext.RequestContextParameter))\n            factory = expression.AsLambda<Func<IResolutionScope, IRequestContext, Delegate>>(resolutionContext.CurrentScopeParameter, resolutionContext.RequestContextParameter).Compile();\n\n        return (Func<IResolutionScope, IRequestContext, Delegate>)factory!;\n    }\n\n    /// <summary>\n    /// Creates a <see cref=\"ServiceContext\"/> from the given <see cref=\"Expression\"/>.\n    /// </summary>\n    /// <param name=\"expression\">The expression to wrap within the context.</param>\n    /// <param name=\"serviceRegistration\">Optional service registration when it's available.</param>\n    /// <returns>The service context.</returns>\n    public static ServiceContext AsServiceContext(this Expression? expression, ServiceRegistration? serviceRegistration = null) =>\n        expression == null ? ServiceContext.Empty : new ServiceContext(expression, serviceRegistration);\n\n    /// <summary>\n    /// Compiles a lambda expression into a Func delegate.\n    /// </summary>\n    /// <typeparam name=\"T\">The result type.</typeparam>\n    /// <param name=\"expression\">The expression</param>\n    /// <returns>The delegate.</returns>\n    public static Func<T> CompileFunc<T>(this Expression<Func<T>> expression) =>\n        (Func<T>)expression.CompileDelegate();\n\n    /// <summary>\n    /// Compiles a lambda expression into a Func delegate.\n    /// </summary>\n    /// <typeparam name=\"T1\">First parameter type.</typeparam>\n    /// <typeparam name=\"T\">The result type.</typeparam>\n    /// <param name=\"expression\">The expression</param>\n    /// <returns>The delegate.</returns>\n    public static Func<T1, T> CompileFunc<T1, T>(this Expression<Func<T1, T>> expression) =>\n        (Func<T1, T>)expression.CompileDelegate();\n\n    /// <summary>\n    /// Constructs an assigment expression, => Expression.Assign(left, right)\n    /// </summary>\n    /// <param name=\"left\">The left part.</param>\n    /// <param name=\"right\">The right part.</param>\n    /// <returns>The assignment expression.</returns>\n    public static BinaryExpression AssignTo(this Expression left, Expression right) => Expression.Assign(left, right);\n\n    /// <summary>\n    /// Constructs an assigment expression, => Expression.Bind(member, expression)\n    /// </summary>\n    /// <param name=\"memberInfo\">The member info.</param>\n    /// <param name=\"expression\">The right part.</param>\n    /// <returns>The assignment expression.</returns>\n    public static MemberAssignment AssignTo(this MemberInfo memberInfo, Expression expression) =>\n        Expression.Bind(memberInfo, expression);\n\n    /// <summary>\n    /// Constructs a constant expression from an object, => Expression.Constant(obj)\n    /// </summary>\n    /// <param name=\"obj\">The object.</param>\n    /// <returns>The constant expression.</returns>\n    public static ConstantExpression AsConstant(this object? obj) => Expression.Constant(obj);\n\n    /// <summary>\n    /// Constructs a constant expression from an object and a type, => Expression.Constant(obj, type)\n    /// </summary>\n    /// <param name=\"obj\">The object.</param>\n    /// <param name=\"type\">The type.</param>\n    /// <returns>The constant expression.</returns>\n    public static ConstantExpression AsConstant(this object? obj, Type type) => Expression.Constant(obj, type);\n\n    /// <summary>\n    /// Constructs a default expression from a type, => Expression.Default(type)\n    /// </summary>\n    /// <param name=\"type\">The type.</param>\n    /// <returns>The default expression.</returns>\n    public static DefaultExpression AsDefault(this Type type) => Expression.Default(type);\n\n    /// <summary>\n    /// Constructs a block expression from an expression collection and variables, => Expression.Block(variables, expressions)\n    /// </summary>\n    /// <param name=\"expressions\">The expressions.</param>\n    /// <param name=\"variables\">The variables.</param>\n    /// <returns>The block expression.</returns>\n    public static BlockExpression AsBlock(this IEnumerable<Expression> expressions, params ParameterExpression[] variables) =>\n        Expression.Block(variables, expressions);\n\n    internal static BlockExpression AsBlock(this ExpandableArray<Expression> expressions, params ParameterExpression[] variables) =>\n        Expression.Block(variables, expressions);\n\n    private static BlockExpression AsBlock(this ExpandableArray<Expression> expressions, IEnumerable<ParameterExpression> variables) =>\n        Expression.Block(variables, expressions);\n\n    /// <summary>\n    /// Constructs a lambda expression from an expression and parameters, => Expression.Lambda(expression, parameters)\n    /// </summary>\n    /// <param name=\"expression\">The expression.</param>\n    /// <param name=\"parameters\">The parameters.</param>\n    /// <returns>The lambda expression.</returns>\n    public static LambdaExpression AsLambda(this Expression expression, params ParameterExpression[] parameters) =>\n        Expression.Lambda(expression, parameters);\n\n    /// <summary>\n    /// Constructs a lambda expression from an expression and parameters, => Expression.Lambda(expression, parameters)\n    /// </summary>\n    /// <param name=\"expression\">The expression.</param>\n    /// <param name=\"delegateType\">The type of the delegate.</param>\n    /// <param name=\"parameters\">The parameters.</param>\n    /// <returns>The lambda expression.</returns>\n    public static LambdaExpression AsLambda(this Expression expression, Type delegateType, IEnumerable<ParameterExpression> parameters) =>\n        Expression.Lambda(delegateType, expression, parameters);\n\n    /// <summary>\n    /// Constructs a lambda expression from an expression and parameters, => Expression.Lambda(expression, parameters)\n    /// </summary>\n    /// <param name=\"expression\">The expression.</param>\n    /// <param name=\"delegateType\">The type of the delegate.</param>\n    /// <param name=\"parameters\">The parameters.</param>\n    /// <returns>The lambda expression.</returns>\n    public static LambdaExpression AsLambda(this Expression expression, Type delegateType, params ParameterExpression[] parameters) =>\n        Expression.Lambda(delegateType, expression, parameters);\n\n    /// <summary>\n    /// Constructs a lambda expression from an expression and parameters, => Expression.Lambda(expression, parameters)\n    /// </summary>\n    /// <param name=\"expression\">The expression.</param>\n    /// <param name=\"parameters\">The parameters.</param>\n    /// <returns>The lambda expression.</returns>\n    public static LambdaExpression AsLambda(this Expression expression, IEnumerable<ParameterExpression> parameters) =>\n        Expression.Lambda(expression, parameters);\n\n    /// <summary>\n    /// Constructs a lambda expression from an expression and parameters, => Expression.Lambda{TDelegate}(expression, parameters)\n    /// </summary>\n    /// <param name=\"expression\">The expression.</param>\n    /// <param name=\"parameters\">The parameters.</param>\n    /// <returns>The lambda expression.</returns>\n    public static Expression<TDelegate> AsLambda<TDelegate>(this Expression expression, params ParameterExpression[] parameters) =>\n        Expression.Lambda<TDelegate>(expression, parameters);\n\n    /// <summary>\n    /// Constructs a variable expression from a type, => Expression.Variable(type, name)\n    /// </summary>\n    /// <param name=\"type\">The type.</param>\n    /// <param name=\"name\">The name.</param>\n    /// <returns>The variable expression.</returns>\n    public static ParameterExpression AsVariable(this Type type, string? name = null) => Expression.Variable(type, name);\n\n    /// <summary>\n    /// Constructs a parameter expression from a type, => Expression.Parameter(type, name)\n    /// </summary>\n    /// <param name=\"type\">The type.</param>\n    /// <param name=\"name\">The name.</param>\n    /// <returns>The parameter expression.</returns>\n    public static ParameterExpression AsParameter(this Type type, string? name = null) => Expression.Parameter(type, name);\n\n    /// <summary>\n    /// Constructs a static method call expression from a <see cref=\"MethodInfo\"/> and its parameters, => Expression.Call(methodInfo, parameters)\n    /// </summary>\n    /// <param name=\"methodInfo\">The static method info.</param>\n    /// <param name=\"parameters\">The parameters.</param>\n    /// <returns>The call expression.</returns>\n    public static MethodCallExpression CallStaticMethod(this MethodInfo methodInfo, params Expression[] parameters) =>\n        Expression.Call(methodInfo, parameters);\n\n    /// <summary>\n    /// Constructs a static method call expression from a <see cref=\"MethodInfo\"/> and its parameters, => Expression.Call(methodInfo, parameters)\n    /// </summary>\n    /// <param name=\"methodInfo\">The static method info.</param>\n    /// <param name=\"parameters\">The parameters.</param>\n    /// <returns>The call expression.</returns>\n    public static MethodCallExpression CallStaticMethod(this MethodInfo methodInfo, IEnumerable<Expression> parameters) =>\n        Expression.Call(methodInfo, parameters);\n\n    /// <summary>\n    /// Constructs a method call expression from a target expression, method info and parameters, => Expression.Call(target, methodInfo, parameters)\n    /// </summary>\n    /// <param name=\"target\">The target expression.</param>\n    /// <param name=\"methodInfo\">The method info.</param>\n    /// <param name=\"parameters\">The parameters.</param>\n    /// <returns>The call expression.</returns>\n    public static MethodCallExpression CallMethod(this Expression target, MethodInfo methodInfo, params Expression[] parameters) =>\n        Expression.Call(target, methodInfo, parameters);\n\n    /// <summary>\n    /// Constructs a method call expression from a target expression, method info and parameters, => Expression.Call(target, methodInfo, parameters)\n    /// </summary>\n    /// <param name=\"target\">The target expression.</param>\n    /// <param name=\"methodInfo\">The method info.</param>\n    /// <param name=\"parameters\">The parameters.</param>\n    /// <returns>The call expression.</returns>\n    public static MethodCallExpression CallMethod(this Expression target, MethodInfo methodInfo, IEnumerable<Expression> parameters) =>\n        Expression.Call(target, methodInfo, parameters);\n\n    /// <summary>\n    /// Constructs a method call expression from a target expression, method info and parameters, => Expression.Call(target, methodInfo, parameters)\n    /// </summary>\n    /// <param name=\"target\">The target expression.</param>\n    /// <param name=\"methodInfo\">The method info.</param>\n    /// <param name=\"parameters\">The parameters.</param>\n    /// <returns>The call expression.</returns>\n    public static MethodCallExpression CallMethod(this MethodInfo methodInfo, Expression target, params Expression[] parameters) =>\n        target.CallMethod(methodInfo, parameters);\n\n    /// <summary>\n    /// Constructs a method call expression from a target expression, method info and parameters, => Expression.Call(target, methodInfo, parameters)\n    /// </summary>\n    /// <param name=\"target\">The target expression.</param>\n    /// <param name=\"methodInfo\">The method info.</param>\n    /// <param name=\"parameters\">The parameters.</param>\n    /// <returns>The call expression.</returns>\n    public static MethodCallExpression CallMethod(this MethodInfo methodInfo, Expression target, IEnumerable<Expression> parameters) =>\n        target.CallMethod(methodInfo, parameters);\n\n    /// <summary>\n    /// Constructs a convert expression, => Expression.Convert(expression, type)\n    /// </summary>\n    /// <param name=\"expression\">The expression.</param>\n    /// <param name=\"type\">The type.</param>\n    /// <returns>The convert expression.</returns>\n    public static Expression ConvertTo(this Expression expression, Type type) => Expression.Convert(expression, type);\n\n    /// <summary>\n    /// Constructs an invocation expression, => Expression.Invoke(expression, parameters)\n    /// </summary>\n    /// <param name=\"expression\">The expression.</param>\n    /// <param name=\"parameters\">The parameters.</param>\n    /// <returns>The invocation expression.</returns>\n    public static InvocationExpression InvokeLambda(this LambdaExpression expression, params Expression[] parameters) =>\n        Expression.Invoke(expression, parameters);\n\n    /// <summary>\n    /// Constructs an invocation expression, => Expression.Invoke(delegate.AsConstant(), parameters)\n    /// </summary>\n    /// <param name=\"delegate\">The delegate to invoke.</param>\n    /// <param name=\"parameters\">The delegate parameters.</param>\n    /// <returns>The invocation expression.</returns>\n    public static InvocationExpression InvokeDelegate(this Delegate @delegate, params Expression[] parameters) =>\n        Expression.Invoke(@delegate.AsConstant(), parameters);\n\n    /// <summary>\n    /// Constructs an invocation expression, => Expression.Invoke(delegate.AsConstant(), parameters)\n    /// </summary>\n    /// <param name=\"delegate\">The delegate to invoke.</param>\n    /// <param name=\"parameters\">The delegate parameters.</param>\n    /// <returns>The invocation expression.</returns>\n    public static InvocationExpression InvokeDelegate(this Delegate @delegate, IEnumerable<Expression> parameters) =>\n        Expression.Invoke(@delegate.AsConstant(), parameters);\n\n    /// <summary>\n    /// Constructs an new expression, => Expression.New(constructor, arguments)\n    /// </summary>\n    /// <param name=\"constructor\">The constructor info.</param>\n    /// <param name=\"arguments\">The arguments.</param>\n    /// <returns>The new expression.</returns>\n    public static NewExpression MakeNew(this ConstructorInfo constructor, IEnumerable<Expression> arguments) =>\n        Expression.New(constructor, arguments);\n\n    /// <summary>\n    /// Constructs an new expression, => Expression.New(constructor, arguments)\n    /// </summary>\n    /// <param name=\"constructor\">The constructor info.</param>\n    /// <param name=\"arguments\">The arguments.</param>\n    /// <returns>The new expression.</returns>\n    public static NewExpression MakeNew(this ConstructorInfo constructor, params Expression[] arguments) =>\n        Expression.New(constructor, arguments);\n\n    /// <summary>\n    /// Constructs a member access expression, => Expression.Property(expression, prop) or Expression.Field(expression, field)\n    /// </summary>\n    /// <param name=\"expression\">The target expression.</param>\n    /// <param name=\"memberInfo\">The property or field info.</param>\n    /// <returns>The member access expression.</returns>\n    public static MemberExpression Member(this Expression expression, MemberInfo memberInfo) =>\n        memberInfo is PropertyInfo prop ? Expression.Property(expression, prop) : Expression.Field(expression, (FieldInfo)memberInfo);\n\n    /// <summary>\n    /// Constructs a property access expression, => Expression.Property(expression, prop)\n    /// </summary>\n    /// <param name=\"expression\">The target expression.</param>\n    /// <param name=\"propertyInfo\">The property info.</param>\n    /// <returns>The property access expression.</returns>\n    public static MemberExpression Prop(this Expression expression, PropertyInfo propertyInfo) =>\n        Expression.Property(expression, propertyInfo);\n\n    /// <summary>\n    /// Constructs a property access expression, => Expression.Property(expression, prop)\n    /// </summary>\n    /// <param name=\"propertyInfo\">The property info.</param>\n    /// <param name=\"expression\">The target expression.</param>\n    /// <returns>The property access expression.</returns>\n    public static MemberExpression Access(this PropertyInfo propertyInfo, Expression expression) =>\n        Expression.Property(expression, propertyInfo);\n\n    /// <summary>\n    /// Constructs a member init expression, => Expression.MemberInit(expression, bindings)\n    /// </summary>\n    /// <param name=\"expression\">The expression.</param>\n    /// <param name=\"bindings\">The member bindings.</param>\n    /// <returns>The member init expression.</returns>\n    public static MemberInitExpression InitMembers(this Expression expression, IEnumerable<MemberBinding> bindings) =>\n        Expression.MemberInit((NewExpression)expression, bindings);\n\n    /// <summary>\n    /// Constructs a member init expression, => Expression.MemberInit(expression, bindings)\n    /// </summary>\n    /// <param name=\"expression\">The expression.</param>\n    /// <param name=\"bindings\">The member bindings.</param>\n    /// <returns>The member init expression.</returns>\n    public static MemberInitExpression InitMembers(this Expression expression, params MemberBinding[] bindings) =>\n        Expression.MemberInit((NewExpression)expression, bindings);\n\n    /// <summary>\n    /// Constructs a new array expression, => Expression.NewArrayInit(type, initializerExpressions)\n    /// </summary>\n    /// <param name=\"type\">The type.</param>\n    /// <param name=\"initializerExpressions\">The element initializer expressions.</param>\n    /// <returns>The new array expression.</returns>\n    public static NewArrayExpression InitNewArray(this Type type, params Expression[] initializerExpressions) =>\n        Expression.NewArrayInit(type, initializerExpressions);\n\n    /// <summary>\n    /// Constructs a new array expression, => Expression.NewArrayInit(type, initializerExpressions)\n    /// </summary>\n    /// <param name=\"type\">The type.</param>\n    /// <param name=\"initializerExpressions\">The element initializer expressions.</param>\n    /// <returns>The new array expression.</returns>\n    public static NewArrayExpression InitNewArray(this Type type, IEnumerable<Expression> initializerExpressions) =>\n        Expression.NewArrayInit(type, initializerExpressions);\n}"
  },
  {
    "path": "src/Extensions/TypeExtensions.cs",
    "content": "﻿using Stashbox.Attributes;\nusing Stashbox.Configuration;\nusing Stashbox.Registration;\nusing Stashbox.Resolution;\nusing Stashbox.Utils;\nusing System.Collections.Generic;\nusing System.Collections.ObjectModel;\nusing System.Linq;\nusing System.Reflection;\nusing System.Runtime.CompilerServices;\nusing Stashbox;\nusing DependencyAttribute = Stashbox.Attributes.DependencyAttribute;\n\nnamespace System;\n\ninternal static class TypeExtensions\n{\n    public static Type? GetEnumerableType(this Type type)\n    {\n        if (type.IsArray)\n            return type.GetElementType();\n\n        if (type.ImplementsGenericType(TypeCache.EnumerableType) && type != TypeCache<string>.Type && type.GenericTypeArguments.Length == 1)\n            return type.GenericTypeArguments[0];\n\n        return null;\n    }\n\n    public static bool IsClosedGenericType(this Type type) =>\n        type is { IsGenericType: true, IsGenericTypeDefinition: false };\n\n    public static bool IsOpenGenericType(this Type type) =>\n        type is { IsGenericType: true, ContainsGenericParameters: true };\n\n    public static ConstructorInfo? GetConstructor(this Type type, params Type[] args) =>\n        Array.Find(type.GetConstructors(), c => c.GetParameters().Select(p => p.ParameterType).SequenceEqual(args));\n\n    public static bool IsDisposable(this Type type) =>\n        type.Implements(TypeCache<IDisposable>.Type)\n#if HAS_ASYNC_DISPOSABLE\n         || type.Implements(TypeCache<IAsyncDisposable>.Type)\n#endif\n    ;\n\n    public static bool IsCompositionRoot(this Type type) =>\n        type.Implements(TypeCache<ICompositionRoot>.Type);\n\n    public static bool IsResolvableType(this Type type) =>\n        type is { IsAbstract: false, IsInterface: false, IsClass: true } &&\n        type != TypeCache<string>.Type &&\n        type.GetCustomAttribute<CompilerGeneratedAttribute>() == null;\n\n    public static IEnumerable<Type> GetRegisterableInterfaceTypes(this Type type) =>\n        type.GetInterfaces().Where(t =>\n                t != TypeCache<IDisposable>.Type\n#if HAS_ASYNC_DISPOSABLE\n         && t != TypeCache<IAsyncDisposable>.Type\n#endif\n        );\n\n    public static IEnumerable<Type> GetRegisterableBaseTypes(this Type type)\n    {\n        var baseType = type.BaseType;\n        while (baseType != null && !baseType.IsObjectType())\n        {\n            yield return baseType;\n            baseType = baseType.BaseType;\n        }\n    }\n\n    public static IEnumerable<Type> GetPossibleDependencyTypes(this Type type)\n    {\n        var constructorParameterTypes = type.GetConstructors()\n            .SelectMany(c => c.GetParameters().Select(p => p.ParameterType));\n\n        var memberTypes = type.GetProperties().Select(p => p.PropertyType)\n            .Concat(type.GetFields().Select(f => f.FieldType));\n\n        return constructorParameterTypes.Concat(memberTypes).Distinct();\n    }\n\n    public static bool Implements(this Type type, Type interfaceType) =>\n        type == interfaceType || (interfaceType.IsOpenGenericType()\n            ? type.ImplementsGenericType(interfaceType.GetGenericTypeDefinition())\n            : interfaceType.IsAssignableFrom(type));\n\n    public static bool ImplementsWithoutGenericCheck(this Type type, Type interfaceType) =>\n        interfaceType.IsAssignableFrom(type);\n\n    private static bool ImplementsGenericType(this Type type, Type genericType) =>\n        type.MapsToGenericTypeDefinition(genericType) ||\n        type.HasInterfaceThatMapsToGenericTypeDefinition(genericType) ||\n        type.BaseType != null && type.BaseType.ImplementsGenericType(genericType);\n\n    private static bool HasInterfaceThatMapsToGenericTypeDefinition(this Type type, Type genericType) =>\n        type.GetInterfaces()\n            .Where(it => it.IsGenericType)\n            .Any(it => it.GetGenericTypeDefinition() == genericType);\n\n    public static bool MapsToGenericTypeDefinition(this Type type, Type genericType) =>\n        genericType.IsGenericTypeDefinition\n        && type.IsGenericType\n        && type.GetGenericTypeDefinition() == genericType;\n\n    public static ConstructorInfo? GetFirstConstructor(this Type type) =>\n        type.GetConstructors().FirstOrDefault();\n\n    public static TypeInformation AsTypeInformation(this ParameterInfo parameter,\n        Type? declaringType,\n        TypeInformation parent,\n        ServiceRegistration? serviceRegistration,\n        ContainerConfiguration containerConfiguration)\n    {\n        var customAttributes = parameter.GetCustomAttributes();\n        var dependencyName = parameter.GetNameFromDependencyAttribute(containerConfiguration);\n\n        if (serviceRegistration != null)\n        {\n            var dependencyBindings = serviceRegistration?.Options.GetOrDefault<Dictionary<object, object?>>(RegistrationOption.DependencyBindings);\n            if (dependencyBindings != null || containerConfiguration.TreatingParameterAndMemberNameAsDependencyNameEnabled)\n            {\n                if (dependencyBindings != null && parameter.Name != null && dependencyBindings.TryGetValue(parameter.Name,\n                        out var foundNamedDependencyName))\n                    dependencyName = foundNamedDependencyName;\n                else if (dependencyBindings != null && dependencyBindings.TryGetValue(parameter.ParameterType,\n                             out var foundTypedDependencyName))\n                    dependencyName = foundTypedDependencyName;\n                else if (dependencyName == null &&\n                         containerConfiguration.TreatingParameterAndMemberNameAsDependencyNameEnabled)\n                    dependencyName = parameter.Name;\n            }\n        }\n\n        return new TypeInformation(\n            parameter.ParameterType,\n            declaringType,\n            parent,\n            dependencyName,\n            customAttributes,\n            parameter.Name,\n            parameter.GetOptionalDefaultValue(),\n            parameter.HasDependencyNameAttribute(containerConfiguration),\n            null);\n    }\n\n    public static TypeInformation AsTypeInformation(this MemberInfo member, \n        ServiceRegistration? serviceRegistration,\n        TypeInformation parent,\n        ContainerConfiguration containerConfiguration)\n    {\n        var customAttributes = member.GetCustomAttributes();\n        var dependencyName = member.GetNameFromDependencyAttribute(containerConfiguration);\n\n        if (serviceRegistration != null)\n        {\n            var dependencyBindings = serviceRegistration?.Options.GetOrDefault<Dictionary<object, object?>>(RegistrationOption.DependencyBindings);\n            if (dependencyBindings != null || containerConfiguration.TreatingParameterAndMemberNameAsDependencyNameEnabled)\n            {\n                if (dependencyBindings != null && dependencyBindings.TryGetValue(member.Name, out var foundNamedDependencyName))\n                    dependencyName = foundNamedDependencyName;\n                else if (dependencyName == null && containerConfiguration.TreatingParameterAndMemberNameAsDependencyNameEnabled)\n                    dependencyName = member.Name;\n            }\n        }\n\n        var type = member is PropertyInfo prop ? prop.PropertyType : ((FieldInfo)member).FieldType;\n        return new TypeInformation(\n            type,\n            member.DeclaringType,\n            parent,\n            dependencyName,\n            customAttributes,\n            member.Name,\n            null,\n            member.HasDependencyNameAttribute(containerConfiguration),\n            null);\n    }\n\n    public static MethodInfo[] GetUsableMethods(this Type type)\n    {\n        var methods = type.GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance).Where(method => method.GetInjectionAttribute() != null);\n        var baseType = type.BaseType;\n        while (baseType != null && !baseType.IsObjectType())\n        {\n            methods = methods.Concat(baseType.GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance).Where(method => method.GetInjectionAttribute() != null));\n            baseType = baseType.BaseType;\n        }\n\n        return methods.CastToArray();\n    }\n\n    public static MemberInfo[] GetUsableMembers(this Type type,\n        ServiceRegistration? serviceRegistration,\n        ContainerConfiguration containerConfiguration)\n    {\n        var autoMemberOptions = serviceRegistration?.Options.GetOrDefault<AutoMemberOptions>(RegistrationOption.AutoMemberOptions);\n        var autoMemberInjectionEnabled = containerConfiguration.AutoMemberInjectionEnabled || autoMemberOptions != null;\n        var autoMemberInjectionRule = autoMemberOptions?.AutoMemberInjectionRule ?? containerConfiguration.AutoMemberInjectionRule;\n\n        var publicPropsEnabled = autoMemberInjectionEnabled && (autoMemberInjectionRule & Rules.AutoMemberInjectionRules.PropertiesWithPublicSetter) == Rules.AutoMemberInjectionRules.PropertiesWithPublicSetter;\n        var limitedPropsEnabled = autoMemberInjectionEnabled && (autoMemberInjectionRule & Rules.AutoMemberInjectionRules.PropertiesWithLimitedAccess) == Rules.AutoMemberInjectionRules.PropertiesWithLimitedAccess;\n        var fieldsEnabled = autoMemberInjectionEnabled && (autoMemberInjectionRule & Rules.AutoMemberInjectionRules.PrivateFields) == Rules.AutoMemberInjectionRules.PrivateFields;\n\n        var dependencyBindings = serviceRegistration?.Options.GetOrDefault<Dictionary<object, object?>>(RegistrationOption.DependencyBindings);\n\n        var globalRequiredInjectionEnabled = containerConfiguration.RequiredMemberInjectionEnabled;\n        var regRequiredInjectionEnabled = serviceRegistration?.Options.GetOrDefault<bool?>(RegistrationOption.RequiredMemberInjectionEnabled);\n        var requiredInjectionEnabled = regRequiredInjectionEnabled ?? globalRequiredInjectionEnabled;\n        \n        IEnumerable<MemberInfo> properties = type.GetProperties(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance)\n            .Where(member => member.FilterProperty(dependencyBindings, autoMemberOptions, containerConfiguration, publicPropsEnabled, limitedPropsEnabled, requiredInjectionEnabled));\n        IEnumerable<MemberInfo> fields = type.GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance)\n            .Where(member => member.FilterField(dependencyBindings, autoMemberOptions,  containerConfiguration, fieldsEnabled, requiredInjectionEnabled));\n\n        var baseType = type.BaseType;\n        while (baseType != null && !baseType.IsObjectType())\n        {\n            properties = properties.Concat(baseType.GetProperties(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance)\n                .Where(member => member.FilterProperty(dependencyBindings, autoMemberOptions, containerConfiguration, publicPropsEnabled, limitedPropsEnabled, requiredInjectionEnabled)));\n            fields = fields.Concat(baseType.GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance)\n                .Where(member => member.FilterField(dependencyBindings, autoMemberOptions, containerConfiguration, fieldsEnabled, requiredInjectionEnabled)));\n            baseType = baseType.BaseType;\n        }\n\n        return properties.Concat(fields).CastToArray();\n    }\n\n    public static bool SatisfiesGenericConstraintsOf(this Type implementationType, Type serviceType)\n    {\n        if (!implementationType.IsGenericTypeDefinition) return true;\n\n        var serviceParameters = serviceType.GetGenericArguments();\n        var serviceParametersLength = serviceParameters.Length;\n        var implementationParameters = implementationType.GetGenericArguments();\n        var implementationParametersLength = implementationParameters.Length;\n\n        for (var i = 0; i < implementationParametersLength; i++)\n        {\n            var implementationParameter = implementationParameters[i];\n            var parameterPosition = implementationParameter.GenericParameterPosition;\n            if (parameterPosition >= serviceParametersLength)\n                return false;\n\n            var argumentToValidate = serviceParameters[parameterPosition];\n            var parameterAttributes = implementationParameter.GenericParameterAttributes;\n\n            if (parameterAttributes.HasDefaultConstructorConstraint() &&\n                !parameterAttributes.HasNotNullableValueTypeConstraint() &&\n                !argumentToValidate.IsPrimitive &&\n                !argumentToValidate.HasPublicParameterlessConstructor())\n                return false;\n\n            if (parameterAttributes.HasReferenceTypeConstraint() &&\n                argumentToValidate is { IsClass: false, IsInterface: false })\n                return false;\n            \n            if (parameterAttributes.HasNotNullableValueTypeConstraint() &&\n                argumentToValidate is { IsValueType: false, IsPrimitive: false, IsEnum: false })\n                return false;\n\n            var constraints = implementationParameter.GetGenericParameterConstraints();\n            var constraintsLength = constraints.Length;\n\n            if (constraints.Length <= 0) continue;\n\n            var found = false;\n            for (var j = 0; !found && j < constraintsLength; j++)\n            {\n                var constraintForCheck = constraints[j];\n                if (argumentToValidate.Implements(constraintForCheck))\n                    found = true;\n            }\n\n            return found;\n        }\n\n        return true;\n    }\n\n    private static bool HasDependencyNameAttribute(this ParameterInfo parameterInfo, ContainerConfiguration containerConfiguration) =>\n        parameterInfo.GetCustomAttributes(TypeCache<DependencyNameAttribute>.Type, false).FirstOrDefault() != null ||\n        parameterInfo.CustomAttributes.Any(ca => containerConfiguration.AdditionalDependencyNameAttributeTypes != null && \n                                                 containerConfiguration.AdditionalDependencyNameAttributeTypes.Contains(ca.AttributeType));\n\n    private static bool HasDependencyNameAttribute(this MemberInfo memberInfo, ContainerConfiguration containerConfiguration) =>\n        memberInfo.GetCustomAttributes(TypeCache<DependencyNameAttribute>.Type, false).FirstOrDefault() != null || \n        memberInfo.CustomAttributes.Any(ca => containerConfiguration.AdditionalDependencyNameAttributeTypes != null && \n                                              containerConfiguration.AdditionalDependencyNameAttributeTypes.Contains(ca.AttributeType));\n    \n    public static bool IsNullableType(this Type type) =>\n        type.IsGenericType && type.GetGenericTypeDefinition() == TypeCache.NullableType;\n\n    public static MethodInfo GetMethod(this Delegate @delegate) =>\n        @delegate.GetMethodInfo();\n\n    public static bool IsCompiledLambda(this Delegate @delegate) =>\n        @delegate.Target != null && @delegate.Target.GetType().FullName == \"System.Runtime.CompilerServices.Closure\";\n\n    public static string GetDiagnosticsView(this Type type)\n    {\n        if (!type.IsGenericType) return type.Name;\n\n        var typeName = type.Name;\n        var i = typeName.IndexOf('`');\n#if NET5_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER\n            typeName = i != -1 ? typeName[..i] : typeName;\n#else\n        typeName = i != -1 ? typeName.Substring(0, i) : typeName;\n#endif\n\n        typeName += \"<\";\n        if (type.IsGenericTypeDefinition)\n            typeName += new string(Enumerable.Repeat(',', type.GetGenericArguments().Length - 1).ToArray());\n        else\n            typeName += string.Join(\",\", type.GetGenericArguments().Select(a => a.GetDiagnosticsView()));\n\n        typeName += \">\";\n\n        return typeName;\n    }\n\n    private static bool IsObjectType(this Type type) => type == TypeCache<object>.Type;\n\n    private static bool HasDefaultConstructorConstraint(this GenericParameterAttributes attributes) =>\n        (attributes & GenericParameterAttributes.DefaultConstructorConstraint) == GenericParameterAttributes.DefaultConstructorConstraint;\n\n    private static bool HasReferenceTypeConstraint(this GenericParameterAttributes attributes) =>\n        (attributes & GenericParameterAttributes.ReferenceTypeConstraint) == GenericParameterAttributes.ReferenceTypeConstraint;\n    \n    private static bool HasNotNullableValueTypeConstraint(this GenericParameterAttributes attributes) =>\n        (attributes & GenericParameterAttributes.NotNullableValueTypeConstraint) == GenericParameterAttributes.NotNullableValueTypeConstraint;\n\n    private static bool FilterProperty(this PropertyInfo prop, Dictionary<object, object?>? dependencyBindings, AutoMemberOptions? autoMemberOptions,\n        ContainerConfiguration containerConfiguration, bool publicPropsEnabled, bool limitedPropsEnabled, bool requiredInjectionEnabled)\n    {\n        var valid = prop.CanWrite && !prop.IsIndexer() &&\n                    (prop.HasDependencyAttribute(containerConfiguration) || \n#if HAS_REQUIRED\n                     (prop.HasRequiredAttribute() && requiredInjectionEnabled) ||\n#endif\n                     publicPropsEnabled && prop.GetSetMethod() != null || limitedPropsEnabled ||\n                     (dependencyBindings != null && dependencyBindings.ContainsKey(prop.Name)));\n        \n        valid = valid && (containerConfiguration.AutoMemberInjectionFilter == null || containerConfiguration.AutoMemberInjectionFilter(prop));\n        valid = valid && (autoMemberOptions?.AutoMemberInjectionFilter == null || autoMemberOptions.AutoMemberInjectionFilter(prop));\n\n        return valid;\n    }\n\n    private static bool FilterField(this FieldInfo field, Dictionary<object, object?>? dependencyBindings, AutoMemberOptions? autoMemberOptions,\n        ContainerConfiguration containerConfiguration, bool fieldsEnabled, bool requiredInjectionEnabled)\n    {\n        var valid = !field.IsInitOnly && !field.IsBackingField() &&\n                    (field.HasDependencyAttribute(containerConfiguration) || \n#if HAS_REQUIRED\n                     (field.HasRequiredAttribute() && requiredInjectionEnabled) ||\n#endif\n                     fieldsEnabled ||\n                     (dependencyBindings != null && dependencyBindings.ContainsKey(field.Name)));\n\n        valid = valid && (containerConfiguration.AutoMemberInjectionFilter == null || containerConfiguration.AutoMemberInjectionFilter(field));\n        valid = valid && (autoMemberOptions?.AutoMemberInjectionFilter == null || autoMemberOptions.AutoMemberInjectionFilter(field));\n\n        return valid;\n    }\n\n    private static bool IsBackingField(this MemberInfo field) =>\n        field.Name[0] == '<';\n\n    private static bool IsIndexer(this PropertyInfo property) =>\n        property.GetIndexParameters().Length != 0;\n\n    private static TypeInformation.DefaultValueHolder? GetOptionalDefaultValue(this ParameterInfo parameter)\n    {\n        if (!parameter.IsOptional) return null;\n        if (parameter.DefaultValue != null && parameter.DefaultValue.GetType() == TypeCache<Missing>.Type) \n            return parameter.IsNullableMember() \n                ? new TypeInformation.DefaultValueHolder(null) \n                : null;\n        return new TypeInformation.DefaultValueHolder(parameter.DefaultValue);\n    }\n\n    private static bool IsNullableMember(this ParameterInfo parameter) => \n        IsNullableMember(parameter.Member, parameter.ParameterType);\n    \n    private static bool IsNullableMember(MemberInfo member, Type memberType)\n    {\n        if (memberType.IsValueType)\n            return Nullable.GetUnderlyingType(memberType) != null;\n\n        var nullable = member.CustomAttributes\n            .FirstOrDefault(x => x.AttributeType.FullName == \"System.Runtime.CompilerServices.NullableAttribute\");\n        if (nullable is { ConstructorArguments.Count: 1 })\n        {\n            var attributeArgument = nullable.ConstructorArguments[0];\n            if (attributeArgument.ArgumentType == TypeCache<byte[]>.Type)\n            {\n                var args = (ReadOnlyCollection<CustomAttributeTypedArgument>)attributeArgument.Value!;\n                if (args.Count > 0 && args[0].ArgumentType == TypeCache<byte>.Type)\n                    return (byte)args[0].Value! == 2;\n            }\n            else if (attributeArgument.ArgumentType == TypeCache<byte>.Type)\n                return (byte)attributeArgument.Value! == 2;\n        }\n        for (var type = member; type != null; type = type.DeclaringType)\n        {\n            var context = type.CustomAttributes\n                .FirstOrDefault(x => x.AttributeType.FullName == \"System.Runtime.CompilerServices.NullableContextAttribute\");\n            if (context is { ConstructorArguments.Count: 1 } &&\n                context.ConstructorArguments[0].ArgumentType == TypeCache<byte>.Type)\n                return (byte)context.ConstructorArguments[0].Value! == 2;\n        }\n        return false;\n    }\n\n    private static bool HasPublicParameterlessConstructor(this Type type) =>\n        Array.Find(type.GetConstructors(), c => c.GetParameters().Length == 0) != null;\n\n    private static object? GetNameFromDependencyAttribute(this MemberInfo property, ContainerConfiguration containerConfiguration)\n    {\n        var attr = property.GetCustomAttributes(TypeCache<DependencyAttribute>.Type, false).FirstOrDefault();\n        if (attr != null) return (attr as DependencyAttribute)?.Name;\n\n        var msAttr = property.CustomAttributes.FirstOrDefault(a => containerConfiguration.AdditionalDependencyAttributeTypes != null &&\n                                                                   containerConfiguration.AdditionalDependencyAttributeTypes.Contains(a.AttributeType));\n        return msAttr?.ConstructorArguments.FirstOrDefault().Value;\n    }\n\n    private static object? GetNameFromDependencyAttribute(this ParameterInfo parameter, ContainerConfiguration containerConfiguration)\n    {\n        var attr = parameter.GetCustomAttributes(TypeCache<DependencyAttribute>.Type, false).FirstOrDefault();\n        if (attr != null) return (attr as DependencyAttribute)?.Name;\n\n        var msAttr = parameter.CustomAttributes.FirstOrDefault(a => containerConfiguration.AdditionalDependencyAttributeTypes != null &&\n                                                                    containerConfiguration.AdditionalDependencyAttributeTypes.Contains(a.AttributeType));\n        return msAttr?.ConstructorArguments.FirstOrDefault().Value;\n    }\n\n    private static bool HasDependencyAttribute(this MemberInfo property, ContainerConfiguration containerConfiguration)\n    {\n        return property.GetCustomAttributes(TypeCache<DependencyAttribute>.Type, false).FirstOrDefault() != null ||\n               property.CustomAttributes.Any(a => containerConfiguration.AdditionalDependencyAttributeTypes != null &&\n                                                  containerConfiguration.AdditionalDependencyAttributeTypes.Contains(a.AttributeType));\n    }\n    \n#if HAS_REQUIRED\n    private static bool HasRequiredAttribute(this MemberInfo memberInfo) =>\n        memberInfo.GetCustomAttributes(TypeCache<RequiredMemberAttribute>.Type, false).FirstOrDefault() != null;\n#endif\n\n    private static InjectionMethodAttribute? GetInjectionAttribute(this MemberInfo method)\n    {\n        var attr = method.GetCustomAttributes(TypeCache<InjectionMethodAttribute>.Type, false).FirstOrDefault();\n        return attr as InjectionMethodAttribute;\n    }\n}"
  },
  {
    "path": "src/ICompositionRoot.cs",
    "content": "﻿namespace Stashbox;\n\n/// <summary>\n/// Represents a composition root used by the <see cref=\"CollectionRegistratorExtensions.ComposeBy{TCompositionRoot}\"/>, <see cref=\"IDependencyCollectionRegistrator.ComposeBy(System.Type, object[])\"/>, <see cref=\"CollectionRegistratorExtensions.ComposeAssembly\"/>, and <see cref=\"CollectionRegistratorExtensions.ComposeAssemblies\"/> methods.\n/// </summary>\npublic interface ICompositionRoot\n{\n    /// <summary>\n    /// Composes services through the <see cref=\"CollectionRegistratorExtensions.ComposeBy{TCompositionRoot}\"/>, <see cref=\"IDependencyCollectionRegistrator.ComposeBy(System.Type, object[])\"/>, <see cref=\"CollectionRegistratorExtensions.ComposeAssembly\"/>, and <see cref=\"CollectionRegistratorExtensions.ComposeAssemblies\"/> methods.\n    /// </summary>\n    /// <param name=\"container\">The <see cref=\"IStashboxContainer\"/>.</param>\n    void Compose(IStashboxContainer container);\n}"
  },
  {
    "path": "src/IContainerContext.cs",
    "content": "﻿using Stashbox.Configuration;\nusing Stashbox.Registration;\nusing Stashbox.Resolution;\n\nnamespace Stashbox;\n\n/// <summary>\n/// Represents the container context.\n/// </summary>\npublic interface IContainerContext\n{\n    /// <summary>\n    /// The service registration repository.\n    /// </summary>\n    IRegistrationRepository RegistrationRepository { get; }\n\n    /// <summary>\n    /// The service decorator registration repository.\n    /// </summary>\n    IDecoratorRepository DecoratorRepository { get; }\n\n    /// <summary>\n    /// The parent container context.\n    /// </summary>\n    IContainerContext? ParentContext { get; }\n\n    /// <summary>\n    /// The resolution strategy.\n    /// </summary>\n    IResolutionStrategy ResolutionStrategy { get; }\n\n    /// <summary>\n    /// The parent container context.\n    /// </summary>\n    IResolutionScope RootScope { get; }\n\n    /// <summary>\n    /// The container configuration.\n    /// </summary>\n    ContainerConfiguration ContainerConfiguration { get; }\n}"
  },
  {
    "path": "src/IDecoratorRegistrator.cs",
    "content": "﻿using Stashbox.Registration.Fluent;\nusing System;\n\nnamespace Stashbox;\n\n/// <summary>\n/// Represents a decorator registrator.\n/// </summary>\npublic interface IDecoratorRegistrator\n{\n    /// <summary>\n    /// Registers a decorator service into the container.\n    /// </summary>\n    /// <param name=\"typeFrom\">The service type.</param>\n    /// <param name=\"typeTo\">The implementation type.</param>\n    /// <param name=\"configurator\">The configurator for the registered types.</param>\n    /// <returns>The <see cref=\"IStashboxContainer\"/> instance.</returns>\n    IStashboxContainer RegisterDecorator(Type typeFrom, Type typeTo, Action<DecoratorConfigurator>? configurator = null);\n\n    /// <summary>\n    /// Registers a decorator service into the container.\n    /// </summary>\n    /// <typeparam name=\"TFrom\">The service type.</typeparam>\n    /// <typeparam name=\"TTo\">The implementation type.</typeparam>\n    /// <param name=\"configurator\">The configurator for the registered types.</param>\n    /// <returns>The <see cref=\"IStashboxContainer\"/> instance.</returns>\n    IStashboxContainer RegisterDecorator<TFrom, TTo>(Action<DecoratorConfigurator<TFrom, TTo>>? configurator = null)\n        where TFrom : class\n        where TTo : class, TFrom;\n\n    /// <summary>\n    /// Registers a decorator service into the container. \n    /// This function configures the registration with the <see cref=\"BaseFluentConfigurator{T}.AsImplementedTypes()\"/> option.\n    /// </summary>\n    /// <param name=\"typeTo\">The implementation type.</param>\n    /// <param name=\"configurator\">The configurator for the registered types.</param>\n    /// <returns>The <see cref=\"IStashboxContainer\"/> instance.</returns>\n    IStashboxContainer RegisterDecorator(Type typeTo, Action<DecoratorConfigurator>? configurator = null);\n\n    /// <summary>\n    /// Registers a decorator service into the container. \n    /// This function configures the registration with the <see cref=\"BaseFluentConfigurator{T}.AsImplementedTypes()\"/> option.\n    /// </summary>\n    /// <typeparam name=\"TTo\">The implementation type.</typeparam>\n    /// <param name=\"configurator\">The configurator for the registered types.</param>\n    /// <returns>The <see cref=\"IStashboxContainer\"/> instance.</returns>\n    IStashboxContainer RegisterDecorator<TTo>(Action<DecoratorConfigurator<TTo, TTo>>? configurator = null)\n        where TTo : class;\n\n    /// <summary>\n    /// Registers a decorator service into the container.\n    /// </summary>\n    /// <typeparam name=\"TFrom\">The service type.</typeparam>\n    /// <param name=\"typeTo\">The implementation type.</param>\n    /// <param name=\"configurator\">The configurator for the registered types.</param>\n    /// <returns>The <see cref=\"IStashboxContainer\"/> instance.</returns>\n    IStashboxContainer RegisterDecorator<TFrom>(Type typeTo,\n        Action<DecoratorConfigurator<TFrom, TFrom>>? configurator = null)\n        where TFrom : class;\n}"
  },
  {
    "path": "src/IDependencyCollectionRegistrator.cs",
    "content": "﻿using Stashbox.Registration.Fluent;\nusing System;\nusing System.Collections.Generic;\n\nnamespace Stashbox;\n\n/// <summary>\n/// Represents a dependency collection registrator.\n/// </summary>\npublic interface IDependencyCollectionRegistrator\n{\n    /// <summary>\n    /// Registers a collection of types mapped to a service type.\n    /// </summary>\n    /// <param name=\"typeFrom\">The service type.</param>\n    /// <param name=\"types\">Types to register.</param>\n    /// <param name=\"selector\">The type selector. Used to filter which types should be excluded/included in the registration process.</param>\n    /// <param name=\"configurator\">The configurator for the registered types.</param>\n    /// <returns>The <see cref=\"IStashboxContainer\"/> instance.</returns>\n    IStashboxContainer RegisterTypesAs(Type typeFrom,\n        IEnumerable<Type> types,\n        Func<Type, bool>? selector = null,\n        Action<RegistrationConfigurator>? configurator = null);\n\n    /// <summary>\n    /// Registers a collection of types into the container.\n    /// </summary>\n    /// <param name=\"types\">Types to register.</param>\n    /// <param name=\"selector\">The type selector. Used to filter which types should be excluded/included in the registration process.</param>\n    /// <param name=\"serviceTypeSelector\">The service type selector. Used to filter which interface or base types the implementation should be mapped to.</param>\n    /// <param name=\"registerSelf\">If it's true, the types will be registered to their own type too.</param>\n    /// <param name=\"configurator\">The configurator for the registered types.</param>\n    /// <returns>The <see cref=\"IStashboxContainer\"/> instance.</returns>\n    IStashboxContainer RegisterTypes(IEnumerable<Type> types,\n        Func<Type, bool>? selector = null,\n        Func<Type, Type, bool>? serviceTypeSelector = null,\n        bool registerSelf = true,\n        Action<RegistrationConfigurator>? configurator = null);\n\n    /// <summary>\n    /// Composes services by calling the <see cref=\"ICompositionRoot.Compose\"/> method of the given root.\n    /// </summary>\n    /// <param name=\"compositionRootType\">The type of an <see cref=\"ICompositionRoot\"/> implementation.</param>\n    /// <param name=\"compositionRootArguments\">Optional composition root constructor arguments.</param>\n    /// <returns>The <see cref=\"IStashboxContainer\"/> instance.</returns>\n    IStashboxContainer ComposeBy(Type compositionRootType,\n        params object[] compositionRootArguments);\n\n    /// <summary>\n    /// Composes services by calling the <see cref=\"ICompositionRoot.Compose\"/> method of the given root.\n    /// </summary>\n    /// <param name=\"compositionRoot\">The composition root instance.</param>\n    /// <returns>The <see cref=\"IStashboxContainer\"/> instance.</returns>\n    IStashboxContainer ComposeBy(ICompositionRoot compositionRoot);\n}"
  },
  {
    "path": "src/IDependencyReMapper.cs",
    "content": "﻿using Stashbox.Registration.Fluent;\nusing System;\n\nnamespace Stashbox;\n\n/// <summary>\n/// Represents a dependency remapper.\n/// </summary>\npublic interface IDependencyReMapper\n{\n    /// <summary>\n    /// Replaces an existing registration mapping.\n    /// </summary>\n    /// <typeparam name=\"TFrom\">The service type to re-map.</typeparam>\n    /// <typeparam name=\"TTo\">The implementation type to re-map.</typeparam>\n    /// <param name=\"configurator\">The configurator for the registered types.</param>\n    /// <returns>The <see cref=\"IStashboxContainer\"/> instance.</returns>\n    IStashboxContainer ReMap<TFrom, TTo>(Action<RegistrationConfigurator<TFrom, TTo>>? configurator = null)\n        where TFrom : class\n        where TTo : class, TFrom;\n\n    /// <summary>\n    /// Replaces an existing registration mapping.\n    /// </summary>\n    /// <typeparam name=\"TFrom\">The service type to re-map.</typeparam>\n    /// <param name=\"typeTo\">The implementation type to re-map.</param>\n    /// <param name=\"configurator\">The configurator for the registered types.</param>\n    /// <returns>The <see cref=\"IStashboxContainer\"/> instance.</returns>\n    IStashboxContainer ReMap<TFrom>(Type typeTo, Action<RegistrationConfigurator<TFrom, TFrom>>? configurator = null)\n        where TFrom : class;\n\n    /// <summary>\n    /// Replaces an existing registration mapping.\n    /// </summary>\n    /// <param name=\"typeFrom\">The service type to re-map.</param>\n    /// <param name=\"typeTo\">The implementation type to re-map.</param>\n    /// <param name=\"configurator\">The configurator for the registered types.</param>\n    /// <returns>The <see cref=\"IStashboxContainer\"/> instance.</returns>\n    IStashboxContainer ReMap(Type typeFrom, Type typeTo, Action<RegistrationConfigurator>? configurator = null);\n\n    /// <summary>\n    /// Replaces an existing registration mapping.\n    /// </summary>\n    /// <typeparam name=\"TTo\">The service/implementation type to re-map.</typeparam>\n    /// <param name=\"configurator\">The configurator for the registered types.</param>\n    /// <returns>The <see cref=\"IStashboxContainer\"/> instance.</returns>\n    IStashboxContainer ReMap<TTo>(Action<RegistrationConfigurator<TTo, TTo>>? configurator = null)\n        where TTo : class;\n\n    /// <summary>\n    /// Replaces an existing decorator mapping.\n    /// </summary>\n    /// <param name=\"typeFrom\">The service type to re-map.</param>\n    /// <param name=\"typeTo\">The implementation type to re-map.</param>\n    /// <param name=\"configurator\">The configurator for the registered types.</param>\n    /// <returns>The <see cref=\"IStashboxContainer\"/> instance.</returns>\n    IStashboxContainer ReMapDecorator(Type typeFrom, Type typeTo, Action<DecoratorConfigurator>? configurator = null);\n\n    /// <summary>\n    /// Replaces an existing decorator mapping.\n    /// </summary>\n    /// <typeparam name=\"TFrom\">The service type to re-map.</typeparam>\n    /// <typeparam name=\"TTo\">The implementation type to re-map.</typeparam>\n    /// <param name=\"configurator\">The configurator for the registered types.</param>\n    /// <returns>The <see cref=\"IStashboxContainer\"/> instance.</returns>\n    IStashboxContainer ReMapDecorator<TFrom, TTo>(Action<DecoratorConfigurator<TFrom, TTo>>? configurator = null)\n        where TFrom : class\n        where TTo : class, TFrom;\n\n    /// <summary>\n    /// Replaces an existing decorator mapping.\n    /// </summary>\n    /// <typeparam name=\"TFrom\">The service type to re-map.</typeparam>\n    /// <param name=\"typeTo\">The implementation type to re-map.</param>\n    /// <param name=\"configurator\">The configurator for the registered types.</param>\n    /// <returns>The <see cref=\"IStashboxContainer\"/> instance.</returns>\n    IStashboxContainer ReMapDecorator<TFrom>(Type typeTo, Action<DecoratorConfigurator<TFrom, TFrom>>? configurator = null)\n        where TFrom : class;\n}"
  },
  {
    "path": "src/IDependencyRegistrator.cs",
    "content": "﻿using Stashbox.Registration.Fluent;\nusing System;\n\nnamespace Stashbox;\n\n/// <summary>\n/// Represents a dependency registrator.\n/// </summary>\npublic interface IDependencyRegistrator\n{\n    /// <summary>\n    /// Registers a service into the container.\n    /// </summary>\n    /// <typeparam name=\"TFrom\">The service type.</typeparam>\n    /// <typeparam name=\"TTo\">The implementation type.</typeparam>\n    /// <returns>The <see cref=\"IStashboxContainer\"/> instance.</returns>\n    IStashboxContainer Register<TFrom, TTo>(Action<RegistrationConfigurator<TFrom, TTo>> configurator)\n        where TFrom : class\n        where TTo : class, TFrom;\n\n    /// <summary>\n    /// Registers a service into the container with a name.\n    /// </summary>\n    /// <typeparam name=\"TFrom\">The service type.</typeparam>\n    /// <typeparam name=\"TTo\">The implementation type.</typeparam>\n    /// <param name=\"name\">The name of the registration.</param>\n    /// <returns>The <see cref=\"IStashboxContainer\"/> instance.</returns>\n    IStashboxContainer Register<TFrom, TTo>(object? name = null)\n        where TFrom : class\n        where TTo : class, TFrom;\n\n    /// <summary>\n    /// Registers a service into the container.\n    /// </summary>\n    /// <typeparam name=\"TFrom\">The service type.</typeparam>\n    /// <param name=\"typeTo\">The implementation type.</param>\n    /// <param name=\"configurator\">The configurator for the registered types.</param>\n    /// <returns>The <see cref=\"IStashboxContainer\"/> instance.</returns>\n    IStashboxContainer Register<TFrom>(Type typeTo, Action<RegistrationConfigurator<TFrom, TFrom>>? configurator = null)\n        where TFrom : class;\n\n    /// <summary>\n    /// Registers a service into the container.\n    /// </summary>\n    /// <param name=\"typeFrom\">The service type.</param>\n    /// <param name=\"typeTo\">The implementation type.</param>\n    /// <param name=\"configurator\">The configurator for the registered types.</param>\n    /// <returns>The <see cref=\"IStashboxContainer\"/> instance.</returns>\n    IStashboxContainer Register(Type typeFrom, Type typeTo, Action<RegistrationConfigurator>? configurator = null);\n\n    /// <summary>\n    /// Registers a service into the container.\n    /// </summary>\n    /// <typeparam name=\"TTo\">The service/implementation type.</typeparam>\n    /// <param name=\"configurator\">The configurator for the registered types.</param>\n    /// <returns>The <see cref=\"IStashboxContainer\"/> instance.</returns>\n    IStashboxContainer Register<TTo>(Action<RegistrationConfigurator<TTo, TTo>> configurator)\n        where TTo : class;\n\n    /// <summary>\n    /// Registers a service into the container.\n    /// </summary>\n    /// <typeparam name=\"TTo\">The service/implementation type.</typeparam>\n    /// <param name=\"name\">The name of the registration.</param>\n    /// <returns>The <see cref=\"IStashboxContainer\"/> instance.</returns>\n    IStashboxContainer Register<TTo>(object? name = null)\n        where TTo : class;\n\n    /// <summary>\n    /// Registers a service into the container.\n    /// </summary>\n    /// <param name=\"typeTo\">The service/implementation type.</param>\n    /// <param name=\"configurator\">The configurator for the registered types.</param>\n    /// <returns>The <see cref=\"IStashboxContainer\"/> instance.</returns>\n    IStashboxContainer Register(Type typeTo, Action<RegistrationConfigurator>? configurator = null);\n\n    /// <summary>\n    /// Registers a named service with singleton lifetime.\n    /// </summary>\n    /// <typeparam name=\"TFrom\">The service type.</typeparam>\n    /// <typeparam name=\"TTo\">The implementation type.</typeparam>\n    /// <param name=\"name\">The name of the registration.</param>\n    /// <returns>The <see cref=\"IStashboxContainer\"/> instance.</returns>\n    IStashboxContainer RegisterSingleton<TFrom, TTo>(object? name = null)\n        where TFrom : class\n        where TTo : class, TFrom;\n\n    /// <summary>\n    /// Registers a named service with singleton lifetime.\n    /// </summary>\n    /// <typeparam name=\"TTo\">The service/implementation type.</typeparam>\n    /// <param name=\"name\">The name of the registration.</param>\n    /// <returns>The <see cref=\"IStashboxContainer\"/> instance.</returns>\n    IStashboxContainer RegisterSingleton<TTo>(object? name = null)\n        where TTo : class;\n\n    /// <summary>\n    /// Registers a named service with singleton lifetime.\n    /// </summary>\n    /// <param name=\"typeFrom\">The service type.</param>\n    /// <param name=\"typeTo\">The implementation type.</param>\n    /// <param name=\"name\">The name of the registration.</param>\n    /// <returns>The <see cref=\"IStashboxContainer\"/> instance.</returns>\n    IStashboxContainer RegisterSingleton(Type typeFrom, Type typeTo, object? name = null);\n\n    /// <summary>\n    /// Registers a named service with scoped lifetime.\n    /// </summary>\n    /// <typeparam name=\"TFrom\">The service type.</typeparam>\n    /// <typeparam name=\"TTo\">The implementation type.</typeparam>\n    /// <param name=\"name\">The name of the registration.</param>\n    /// <returns>The <see cref=\"IStashboxContainer\"/> instance.</returns>\n    IStashboxContainer RegisterScoped<TFrom, TTo>(object? name = null)\n        where TFrom : class\n        where TTo : class, TFrom;\n\n    /// <summary>\n    /// Registers a named service with scoped lifetime.\n    /// </summary>\n    /// <param name=\"typeFrom\">The service type.</param>\n    /// <param name=\"typeTo\">The implementation type.</param>\n    /// <param name=\"name\">The name of the registration.</param>\n    /// <returns>The <see cref=\"IStashboxContainer\"/> instance.</returns>\n    IStashboxContainer RegisterScoped(Type typeFrom, Type typeTo, object? name = null);\n\n    /// <summary>\n    /// Registers a named service with scoped lifetime.\n    /// </summary>\n    /// <typeparam name=\"TTo\">The implementation type.</typeparam>\n    /// <param name=\"name\">The name of the registration.</param>\n    /// <returns>The <see cref=\"IStashboxContainer\"/> instance.</returns>\n    IStashboxContainer RegisterScoped<TTo>(object? name = null)\n        where TTo : class;\n\n    /// <summary>\n    /// Registers an already constructed instance into the container.\n    /// </summary>\n    /// <typeparam name=\"TInstance\">The service type.</typeparam>\n    /// <param name=\"instance\">The constructed instance.</param>\n    /// <param name=\"name\">The name of the registration.</param>\n    /// <param name=\"withoutDisposalTracking\">If it's set to true the container will exclude the instance from disposal tracking.</param>\n    /// <param name=\"finalizerDelegate\">The cleanup delegate to call before dispose.</param>\n    /// <returns>The <see cref=\"IStashboxContainer\"/> instance.</returns>\n    IStashboxContainer RegisterInstance<TInstance>(TInstance instance, object? name = null, bool withoutDisposalTracking = false, Action<TInstance>? finalizerDelegate = null)\n        where TInstance : class;\n\n    /// <summary>\n    /// Registers an already constructed instance into the container.\n    /// </summary>\n    /// <param name=\"instance\">The constructed instance.</param>\n    /// <param name=\"serviceType\">The service type.</param>\n    /// <param name=\"name\">The name of the registration.</param>\n    /// <param name=\"withoutDisposalTracking\">If it's set to true the container will exclude the instance from disposal tracking.</param>\n    /// <returns>The <see cref=\"IStashboxContainer\"/> instance.</returns>\n    IStashboxContainer RegisterInstance(object instance, Type serviceType, object? name = null, bool withoutDisposalTracking = false);\n\n    /// <summary>\n    /// Registers an already constructed instance, but the container will perform injections and extensions on it.\n    /// </summary>\n    /// <typeparam name=\"TInstance\">The service type.</typeparam>\n    /// <param name=\"instance\">The constructed instance.</param>\n    /// <param name=\"name\">The name of the registration.</param>\n    /// <param name=\"withoutDisposalTracking\">If it's set to true the container will exclude the instance from disposal tracking.</param>\n    /// <param name=\"finalizerDelegate\">The cleanup delegate to call before dispose.</param>\n    /// <returns>The <see cref=\"IStashboxContainer\"/> instance.</returns>\n    IStashboxContainer WireUp<TInstance>(TInstance instance, object? name = null, bool withoutDisposalTracking = false, Action<TInstance>? finalizerDelegate = null)\n        where TInstance : class;\n\n    /// <summary>\n    /// Registers an already constructed instance, but the container will perform injections and extensions on it.\n    /// </summary>\n    /// <param name=\"instance\">The constructed instance.</param>\n    /// <param name=\"serviceType\">The service type.</param>\n    /// <param name=\"name\">The name of the registration.</param>\n    /// <param name=\"withoutDisposalTracking\">If it's set to true the container will exclude the instance from disposal tracking.</param>\n    /// <returns>The <see cref=\"IStashboxContainer\"/> instance.</returns>\n    IStashboxContainer WireUp(object instance, Type serviceType, object? name = null, bool withoutDisposalTracking = false);\n}"
  },
  {
    "path": "src/IDependencyResolver.cs",
    "content": "﻿using Stashbox.Resolution;\nusing System;\nusing System.Collections.Generic;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace Stashbox;\n\n/// <summary>\n/// Represents a dependency resolver.\n/// </summary>\npublic interface IDependencyResolver : IServiceProvider,\n#if HAS_ASYNC_DISPOSABLE\n        IAsyncDisposable,\n#endif\n    IDisposable\n{\n    /// <summary>\n    /// Resolves an instance from the container.\n    /// </summary>\n    /// <param name=\"typeFrom\">The type of the requested service.</param>\n    /// <returns>The resolved object.</returns>\n    object Resolve(Type typeFrom);\n\n    /// <summary>\n    /// Resolves a named instance from the container with dependency overrides.\n    /// </summary>\n    /// <param name=\"typeFrom\">The type of the requested service.</param>\n    /// <param name=\"name\">The name of the requested service.</param>\n    /// <param name=\"dependencyOverrides\">A collection of objects which are used to override certain dependencies of the requested service.</param>\n    /// <param name=\"resolutionBehavior\">The resolution behavior.</param>\n    /// <returns>The resolved object.</returns>\n    object Resolve(Type typeFrom, object? name, object[]? dependencyOverrides, ResolutionBehavior resolutionBehavior = ResolutionBehavior.Default);\n\n    /// <summary>\n    /// Resolves an instance from the container or returns default if the type is not resolvable.\n    /// </summary>\n    /// <param name=\"typeFrom\">The type of the requested service.</param>\n    /// <returns>The resolved object.</returns>\n    object? ResolveOrDefault(Type typeFrom);\n    \n    /// <summary>\n    /// Resolves an instance from the container with dependency overrides or returns default if the type is not resolvable.\n    /// </summary>\n    /// <param name=\"typeFrom\">The type of the requested service.</param>\n    /// <param name=\"name\">The name of the requested service.</param>\n    /// <param name=\"dependencyOverrides\">A collection of objects which are used to override certain dependencies of the requested service.</param>\n    /// <param name=\"resolutionBehavior\">The resolution behavior.</param>\n    /// <returns>The resolved object.</returns>\n    object? ResolveOrDefault(Type typeFrom, object? name, object[]? dependencyOverrides, ResolutionBehavior resolutionBehavior = ResolutionBehavior.Default);\n\n    /// <summary>\n    /// Returns a factory delegate that can be used to activate the service.\n    /// </summary>\n    /// <param name=\"typeFrom\">The type of the requested instances.</param>\n    /// <param name=\"name\">The name of the requested registration.</param>\n    /// <param name=\"resolutionBehavior\">The resolution behavior.</param>\n    /// <param name=\"parameterTypes\">The parameter type.</param>\n    /// <returns>The factory delegate.</returns>\n    Delegate ResolveFactory(Type typeFrom, object? name = null, ResolutionBehavior resolutionBehavior = ResolutionBehavior.Default, params Type[] parameterTypes);\n\n    /// <summary>\n    /// Returns a factory delegate that can be used to activate the service or returns default if the type is not resolvable.\n    /// </summary>\n    /// <param name=\"typeFrom\">The type of the requested instances.</param>\n    /// <param name=\"name\">The name of the requested registration.</param>\n    /// <param name=\"resolutionBehavior\">The resolution behavior.</param>\n    /// <param name=\"parameterTypes\">The parameter type.</param>\n    /// <returns>The factory delegate.</returns>\n    Delegate? ResolveFactoryOrDefault(Type typeFrom, object? name = null, ResolutionBehavior resolutionBehavior = ResolutionBehavior.Default, params Type[] parameterTypes);\n\n    /// <summary>\n    /// Creates a new scope.\n    /// </summary>\n    /// <param name=\"name\">The name of the scope.</param>\n    /// <param name=\"attachToParent\">If true, the new scope will be attached to the lifecycle of its parent scope. When the parent is being disposed, the new scope will be disposed with it.</param>\n    /// <returns>The created scope.</returns>\n    IDependencyResolver BeginScope(object? name = null, bool attachToParent = false);\n\n    /// <summary>\n    /// Puts an instance into the scope. The instance will be disposed along with the scope disposal.\n    /// </summary>\n    /// <param name=\"typeFrom\">The service type.</param>\n    /// <param name=\"instance\">The instance.</param>\n    /// <param name=\"withoutDisposalTracking\">If it's set to true the container will exclude the instance from disposal tracking.</param>\n    /// <param name=\"name\">The dependency name of the instance.</param>\n    /// <returns>The scope.</returns>\n    void PutInstanceInScope(Type typeFrom, object instance, bool withoutDisposalTracking = false, object? name = null);\n\n    /// <summary>\n    /// Builds up an existing instance. This means the container performs member and method injections on it without registering it into the container.\n    /// </summary>\n    /// <typeparam name=\"TTo\">The type of the requested instance.</typeparam>\n    /// <param name=\"instance\">The instance to build up.</param>\n    /// <param name=\"resolutionBehavior\">The resolution behavior.</param>\n    /// <returns>The built object.</returns>\n    TTo BuildUp<TTo>(TTo instance, ResolutionBehavior resolutionBehavior = ResolutionBehavior.Default)\n        where TTo : class;\n\n    /// <summary>\n    /// Activates an object without registering it into the container. If you want to resolve a\n    /// registered service use the <see cref=\"Resolve(Type)\" /> method instead.\n    /// </summary>\n    /// <param name=\"type\">The type to activate.</param>\n    /// <param name=\"resolutionBehavior\">The resolution behavior.</param>\n    /// <param name=\"arguments\">Optional dependency overrides.</param>\n    /// <returns>The built object.</returns>\n    object Activate(Type type, ResolutionBehavior resolutionBehavior, params object[] arguments);\n\n    /// <summary>\n    /// Calls the registered asynchronous initializers of all resolved objects.\n    /// </summary>\n    /// <param name=\"token\">The cancellation token.</param>\n    /// <returns>The initializer task.</returns>\n    ValueTask InvokeAsyncInitializers(CancellationToken token = default);\n\n    /// <summary>\n    /// Checks whether a type can be resolved by the container, or not.\n    /// </summary>\n    /// <param name=\"typeFrom\">The service type.</param>\n    /// <param name=\"name\">The registration name.</param>\n    /// <param name=\"resolutionBehavior\">The resolution behavior.</param>\n    /// <returns>True if the service can be resolved, otherwise false.</returns>\n    bool CanResolve(Type typeFrom, object? name = null, ResolutionBehavior resolutionBehavior = ResolutionBehavior.Default);\n\n    /// <summary>\n    /// Returns all cached service resolution delegates.\n    /// </summary>\n    /// <returns>The service resolution delegates.</returns>\n    IEnumerable<DelegateCacheEntry> GetDelegateCacheEntries();\n}"
  },
  {
    "path": "src/IFuncRegistrator.cs",
    "content": "﻿using System;\n\nnamespace Stashbox;\n\n/// <summary>\n/// Represents a factory registrator.\n/// </summary>\npublic interface IFuncRegistrator\n{\n    /// <summary>\n    /// Registers a service with a factory resolver.\n    /// </summary>\n    /// <typeparam name=\"TService\">The service type.</typeparam>\n    /// <param name=\"factory\">The factory delegate.</param>\n    /// <param name=\"name\">The name of the factory registration.</param>\n    /// <returns>The <see cref=\"IStashboxContainer\"/> instance.</returns>\n    IStashboxContainer RegisterFunc<TService>(Func<IDependencyResolver, TService> factory, object? name = null);\n\n    /// <summary>\n    /// Registers a service with a factory resolver.\n    /// </summary>\n    /// <typeparam name=\"T1\">The first parameter of the factory.</typeparam>\n    /// <typeparam name=\"TService\">The service type.</typeparam>\n    /// <param name=\"factory\">The factory delegate.</param>\n    /// <param name=\"name\">The name of the factory registration.</param>\n    /// <returns>The <see cref=\"IStashboxContainer\"/> instance.</returns>\n    IStashboxContainer RegisterFunc<T1, TService>(Func<T1, IDependencyResolver, TService> factory, object? name = null);\n\n    /// <summary>\n    /// Registers a service with a factory resolver.\n    /// </summary>\n    /// <typeparam name=\"T1\">The first parameter of the factory.</typeparam>\n    /// <typeparam name=\"T2\">The second parameter of the factory.</typeparam>\n    /// <typeparam name=\"TService\">The service type.</typeparam>\n    /// <param name=\"factory\">The factory delegate.</param>\n    /// <param name=\"name\">The name of the factory registration.</param>\n    /// <returns>The <see cref=\"IStashboxContainer\"/> instance.</returns>\n    IStashboxContainer RegisterFunc<T1, T2, TService>(Func<T1, T2, IDependencyResolver, TService> factory, object? name = null);\n\n    /// <summary>\n    /// Registers a service with a factory resolver.\n    /// </summary>\n    /// <typeparam name=\"T1\">The first parameter of the factory.</typeparam>\n    /// <typeparam name=\"T2\">The second parameter of the factory.</typeparam>\n    /// <typeparam name=\"T3\">The third parameter of the factory.</typeparam>\n    /// <typeparam name=\"TService\">The service type.</typeparam>\n    /// <param name=\"factory\">The factory delegate.</param>\n    /// <param name=\"name\">The name of the factory registration.</param>\n    /// <returns>The <see cref=\"IStashboxContainer\"/> instance.</returns>\n    IStashboxContainer RegisterFunc<T1, T2, T3, TService>(Func<T1, T2, T3, IDependencyResolver, TService> factory, object? name = null);\n\n    /// <summary>\n    /// Registers a service with a factory resolver.\n    /// </summary>\n    /// <typeparam name=\"T1\">The first parameter of the factory.</typeparam>\n    /// <typeparam name=\"T2\">The second parameter of the factory.</typeparam>\n    /// <typeparam name=\"T3\">The third parameter of the factory.</typeparam>\n    /// <typeparam name=\"T4\">The fourth parameter of the factory.</typeparam>\n    /// <typeparam name=\"TService\">The service type.</typeparam>\n    /// <param name=\"factory\">The factory delegate.</param>\n    /// <param name=\"name\">The name of the factory registration.</param>\n    /// <returns>The <see cref=\"IStashboxContainer\"/> instance.</returns>\n    IStashboxContainer RegisterFunc<T1, T2, T3, T4, TService>(Func<T1, T2, T3, T4, IDependencyResolver, TService> factory, object? name = null);\n}"
  },
  {
    "path": "src/IResolutionScope.cs",
    "content": "﻿using Stashbox.Resolution;\nusing System;\nusing System.Collections.Generic;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace Stashbox;\n\n/// <summary>\n/// Represents a resolution scope.\n/// </summary>\npublic interface IResolutionScope : IDependencyResolver\n{\n    /// <summary>\n    /// The parent scope.\n    /// </summary>\n    IResolutionScope? ParentScope { get; }\n\n    /// <summary>\n    /// The name of the scope, if it's null then it's a regular nameless scope.\n    /// </summary>\n    object? Name { get; }\n\n    /// <summary>\n    /// Adds a service to dispose tracking.\n    /// </summary>\n    /// <param name=\"disposable\">The <see cref=\"IDisposable\"/> object.</param>\n    /// <returns>The <see cref=\"IDisposable\"/> object.</returns>\n    object AddDisposableTracking(object disposable);\n\n    /// <summary>\n    /// Adds a service to dispose tracking.\n    /// </summary>\n    /// <param name=\"disposable\">The <see cref=\"IDisposable\"/> object.</param>\n    /// <param name=\"requestContext\">The request context.</param>\n    /// <returns>The <see cref=\"IDisposable\"/> object.</returns>\n    object AddRequestContextAwareDisposableTracking(object disposable, IRequestContext requestContext);\n\n    /// <summary>\n    /// Adds a service with a cleanup delegate.\n    /// </summary>\n    /// <param name=\"finalizable\">The object to cleanup.</param>\n    /// <param name=\"finalizer\">The cleanup delegate.</param>\n    /// <returns>The object to cleanup.</returns>\n    object AddWithFinalizer(object finalizable, Action<object> finalizer);\n\n    /// <summary>\n    /// Adds a service with an async initializer delegate.\n    /// </summary>\n    /// <param name=\"initializable\">The object to initialize.</param>\n    /// <param name=\"initializer\">The async initializer delegate.</param>\n    /// <returns>The object to initialize.</returns>\n    object AddWithAsyncInitializer(object initializable, Func<object, IDependencyResolver, CancellationToken, Task> initializer);\n\n    /// <summary>\n    /// Returns an existing scoped object or adds it into the scope if it doesn't exist.\n    /// </summary>\n    /// <param name=\"key\">The key.</param>\n    /// <param name=\"factory\">The value factory used to create the object if it doesn't exist yet.</param>\n    /// <param name=\"requestContext\">The request context.</param>\n    /// <param name=\"serviceType\">The type of the service.</param>\n    /// <returns>The scoped object.</returns>\n    object GetOrAddScopedObject(int key, Func<IResolutionScope, IRequestContext, object> factory,\n        IRequestContext requestContext, Type serviceType);\n\n    /// <summary>\n    /// Invalidates the delegate cache.\n    /// </summary>\n    void InvalidateDelegateCache();\n\n    /// <summary>\n    /// Gets the names of the already opened scopes.\n    /// </summary>\n    /// <returns>The scope names.</returns>\n    IEnumerable<object> GetActiveScopeNames();\n}"
  },
  {
    "path": "src/IStashboxContainer.cs",
    "content": "﻿using Stashbox.Configuration;\nusing Stashbox.Registration;\nusing Stashbox.Resolution;\nusing System;\nusing System.Collections.Generic;\n\nnamespace Stashbox;\n\n/// <summary>\n/// Represents a dependency injection container.\n/// </summary>\npublic interface IStashboxContainer : IDependencyRegistrator, IDependencyResolver, IDependencyReMapper, IDependencyCollectionRegistrator, IDecoratorRegistrator, IFuncRegistrator\n{\n    /// <summary>\n    /// The container context.\n    /// </summary>\n    IContainerContext ContainerContext { get; }\n    \n    /// <summary>\n    /// Child containers created by this container.\n    /// </summary>\n    IEnumerable<ReadOnlyKeyValue<object, IStashboxContainer>> ChildContainers { get; }\n\n    /// <summary>\n    /// Registers an <see cref=\"IResolver\"/>.\n    /// </summary>\n    /// <param name=\"resolver\">The resolver implementation.</param>\n    /// <returns>The container itself.</returns>\n    IStashboxContainer RegisterResolver(IResolver resolver);\n\n    /// <summary>\n    /// Creates a child container.\n    /// </summary>\n    /// <param name=\"config\">The action delegate which will configure the child container.</param>\n    /// <param name=\"attachToParent\">If true, the new child container will be attached to the lifecycle of its parent. When the parent is being disposed, the child will be disposed with it.</param>\n    IStashboxContainer CreateChildContainer(Action<ContainerConfigurator>? config = null, bool attachToParent = true);\n    \n    /// <summary>\n    /// Creates a child container.\n    /// </summary>\n    /// <param name=\"identifier\">The identifier of the child container.</param>\n    /// <param name=\"config\">The action delegate which will configure the child container.</param>\n    /// <param name=\"attachToParent\">If true, the new child container will be attached to the lifecycle of its parent. When the parent is being disposed, the child will be disposed with it.</param>\n    IStashboxContainer CreateChildContainer(object identifier, Action<IStashboxContainer>? config = null, bool attachToParent = true);\n\n    /// <summary>\n    /// Returns the child container identified by <paramref name=\"identifier\"/>.\n    /// </summary>\n    /// <param name=\"identifier\">The identifier of the child container.</param>\n    /// <returns>The child container if it's exist, otherwise null.</returns>\n    IStashboxContainer? GetChildContainer(object identifier);\n    \n    /// <summary>\n    /// Checks whether a type is registered in the container.\n    /// </summary>\n    /// <typeparam name=\"TFrom\">The service type.</typeparam>\n    /// <param name=\"name\">The registration name.</param>\n    /// <returns>True if the service is registered, otherwise false.</returns>\n    bool IsRegistered<TFrom>(object? name = null);\n\n    /// <summary>\n    /// Checks whether a type is registered in the container.\n    /// </summary>\n    /// <param name=\"typeFrom\">The service type.</param>\n    /// <param name=\"name\">The registration name.</param>\n    /// <returns>True if the service is registered, otherwise false.</returns>\n    bool IsRegistered(Type typeFrom, object? name = null);\n\n    /// <summary>\n    /// Configures the container.\n    /// </summary>\n    /// <param name=\"config\">The action delegate which will configure the container.</param>\n    /// <returns>The container itself.</returns>\n    IStashboxContainer Configure(Action<ContainerConfigurator> config);\n\n    /// <summary>\n    /// Validates the current state of the container.\n    /// </summary>\n    void Validate();\n\n    /// <summary>\n    /// Returns all registration mappings.\n    /// </summary>\n    /// <returns>The registration mappings.</returns>\n    IEnumerable<KeyValuePair<Type, ServiceRegistration>> GetRegistrationMappings();\n\n    /// <summary>\n    /// Returns the details about the registrations.\n    /// </summary>\n    /// <returns>The detailed string representation of the registration.</returns>\n    IEnumerable<RegistrationDiagnosticsInfo> GetRegistrationDiagnostics();\n}"
  },
  {
    "path": "src/Lifetime/AutoLifetime.cs",
    "content": "using System.Linq.Expressions;\nusing Stashbox.Registration;\nusing Stashbox.Resolution;\n\nnamespace Stashbox.Lifetime;\n\ninternal class AutoLifetime(LifetimeDescriptor boundaryLifetime) : LifetimeDescriptor\n{\n    private LifetimeDescriptor selectedLifetime = boundaryLifetime;\n\n    protected internal override int LifeSpan => this.selectedLifetime.LifeSpan;\n\n    private protected override Expression? BuildLifetimeAppliedExpression(ServiceRegistration serviceRegistration,\n        ResolutionContext resolutionContext, TypeInformation typeInformation)\n    {\n        var tracker = new ResolutionContext.AutoLifetimeTracker();\n        var context = resolutionContext.BeginAutoLifetimeTrackingContext(tracker);\n        var expression = GetExpressionForRegistration(serviceRegistration, context, typeInformation);\n        this.selectedLifetime = tracker.HighestRankingLifetime.LifeSpan <= this.selectedLifetime.LifeSpan\n            ? tracker.HighestRankingLifetime\n            : this.selectedLifetime;\n\n        var func = expression?.CompileDelegate(context, context.CurrentContainerContext.ContainerConfiguration);\n        if (func == null) return null;\n\n        var final = Expression.Invoke(func.AsConstant(), context.CurrentScopeParameter, context.RequestContextParameter);\n        \n        return this.selectedLifetime.ApplyLifetimeToExpression(final, serviceRegistration, resolutionContext, typeInformation);\n    }\n\n    internal override Expression? ApplyLifetimeToExpression(Expression? expression,\n        ServiceRegistration serviceRegistration,\n        ResolutionContext resolutionContext, TypeInformation typeInformation) =>\n        this.selectedLifetime.ApplyLifetimeToExpression(expression, serviceRegistration, resolutionContext, typeInformation);\n}"
  },
  {
    "path": "src/Lifetime/EmptyLifetime.cs",
    "content": "﻿using Stashbox.Registration;\nusing Stashbox.Resolution;\nusing System.Linq.Expressions;\n\nnamespace Stashbox.Lifetime;\n\ninternal class EmptyLifetime : LifetimeDescriptor\n{\n    private protected override Expression? BuildLifetimeAppliedExpression(ServiceRegistration serviceRegistration,\n        ResolutionContext resolutionContext, TypeInformation typeInformation)\n        => null;\n\n    internal override Expression? ApplyLifetimeToExpression(Expression? expression,\n        ServiceRegistration serviceRegistration,\n        ResolutionContext resolutionContext, TypeInformation typeInformation)\n        => null;\n}"
  },
  {
    "path": "src/Lifetime/ExpressionLifetimeDescriptor.cs",
    "content": "﻿using Stashbox.Registration;\nusing Stashbox.Resolution;\nusing System;\nusing System.Linq.Expressions;\n\nnamespace Stashbox.Lifetime;\n\n/// <summary>\n/// Represents a lifetime descriptor which applies to expressions.\n/// </summary>\npublic abstract class ExpressionLifetimeDescriptor : LifetimeDescriptor\n{\n    private protected override Expression? BuildLifetimeAppliedExpression(ServiceRegistration serviceRegistration,\n        ResolutionContext resolutionContext, TypeInformation typeInformation)\n    {\n        var expression = GetExpressionForRegistration(serviceRegistration, resolutionContext, typeInformation);\n        return this.ApplyLifetimeToExpression(expression, serviceRegistration, resolutionContext, typeInformation);\n    }\n\n    internal override Expression? ApplyLifetimeToExpression(Expression? expression,\n        ServiceRegistration serviceRegistration,\n        ResolutionContext resolutionContext, TypeInformation typeInformation) => expression == null\n        ? null\n        : this.ApplyLifetime(expression, serviceRegistration, resolutionContext, typeInformation);\n\n    /// <summary>\n    /// Derived types are using this method to apply their lifetime to the instance creation.\n    /// </summary>\n    /// <param name=\"expression\">The expression the lifetime should apply to.</param>\n    /// <param name=\"serviceRegistration\">The service registration.</param>\n    /// <param name=\"resolutionContext\">The info about the actual resolution.</param>\n    /// <param name=\"typeInformation\">The type information of the resolved service.</param>\n    /// <returns>The lifetime managed expression.</returns>\n    protected abstract Expression ApplyLifetime(Expression expression, ServiceRegistration serviceRegistration,\n        ResolutionContext resolutionContext, TypeInformation typeInformation);\n}"
  },
  {
    "path": "src/Lifetime/FactoryLifetimeDescriptor.cs",
    "content": "﻿using Stashbox.Registration;\nusing Stashbox.Resolution;\nusing System;\nusing System.Linq.Expressions;\n\nnamespace Stashbox.Lifetime;\n\n/// <summary>\n/// Represents a lifetime descriptor which applies to factory delegates.\n/// </summary>\npublic abstract class FactoryLifetimeDescriptor : LifetimeDescriptor\n{\n    private protected override Expression? BuildLifetimeAppliedExpression(ServiceRegistration serviceRegistration,\n        ResolutionContext resolutionContext, TypeInformation typeInformation)\n    {\n        var factory = GetFactoryDelegateForRegistration(serviceRegistration, resolutionContext, typeInformation);\n        return factory == null ? null : this.ApplyLifetime(factory, serviceRegistration, resolutionContext, typeInformation);\n    }\n    \n    internal override Expression? ApplyLifetimeToExpression(Expression? expression,\n        ServiceRegistration serviceRegistration,\n        ResolutionContext resolutionContext, TypeInformation typeInformation) => expression == null\n        ? null\n        : this.ApplyLifetime(expression.CompileDelegate(resolutionContext, resolutionContext.CurrentContainerContext.ContainerConfiguration), \n            serviceRegistration, resolutionContext, typeInformation);\n\n    private static Func<IResolutionScope, IRequestContext, object>? GetFactoryDelegateForRegistration(ServiceRegistration serviceRegistration,\n        ResolutionContext resolutionContext, TypeInformation typeInformation)\n    {\n        if (!IsRegistrationOutputCacheable(serviceRegistration, resolutionContext))\n            return GetNewFactoryDelegate(serviceRegistration, resolutionContext.BeginSubGraph(), typeInformation);\n\n        var factory = resolutionContext.FactoryCache.GetOrDefault(serviceRegistration.RegistrationId);\n        if (factory != null)\n            return factory;\n\n        factory = GetNewFactoryDelegate(serviceRegistration, resolutionContext.BeginSubGraph(), typeInformation);\n        if (factory == null)\n            return null;\n\n        resolutionContext.FactoryCache.Add(serviceRegistration.RegistrationId, factory);\n        return factory;\n    }\n\n    private static Func<IResolutionScope, IRequestContext, object>? GetNewFactoryDelegate(ServiceRegistration serviceRegistration,\n        ResolutionContext resolutionContext, TypeInformation typeInformation) =>\n        GetExpressionForRegistration(serviceRegistration, resolutionContext, typeInformation)\n            ?.CompileDelegate(resolutionContext, resolutionContext.CurrentContainerContext.ContainerConfiguration);\n\n    /// <summary>\n    /// Derived types are using this method to apply their lifetime to the instance creation.\n    /// </summary>\n    /// <param name=\"factory\">The factory which can be used to instantiate the service.</param>\n    /// <param name=\"serviceRegistration\">The service registration.</param>\n    /// <param name=\"resolutionContext\">The info about the actual resolution.</param>\n    /// <param name=\"typeInformation\">The type information of the resolved service.</param>\n    /// <returns>The lifetime managed expression.</returns>\n    protected abstract Expression ApplyLifetime(Func<IResolutionScope, IRequestContext, object> factory, ServiceRegistration serviceRegistration,\n        ResolutionContext resolutionContext, TypeInformation typeInformation);\n}"
  },
  {
    "path": "src/Lifetime/LifetimeDescriptor.cs",
    "content": "﻿using Stashbox.Exceptions;\nusing Stashbox.Expressions;\nusing Stashbox.Registration;\nusing Stashbox.Resolution;\nusing System;\nusing System.Linq.Expressions;\n\nnamespace Stashbox.Lifetime;\n\n/// <summary>\n/// Represents a lifetime descriptor.\n/// </summary>\npublic abstract class LifetimeDescriptor\n{\n    /// <summary>\n    /// An indicator used to validate the lifetime configuration of the resolution tree.\n    /// Services with longer life-span shouldn't contain dependencies with shorter ones.\n    /// </summary>\n    protected internal virtual int LifeSpan => 0;\n\n    /// <summary>\n    /// The name of the lifetime, used only for diagnostic reasons.\n    /// </summary>\n    protected string Name { get; }\n\n    /// <summary>\n    /// Constructs the lifetime descriptor.\n    /// </summary>\n    protected LifetimeDescriptor()\n    {\n        this.Name = this.GetType().Name;\n    }\n\n    internal Expression? ApplyLifetime(ServiceRegistration serviceRegistration,\n        ResolutionContext resolutionContext, TypeInformation typeInformation)\n    {\n        if (resolutionContext.CurrentContainerContext.ContainerConfiguration.LifetimeValidationEnabled &&\n            this.LifeSpan > 0)\n        {\n            if (resolutionContext.CurrentLifeSpan > this.LifeSpan)\n                throw new LifetimeValidationFailedException(serviceRegistration.ImplementationType,\n                    $\"The life-span of {serviceRegistration.ImplementationType} ({this.Name}|{this.LifeSpan}) \" +\n                    $\"is shorter than its direct or indirect parent's {resolutionContext.NameOfServiceLifeSpanValidatingAgainst}.\" + Environment.NewLine +\n                    \"This could lead to incidental lifetime promotions with longer life-span, it's recommended to double check your lifetime configurations.\");\n\n            resolutionContext = resolutionContext.BeginLifetimeValidationContext(this.LifeSpan,\n                $\"{serviceRegistration.ImplementationType} ({this.Name}|{this.LifeSpan})\");\n        }\n\n        if (resolutionContext.AutoLifetimeTracking != null && this.LifeSpan > resolutionContext.AutoLifetimeTracking.HighestRankingLifetime.LifeSpan)\n        {\n            resolutionContext.AutoLifetimeTracking.HighestRankingLifetime = this;\n        }\n\n        return this.BuildLifetimeAppliedExpression(serviceRegistration, resolutionContext, typeInformation);\n    }\n\n    private protected abstract Expression? BuildLifetimeAppliedExpression(ServiceRegistration serviceRegistration,\n        ResolutionContext resolutionContext, TypeInformation typeInformation);\n    \n    internal abstract Expression? ApplyLifetimeToExpression(Expression? expression, ServiceRegistration serviceRegistration,\n        ResolutionContext resolutionContext, TypeInformation typeInformation);\n\n    private protected static Expression? GetExpressionForRegistration(ServiceRegistration serviceRegistration,\n        ResolutionContext resolutionContext, TypeInformation typeInformation)\n    {\n        if (!IsRegistrationOutputCacheable(serviceRegistration, resolutionContext))\n            return ExpressionBuilder.BuildExpressionForRegistration(serviceRegistration, resolutionContext, typeInformation);\n\n        var expression = resolutionContext.ExpressionCache.GetOrDefault(serviceRegistration.RegistrationId);\n        if (expression != null)\n            return expression;\n\n        expression = ExpressionBuilder.BuildExpressionForRegistration(serviceRegistration, resolutionContext, typeInformation);\n        if (expression == null)\n            return null;\n\n        resolutionContext.CacheExpression(serviceRegistration.RegistrationId, expression);\n        return expression;\n    }\n\n    private protected static bool IsRegistrationOutputCacheable(ServiceRegistration serviceRegistration, ResolutionContext resolutionContext) =>\n        !serviceRegistration.IsDecorator &&\n        resolutionContext.RequestConfiguration.FactoryDelegateCacheEnabled &&\n        resolutionContext.PerResolutionRequestCacheEnabled &&\n        serviceRegistration is not OpenGenericRegistration;\n}"
  },
  {
    "path": "src/Lifetime/Lifetimes.cs",
    "content": "﻿namespace Stashbox.Lifetime;\n\n/// <summary>\n/// Contains all the built-in lifetime managers.\n/// </summary>\npublic static class Lifetimes\n{\n    /// <summary>\n    /// Transient lifetime.\n    /// </summary>\n    public static readonly LifetimeDescriptor Transient = new TransientLifetime();\n\n    /// <summary>\n    /// Singleton lifetime.\n    /// </summary>\n    public static readonly LifetimeDescriptor Singleton = new SingletonLifetime();\n\n    /// <summary>\n    /// Scoped lifetime.\n    /// </summary>\n    public static readonly LifetimeDescriptor Scoped = new ScopedLifetime();\n\n    /// <summary>\n    /// Per resolution request lifetime.\n    /// </summary>\n    public static readonly LifetimeDescriptor PerRequest = new PerRequestLifetime();\n\n    /// <summary>\n    /// Produces a NamedScope lifetime.\n    /// </summary>\n    /// <param name=\"name\">The name of the scope.</param>\n    /// <returns>A named-scope lifetime.</returns>\n    public static LifetimeDescriptor NamedScope(object name) => new NamedScopeLifetime(name);\n\n    /// <summary>\n    /// Produces a lifetime that aligns to the lifetime of the resolved service's dependencies.\n    /// When the underlying service has a dependency with a higher lifespan, this lifetime will inherit that lifespan up to a given boundary.\n    /// </summary>\n    /// <param name=\"boundaryLifetime\">The lifetime that represents a boundary which the derived lifetime must not exceed.</param>\n    /// <returns>An auto lifetime.</returns>\n    public static LifetimeDescriptor Auto(LifetimeDescriptor boundaryLifetime) => new AutoLifetime(boundaryLifetime);\n\n    internal static readonly LifetimeDescriptor Empty = new EmptyLifetime();\n}"
  },
  {
    "path": "src/Lifetime/NamedScopeLifetime.cs",
    "content": "﻿using Stashbox.Exceptions;\nusing Stashbox.Registration;\nusing Stashbox.Resolution;\nusing System;\nusing System.Linq.Expressions;\nusing System.Reflection;\nusing Stashbox.Utils;\n\nnamespace Stashbox.Lifetime;\n\n/// <summary>\n/// Represents a named scope lifetime.\n/// </summary>\npublic class NamedScopeLifetime : FactoryLifetimeDescriptor\n{\n    private static readonly MethodInfo GetScopeValueMethod =\n        TypeCache<NamedScopeLifetime>.Type.GetMethod(nameof(GetScopedValue),\n            BindingFlags.Static | BindingFlags.NonPublic)!;\n\n    /// <summary>\n    /// The name of the scope where this lifetime activates.\n    /// </summary>\n    public readonly object ScopeName;\n\n    /// <inheritdoc />\n    protected internal override int LifeSpan => 10;\n\n    /// <summary>\n    /// Constructs a <see cref=\"NamedScopeLifetime\"/>.\n    /// </summary>\n    /// <param name=\"scopeName\"></param>\n    public NamedScopeLifetime(object scopeName)\n    {\n        this.ScopeName = scopeName;\n    }\n\n    /// <inheritdoc />\n    protected override Expression ApplyLifetime(Func<IResolutionScope, IRequestContext, object> factory,\n        ServiceRegistration serviceRegistration, ResolutionContext resolutionContext,\n        TypeInformation typeInformation) =>\n        GetScopeValueMethod.CallStaticMethod(resolutionContext.CurrentScopeParameter,\n            resolutionContext.RequestContextParameter,\n            factory.AsConstant(),\n            serviceRegistration.ImplementationType.AsConstant(),\n            serviceRegistration.GetDiscriminator(typeInformation,\n                resolutionContext.CurrentContainerContext.ContainerConfiguration).AsConstant(),\n            this.ScopeName.AsConstant(),\n            resolutionContext.CurrentContainerContext.ContainerConfiguration.ExternalResolutionFailedExceptionType\n                .AsConstant().ConvertTo(TypeCache<Type>.Type));\n\n    private static object GetScopedValue(IResolutionScope currentScope, IRequestContext requestContext,\n        Func<IResolutionScope, IRequestContext, object> factory, Type serviceType, int scopeId, object scopeName,\n        Type? externalExceptionType)\n    {\n        var scope = currentScope;\n        while (scope != null && !scopeName.Equals(scope.Name))\n            scope = scope.ParentScope;\n\n        if (scope == null)\n            throw ResolutionFailedException.CreateWithDesiredExceptionType(serviceType,\n                message:\n                $\"The scope '{scopeName}' was not found to resolve {serviceType.FullName} with named scope lifetime.\",\n                externalExceptionType: externalExceptionType);\n\n        return scope.GetOrAddScopedObject(scopeId, factory, requestContext, serviceType);\n    }\n}"
  },
  {
    "path": "src/Lifetime/PerRequestLifetime.cs",
    "content": "﻿using Stashbox.Registration;\nusing Stashbox.Resolution;\nusing Stashbox.Utils;\nusing System;\nusing System.Linq.Expressions;\n\nnamespace Stashbox.Lifetime;\n\n/// <summary>\n/// Represents a per-request lifetime.\n/// </summary>\npublic class PerRequestLifetime : FactoryLifetimeDescriptor\n{\n    /// <inheritdoc />\n    protected override Expression ApplyLifetime(Func<IResolutionScope, IRequestContext, object> factory,\n        ServiceRegistration serviceRegistration, ResolutionContext resolutionContext, TypeInformation typeInformation)\n    {\n        resolutionContext.RequestConfiguration.RequiresRequestContext = true;\n\n        return resolutionContext.RequestContextParameter\n            .ConvertTo(TypeCache<IInternalRequestContext>.Type)\n            .CallMethod(Constants.GetOrAddInstanceMethod,\n                serviceRegistration.GetDiscriminator(typeInformation, \n                    resolutionContext.CurrentContainerContext.ContainerConfiguration).AsConstant(),\n                factory.AsConstant(),\n                resolutionContext.CurrentScopeParameter);\n    }\n}"
  },
  {
    "path": "src/Lifetime/ScopedLifetime.cs",
    "content": "﻿using Stashbox.Exceptions;\nusing Stashbox.Registration;\nusing Stashbox.Resolution;\nusing Stashbox.Utils;\nusing System;\nusing System.Linq.Expressions;\n\nnamespace Stashbox.Lifetime;\n\n/// <summary>\n/// Represents a scoped lifetime.\n/// </summary>\npublic class ScopedLifetime : FactoryLifetimeDescriptor\n{\n    /// <inheritdoc />\n    protected internal override int LifeSpan => 10;\n\n    /// <inheritdoc />\n    protected override Expression ApplyLifetime(Func<IResolutionScope, IRequestContext, object> factory,\n        ServiceRegistration serviceRegistration, ResolutionContext resolutionContext, TypeInformation typeInformation)\n    {\n        if (resolutionContext.CurrentContainerContext.ContainerConfiguration.LifetimeValidationEnabled &&\n            resolutionContext.IsRequestedFromRoot)\n            throw new LifetimeValidationFailedException(serviceRegistration.ImplementationType,\n                $\"Resolution of {serviceRegistration.ImplementationType} ({this.Name}) from the root scope is not allowed, \" +\n                $\"that would promote the service's lifetime to singleton.\");\n\n        return resolutionContext.CurrentScopeParameter.CallMethod(Constants.GetOrAddScopedObjectMethod,\n                serviceRegistration.GetDiscriminator(typeInformation, \n                    resolutionContext.CurrentContainerContext.ContainerConfiguration).AsConstant(),\n                factory.AsConstant(),\n                resolutionContext.RequestContextParameter,\n                serviceRegistration.ImplementationType.AsConstant());\n    }\n}"
  },
  {
    "path": "src/Lifetime/SingletonLifetime.cs",
    "content": "﻿using Stashbox.Registration;\nusing Stashbox.Resolution;\nusing Stashbox.Utils;\nusing System;\nusing System.Linq.Expressions;\n\nnamespace Stashbox.Lifetime;\n\n/// <summary>\n/// Represents a singleton lifetime.\n/// </summary>\npublic class SingletonLifetime : FactoryLifetimeDescriptor\n{\n    /// <inheritdoc />\n    protected internal override int LifeSpan => 20;\n\n    /// <inheritdoc />\n    protected override Expression ApplyLifetime(Func<IResolutionScope, IRequestContext, object> factory,\n        ServiceRegistration serviceRegistration, ResolutionContext resolutionContext, TypeInformation typeInformation)\n    {\n        var rootScope = resolutionContext.RequestInitiatorContainerContext.ContainerConfiguration.ReBuildSingletonsInChildContainerEnabled\n            ? resolutionContext.RequestInitiatorContainerContext.RootScope\n            : resolutionContext.CurrentContainerContext.RootScope;\n\n        return rootScope.AsConstant().CallMethod(Constants.GetOrAddScopedObjectMethod,\n            serviceRegistration.GetDiscriminator(typeInformation, \n                resolutionContext.CurrentContainerContext.ContainerConfiguration).AsConstant(),\n            factory.AsConstant(),\n            resolutionContext.RequestContextParameter,\n            serviceRegistration.ImplementationType.AsConstant());\n    }\n}"
  },
  {
    "path": "src/Lifetime/TransientLifetime.cs",
    "content": "﻿using Stashbox.Registration;\nusing Stashbox.Resolution;\nusing System;\nusing System.Linq.Expressions;\n\nnamespace Stashbox.Lifetime;\n\n/// <summary>\n/// Represents a transient lifetime.\n/// </summary>\npublic class TransientLifetime : ExpressionLifetimeDescriptor\n{\n    /// <inheritdoc />\n    protected override Expression ApplyLifetime(Expression expression,\n        ServiceRegistration serviceRegistration, ResolutionContext resolutionContext, TypeInformation typeInformation) =>\n        expression;\n}"
  },
  {
    "path": "src/Metadata.cs",
    "content": "﻿namespace Stashbox;\n\n/// <summary>\n/// Describes a wrapper for services with additional metadata.\n/// </summary>\n/// <typeparam name=\"TService\">The service type.</typeparam>\n/// <typeparam name=\"TMeta\">The additional metadata type.</typeparam>\npublic sealed class Metadata<TService, TMeta>\n{\n    /// <summary>\n    /// The service.\n    /// </summary>\n    public readonly TService Service;\n\n    /// <summary>\n    /// The additional metadata.\n    /// </summary>\n    public readonly TMeta Data;\n\n    /// <summary>\n    /// Constructs a <see cref=\"Metadata{TService, TMeta}\"/>.\n    /// </summary>\n    /// <param name=\"service\">The service.</param>\n    /// <param name=\"data\">The additional metadata.</param>\n    public Metadata(TService service, TMeta data)\n    {\n        this.Service = service;\n        this.Data = data;\n    }\n}"
  },
  {
    "path": "src/Multitenant/ITenantDistributor.cs",
    "content": "﻿using System;\n\nnamespace Stashbox.Multitenant;\n\n/// <summary>\n/// Represents a tenant distributor that manages tenants in a multi-tenant environment.\n/// </summary>\n[Obsolete(\"The functionality of this interface was moved to IStashboxContainer. Please use IStashboxContainer.CreateChildContainer() and IStashboxContainer.GetChildContainer() instead.\")]\npublic interface ITenantDistributor : IStashboxContainer\n{\n    /// <summary>\n    /// Adds a tenant with a specified service configuration to the distributor.\n    /// </summary>\n    /// <param name=\"tenantId\">The identifier of the tenant.</param>\n    /// <param name=\"tenantConfig\">The service configuration of the tenant.</param>\n    /// <param name=\"attachTenantToRoot\">If true, the new tenant will be attached to the lifecycle of the root container. When the root is being disposed, the tenant will be disposed with it.</param>\n    void ConfigureTenant(object tenantId, Action<IStashboxContainer> tenantConfig, bool attachTenantToRoot = true);\n\n    /// <summary>\n    /// Gets a pre-configured <see cref=\"IDependencyResolver\"/> from the distributor which represents a tenant identified by the given id.\n    /// When the requested tenant doesn't exist a null value will be returned.\n    /// </summary>\n    /// <param name=\"tenantId\">The identifier of the tenant.</param>\n    /// <returns>The pre-configured tenant container if it's exist, otherwise null.</returns>\n    IDependencyResolver? GetTenant(object tenantId);\n}"
  },
  {
    "path": "src/Multitenant/TenantDistributor.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Stashbox.Configuration;\nusing Stashbox.Registration;\nusing Stashbox.Registration.Fluent;\nusing Stashbox.Resolution;\n\nnamespace Stashbox.Multitenant;\n\n/// <summary>\n/// Represents a tenant distributor that manages tenants in a multi-tenant environment.\n/// </summary>\n[Obsolete(\"The functionality of this class was moved to StashboxContainer. Please use StashboxContainer.CreateChildContainer() and StashboxContainer.GetChildContainer() instead.\")]\npublic sealed class TenantDistributor : ITenantDistributor\n{\n    private int disposed;\n    private readonly IStashboxContainer rootContainer;\n    /// <summary>\n    /// Constructs a <see cref=\"TenantDistributor\"/>.\n    /// </summary>\n    /// <param name=\"rootContainer\">A pre-configured root container, used to create child tenant containers. If not set, a new will be created.</param>\n    public TenantDistributor(IStashboxContainer? rootContainer = null)\n    {\n        this.rootContainer = rootContainer ?? new StashboxContainer();\n    }\n\n    /// <inheritdoc />\n    public void ConfigureTenant(object tenantId, Action<IStashboxContainer> tenantConfig, bool attachTenantToRoot = true) =>\n        rootContainer.CreateChildContainer(tenantId, tenantConfig, attachTenantToRoot);\n\n    /// <inheritdoc />\n    public IDependencyResolver? GetTenant(object tenantId) => rootContainer.GetChildContainer(tenantId);\n    /// <inheritdoc />\n    public IEnumerable<ReadOnlyKeyValue<object, IStashboxContainer>> ChildContainers => rootContainer.ChildContainers;\n    /// <inheritdoc />\n    public IStashboxContainer RegisterResolver(IResolver resolver) => rootContainer.RegisterResolver(resolver);\n    /// <inheritdoc />\n    public IStashboxContainer CreateChildContainer(Action<ContainerConfigurator>? config = null, bool attachToParent = true) => rootContainer.CreateChildContainer(config, attachToParent);\n    /// <inheritdoc />\n    public IStashboxContainer CreateChildContainer(object identifier, Action<IStashboxContainer>? config = null,\n        bool attachToParent = true) => rootContainer.CreateChildContainer(identifier, config, attachToParent);\n\n    /// <inheritdoc />\n    public IStashboxContainer? GetChildContainer(object identifier) => rootContainer.GetChildContainer(identifier);\n    /// <inheritdoc />\n    public IContainerContext ContainerContext => rootContainer.ContainerContext;\n    /// <inheritdoc />\n    public bool IsRegistered<TFrom>(object? name = null) => rootContainer.IsRegistered<TFrom>(name);\n    /// <inheritdoc />\n    public bool IsRegistered(Type typeFrom, object? name = null) => rootContainer.IsRegistered(typeFrom, name);\n    /// <inheritdoc />\n    public IStashboxContainer Configure(Action<ContainerConfigurator> config) => rootContainer.Configure(config);\n    /// <inheritdoc />\n    public void Validate() => rootContainer.Validate();\n    /// <inheritdoc />\n    public IEnumerable<KeyValuePair<Type, ServiceRegistration>> GetRegistrationMappings() => rootContainer.GetRegistrationMappings();\n    /// <inheritdoc />\n    public IEnumerable<RegistrationDiagnosticsInfo> GetRegistrationDiagnostics() => rootContainer.GetRegistrationDiagnostics();\n    /// <inheritdoc />\n    public void Dispose()\n    {\n        if (Interlocked.CompareExchange(ref this.disposed, 1, 0) != 0)\n            return;\n\n        this.rootContainer.Dispose();\n    }\n#if HAS_ASYNC_DISPOSABLE\n        /// <inheritdoc />\n        public ValueTask DisposeAsync() => Interlocked.CompareExchange(ref this.disposed, 1, 0) != 0 ? new ValueTask(Task.CompletedTask) : this.rootContainer.DisposeAsync();\n#endif\n    /// <inheritdoc />\n    public IStashboxContainer Register<TFrom, TTo>(Action<RegistrationConfigurator<TFrom, TTo>> configurator) where TFrom : class where TTo : class, TFrom => rootContainer.Register(configurator);\n    /// <inheritdoc />\n    public IStashboxContainer Register<TFrom, TTo>(object? name = null) where TFrom : class where TTo : class, TFrom => rootContainer.Register<TFrom, TTo>(name);\n    /// <inheritdoc />\n    public IStashboxContainer Register<TFrom>(Type typeTo, Action<RegistrationConfigurator<TFrom, TFrom>>? configurator = null) where TFrom : class => rootContainer.Register(typeTo, configurator);\n    /// <inheritdoc />\n    public IStashboxContainer Register(Type typeFrom, Type typeTo, Action<RegistrationConfigurator>? configurator = null) => rootContainer.Register(typeFrom, typeTo, configurator);\n    /// <inheritdoc />\n    public IStashboxContainer Register<TTo>(Action<RegistrationConfigurator<TTo, TTo>> configurator) where TTo : class => rootContainer.Register<TTo>(configurator);\n    /// <inheritdoc />\n    public IStashboxContainer Register<TTo>(object? name = null) where TTo : class => rootContainer.Register<TTo>(name);\n    /// <inheritdoc />\n    public IStashboxContainer Register(Type typeTo, Action<RegistrationConfigurator>? configurator = null) => rootContainer.Register(typeTo, configurator);\n    /// <inheritdoc />\n    public IStashboxContainer RegisterSingleton<TFrom, TTo>(object? name = null) where TFrom : class where TTo : class, TFrom => rootContainer.RegisterSingleton<TFrom, TTo>(name);\n    /// <inheritdoc />\n    public IStashboxContainer RegisterSingleton<TTo>(object? name = null) where TTo : class => rootContainer.RegisterSingleton<TTo>(name);\n    /// <inheritdoc />\n    public IStashboxContainer RegisterSingleton(Type typeFrom, Type typeTo, object? name = null) => rootContainer.RegisterSingleton(typeFrom, typeTo, name);\n    /// <inheritdoc />\n    public IStashboxContainer RegisterScoped<TFrom, TTo>(object? name = null) where TFrom : class where TTo : class, TFrom => rootContainer.RegisterScoped<TFrom, TTo>(name);\n    /// <inheritdoc />\n    public IStashboxContainer RegisterScoped(Type typeFrom, Type typeTo, object? name = null) => rootContainer.RegisterScoped(typeFrom, typeTo, name);\n    /// <inheritdoc />\n    public IStashboxContainer RegisterScoped<TTo>(object? name = null) where TTo : class => rootContainer.RegisterScoped<TTo>(name);\n    /// <inheritdoc />\n    public IStashboxContainer RegisterInstance<TInstance>(TInstance instance, object? name = null,\n        bool withoutDisposalTracking = false, Action<TInstance>? finalizerDelegate = null) where TInstance : class =>\n        rootContainer.RegisterInstance(instance, name, withoutDisposalTracking, finalizerDelegate);\n    /// <inheritdoc />\n    public IStashboxContainer RegisterInstance(object instance, Type serviceType, object? name = null,\n        bool withoutDisposalTracking = false) =>\n        rootContainer.RegisterInstance(instance, serviceType, name, withoutDisposalTracking);\n    /// <inheritdoc />\n    public IStashboxContainer WireUp<TInstance>(TInstance instance, object? name = null, bool withoutDisposalTracking = false,\n        Action<TInstance>? finalizerDelegate = null) where TInstance : class =>\n        rootContainer.WireUp(instance, name, withoutDisposalTracking, finalizerDelegate);\n    /// <inheritdoc />\n    public IStashboxContainer WireUp(object instance, Type serviceType, object? name = null, bool withoutDisposalTracking = false) => rootContainer.WireUp(instance, serviceType, name, withoutDisposalTracking);\n    /// <inheritdoc />\n    public object? GetService(Type serviceType) => rootContainer.GetService(serviceType);\n    /// <inheritdoc />\n    public object Resolve(Type typeFrom) => rootContainer.Resolve(typeFrom);\n    /// <inheritdoc />\n    public object Resolve(Type typeFrom, object? name, object[]? dependencyOverrides, ResolutionBehavior resolutionBehavior = ResolutionBehavior.Default) => rootContainer.Resolve(typeFrom, name, dependencyOverrides, resolutionBehavior);\n    /// <inheritdoc />\n    public object? ResolveOrDefault(Type typeFrom) => rootContainer.ResolveOrDefault(typeFrom);\n    /// <inheritdoc />\n    public object? ResolveOrDefault(Type typeFrom, object? name, object[]? dependencyOverrides, ResolutionBehavior resolutionBehavior = ResolutionBehavior.Default) => rootContainer.ResolveOrDefault(typeFrom, name, dependencyOverrides, resolutionBehavior); \n    /// <inheritdoc />\n    public Delegate ResolveFactory(Type typeFrom, object? name = null, ResolutionBehavior resolutionBehavior = ResolutionBehavior.Default, params Type[] parameterTypes) => rootContainer.ResolveFactory(typeFrom, name, resolutionBehavior, parameterTypes);\n    /// <inheritdoc />\n    public Delegate? ResolveFactoryOrDefault(Type typeFrom, object? name = null, ResolutionBehavior resolutionBehavior = ResolutionBehavior.Default, params Type[] parameterTypes) => rootContainer.ResolveFactoryOrDefault(typeFrom, name, resolutionBehavior, parameterTypes);\n    /// <inheritdoc />\n    public IDependencyResolver BeginScope(object? name = null, bool attachToParent = false) => rootContainer.BeginScope(name, attachToParent);\n    /// <inheritdoc />\n    public void PutInstanceInScope(Type typeFrom, object instance, bool withoutDisposalTracking = false, object? name = null) => rootContainer.PutInstanceInScope(typeFrom, instance, withoutDisposalTracking, name);\n    /// <inheritdoc />\n    public TTo BuildUp<TTo>(TTo instance, ResolutionBehavior resolutionBehavior = ResolutionBehavior.Default) where TTo : class => rootContainer.BuildUp(instance, resolutionBehavior);\n    /// <inheritdoc />\n    public object Activate(Type type, ResolutionBehavior resolutionBehavior, params object[] arguments) => rootContainer.Activate(type, resolutionBehavior, arguments);\n    /// <inheritdoc />\n    public ValueTask InvokeAsyncInitializers(CancellationToken token = default) => rootContainer.InvokeAsyncInitializers(token);\n    /// <inheritdoc />\n    public bool CanResolve(Type typeFrom, object? name = null, ResolutionBehavior resolutionBehavior = ResolutionBehavior.Default) => rootContainer.CanResolve(typeFrom, name);\n    /// <inheritdoc />\n    public IEnumerable<DelegateCacheEntry> GetDelegateCacheEntries() => rootContainer.GetDelegateCacheEntries();\n    /// <inheritdoc />\n    public IStashboxContainer ReMap<TFrom, TTo>(Action<RegistrationConfigurator<TFrom, TTo>>? configurator = null) where TFrom : class where TTo : class, TFrom => rootContainer.ReMap(configurator);\n    /// <inheritdoc />\n    public IStashboxContainer ReMap<TFrom>(Type typeTo, Action<RegistrationConfigurator<TFrom, TFrom>>? configurator = null) where TFrom : class => rootContainer.ReMap(typeTo, configurator);\n    /// <inheritdoc />\n    public IStashboxContainer ReMap(Type typeFrom, Type typeTo, Action<RegistrationConfigurator>? configurator = null) => rootContainer.ReMap(typeFrom, typeTo, configurator);\n    /// <inheritdoc />\n    public IStashboxContainer ReMap<TTo>(Action<RegistrationConfigurator<TTo, TTo>>? configurator = null) where TTo : class => rootContainer.ReMap<TTo>(configurator);\n    /// <inheritdoc />\n    public IStashboxContainer ReMapDecorator(Type typeFrom, Type typeTo, Action<DecoratorConfigurator>? configurator = null) => rootContainer.ReMapDecorator(typeFrom, typeTo, configurator);\n    /// <inheritdoc />\n    public IStashboxContainer ReMapDecorator<TFrom, TTo>(Action<DecoratorConfigurator<TFrom, TTo>>? configurator = null) where TFrom : class where TTo : class, TFrom => rootContainer.ReMapDecorator(configurator);\n    /// <inheritdoc />\n    public IStashboxContainer ReMapDecorator<TFrom>(Type typeTo, Action<DecoratorConfigurator<TFrom, TFrom>>? configurator = null) where TFrom : class => rootContainer.ReMapDecorator(typeTo, configurator);\n    /// <inheritdoc />\n    public IStashboxContainer RegisterTypesAs(Type typeFrom, IEnumerable<Type> types, Func<Type, bool>? selector = null,\n        Action<RegistrationConfigurator>? configurator = null) =>\n        rootContainer.RegisterTypesAs(typeFrom, types, selector, configurator);\n    /// <inheritdoc />\n    public IStashboxContainer RegisterTypes(IEnumerable<Type> types, Func<Type, bool>? selector = null, Func<Type, Type, bool>? serviceTypeSelector = null,\n        bool registerSelf = true, Action<RegistrationConfigurator>? configurator = null) =>\n        rootContainer.RegisterTypes(types, selector, serviceTypeSelector, registerSelf, configurator);\n    /// <inheritdoc />\n    public IStashboxContainer ComposeBy(Type compositionRootType, params object[] compositionRootArguments) => rootContainer.ComposeBy(compositionRootType, compositionRootArguments);\n    /// <inheritdoc />\n    public IStashboxContainer ComposeBy(ICompositionRoot compositionRoot) => rootContainer.ComposeBy(compositionRoot);\n    /// <inheritdoc />\n    public IStashboxContainer RegisterDecorator(Type typeFrom, Type typeTo, Action<DecoratorConfigurator>? configurator = null) => rootContainer.RegisterDecorator(typeFrom, typeTo, configurator);\n    /// <inheritdoc />\n    public IStashboxContainer RegisterDecorator<TFrom, TTo>(Action<DecoratorConfigurator<TFrom, TTo>>? configurator = null) where TFrom : class where TTo : class, TFrom => rootContainer.RegisterDecorator(configurator);\n    /// <inheritdoc />\n    public IStashboxContainer RegisterDecorator(Type typeTo, Action<DecoratorConfigurator>? configurator = null) => rootContainer.RegisterDecorator(typeTo, configurator);\n    /// <inheritdoc />\n    public IStashboxContainer RegisterDecorator<TTo>(Action<DecoratorConfigurator<TTo, TTo>>? configurator = null) where TTo : class => rootContainer.RegisterDecorator<TTo>(configurator);\n    /// <inheritdoc />\n    public IStashboxContainer RegisterDecorator<TFrom>(Type typeTo, Action<DecoratorConfigurator<TFrom, TFrom>>? configurator = null) where TFrom : class => rootContainer.RegisterDecorator(typeTo, configurator);\n    /// <inheritdoc />\n    public IStashboxContainer RegisterFunc<TService>(Func<IDependencyResolver, TService> factory, object? name = null) => rootContainer.RegisterFunc(factory, name);\n    /// <inheritdoc />\n    public IStashboxContainer RegisterFunc<T1, TService>(Func<T1, IDependencyResolver, TService> factory, object? name = null) => rootContainer.RegisterFunc(factory, name);\n    /// <inheritdoc />\n    public IStashboxContainer RegisterFunc<T1, T2, TService>(Func<T1, T2, IDependencyResolver, TService> factory, object? name = null) => rootContainer.RegisterFunc(factory, name);\n    /// <inheritdoc />\n    public IStashboxContainer RegisterFunc<T1, T2, T3, TService>(Func<T1, T2, T3, IDependencyResolver, TService> factory, object? name = null) => rootContainer.RegisterFunc(factory, name);\n    /// <inheritdoc />\n    public IStashboxContainer RegisterFunc<T1, T2, T3, T4, TService>(Func<T1, T2, T3, T4, IDependencyResolver, TService> factory, object? name = null) => rootContainer.RegisterFunc(factory, name);\n}"
  },
  {
    "path": "src/Override.cs",
    "content": "using System;\nusing Stashbox.Utils;\n\nnamespace Stashbox;\n\n/// <summary>\n/// Represents a specialized resolution override.\n/// </summary>\npublic class Override\n{\n    private Override(object instance, object? dependencyName, Type type)\n    {\n        this.Instance = instance;\n        this.DependencyName = dependencyName;\n        this.Type = type;\n    }\n\n    /// <summary>\n    /// The name of the override used for named resolution.\n    /// </summary>\n    public object? DependencyName { get; }\n\n    /// <summary>\n    /// The instance used as dependency override.\n    /// </summary>\n    public object Instance { get; }\n\n    /// <summary>\n    /// The type of the dependency override.\n    /// </summary>\n    public Type Type { get; }\n    \n    /// <summary>\n    /// Creates a new <see cref=\"Override\"/> instance.\n    /// </summary>\n    /// <param name=\"instance\">The instance used as dependency override.</param>\n    /// <param name=\"name\">The optional name of the instance used as dependency override.</param>\n    /// <returns>The constructed override instance.</returns>\n    public static Override Of<TType>(TType instance, object? name = null) where TType: notnull => new(instance, name, TypeCache<TType>.Type);\n\n    /// <summary>\n    /// Creates a new <see cref=\"Override\"/> instance.\n    /// </summary>\n    /// <param name=\"type\">The type of the override.</param>\n    /// <param name=\"instance\">The instance used as dependency override.</param>\n    /// <param name=\"name\">The optional name of the instance used as dependency override.</param>\n    /// <returns>The constructed override instance.</returns>\n    public static Override Of(Type type, object instance, object? name = null) => new(instance, name, type);\n}"
  },
  {
    "path": "src/ReadOnlyKeyValue.cs",
    "content": "﻿using System.Diagnostics;\n\nnamespace Stashbox;\n\n/// <summary>\n/// Represents a readonly key-value pair.\n/// </summary>\n/// <typeparam name=\"TKey\">Type of the key.</typeparam>\n/// <typeparam name=\"TValue\">Type of the value.</typeparam>\n[DebuggerDisplay(\"{Value}\", Name = \"{Key}\")]\npublic readonly struct ReadOnlyKeyValue<TKey, TValue>\n{\n    /// <summary>\n    /// The key.\n    /// </summary>\n    public readonly TKey Key;\n\n    /// <summary>\n    /// The value.\n    /// </summary>\n    public readonly TValue Value;\n\n    /// <summary>\n    /// Constructs a <see cref=\"ReadOnlyKeyValue{TKey, TValue}\"/>.\n    /// </summary>\n    /// <param name=\"key\">The key.</param>\n    /// <param name=\"value\">The value.</param>\n    public ReadOnlyKeyValue(TKey key, TValue value)\n    {\n        this.Key = key;\n        this.Value = value;\n    }\n}"
  },
  {
    "path": "src/Registration/DecoratorRepository.cs",
    "content": "﻿using Stashbox.Registration.Extensions;\nusing Stashbox.Registration.SelectionRules;\nusing Stashbox.Resolution;\nusing Stashbox.Utils;\nusing Stashbox.Utils.Data.Immutable;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing Stashbox.Configuration;\n\nnamespace Stashbox.Registration;\n\ninternal class DecoratorRepository(ContainerConfiguration containerConfiguration) : IDecoratorRepository\n{\n    private ImmutableTree<Type, ImmutableBucket<Type, ServiceRegistration>> repository = ImmutableTree<Type, ImmutableBucket<Type, ServiceRegistration>>.Empty;\n\n    private readonly IRegistrationSelectionRule[] filters =\n    [\n        RegistrationSelectionRules.GenericFilter,\n        RegistrationSelectionRules.ConditionFilter,\n        RegistrationSelectionRules.ScopeNameFilter,\n        RegistrationSelectionRules.DecoratorFilter\n    ];\n\n    public void AddDecorator(Type type, ServiceRegistration serviceRegistration, bool remap)\n    {\n        var newRepository = ImmutableBucket<Type, ServiceRegistration>.Empty.Add(serviceRegistration.ImplementationType, serviceRegistration);\n\n        if (remap)\n            Swap.SwapValue(ref this.repository, (t1, t2, _, _, repo) =>\n                    repo.AddOrUpdate(t1, t2, true, (_, newValue) => newValue), type, newRepository,\n                Constants.DelegatePlaceholder, Constants.DelegatePlaceholder);\n        else\n            Swap.SwapValue(ref this.repository, (t1, t2, t3, _, repo) =>\n                    repo.AddOrUpdate(t1, t2, true, (oldValue, _) => oldValue\n                        .AddOrUpdate(t3.ImplementationType, t3, t3.Options.IsOn(RegistrationOption.ReplaceExistingRegistration))),\n                type, newRepository, serviceRegistration, Constants.DelegatePlaceholder);\n    }\n\n    public IEnumerable<ServiceRegistration>? GetDecoratorsOrDefault(Type implementationTypeToDecorate, TypeInformation typeInformation, ResolutionContext resolutionContext) =>\n        this.GetRegistrationsForType(typeInformation.Type)?.FilterInclusive(typeInformation.Clone(implementationTypeToDecorate), resolutionContext, this.filters);\n\n    public IEnumerable<KeyValuePair<Type, ServiceRegistration>> GetRegistrationMappings() =>\n        repository.Walk().SelectMany(reg => reg.Value.Select(r => new KeyValuePair<Type, ServiceRegistration>(reg.Key, r)));\n\n    private IEnumerable<ServiceRegistration>? GetRegistrationsForType(Type type)\n    {\n        IEnumerable<ServiceRegistration>? registrations = repository.GetOrDefaultByRef(type);\n        if (!type.IsClosedGenericType()) return registrations;\n        \n        var openGenerics = repository.GetOrDefaultByRef(type.GetGenericTypeDefinition());\n\n        if (openGenerics != null)\n            registrations = registrations == null ? openGenerics : openGenerics.Concat(registrations);\n\n        if (!containerConfiguration.VariantGenericTypesEnabled)\n            return registrations;\n        \n        var variantGenerics = repository.Walk()\n            .Where(r => r.Key.IsGenericType &&\n                        r.Key.GetGenericTypeDefinition() == type.GetGenericTypeDefinition() &&\n                        r.Key != type &&\n                        r.Key.ImplementsWithoutGenericCheck(type))\n            .SelectMany(r => r.Value).ToArray();\n\n        if (variantGenerics.Length > 0)\n            registrations = registrations == null ? variantGenerics : variantGenerics.Concat(registrations);\n\n        return registrations;\n    }\n\n}"
  },
  {
    "path": "src/Registration/Extensions/CollectionRegistratorExtensions.cs",
    "content": "﻿using Stashbox.Exceptions;\nusing Stashbox.Registration.Fluent;\nusing Stashbox.Utils;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Reflection;\n\nnamespace Stashbox;\n\n/// <summary>\n/// Represents the extension methods of <see cref=\"IDependencyCollectionRegistrator\"/>.\n/// </summary>\npublic static class CollectionRegistratorExtensions\n{\n    /// <summary>\n    /// Registers a collection of types mapped to a service type.\n    /// </summary>\n    /// <typeparam name=\"TFrom\">The service type.</typeparam>\n    /// <param name=\"registrator\">The registrator.</param>\n    /// <param name=\"types\">Types to register.</param>\n    /// <param name=\"selector\">The type selector. Used to filter which types should be excluded/included in the registration process.</param>\n    /// <param name=\"configurator\">The configurator for the registered types.</param>\n    /// <returns>The <see cref=\"IStashboxContainer\"/> instance.</returns>\n    public static IStashboxContainer RegisterTypesAs<TFrom>(this IDependencyCollectionRegistrator registrator,\n        IEnumerable<Type> types,\n        Func<Type, bool>? selector = null,\n        Action<RegistrationConfigurator>? configurator = null)\n        where TFrom : class =>\n        registrator.RegisterTypesAs(TypeCache<TFrom>.Type,\n            types,\n            selector,\n            configurator);\n\n    /// <summary>\n    /// Registers a collection of types mapped to a service type.\n    /// </summary>\n    /// <typeparam name=\"TFrom\">The service type.</typeparam>\n    /// <param name=\"registrator\">The registrator.</param>\n    /// <param name=\"assembly\">Assembly to register.</param>\n    /// <param name=\"selector\">The type selector. Used to filter which types should be excluded/included in the registration process.</param>\n    /// <param name=\"configurator\">The configurator for the registered types.</param>\n    /// <returns>The <see cref=\"IStashboxContainer\"/> instance.</returns>\n    public static IStashboxContainer RegisterTypesAs<TFrom>(this IDependencyCollectionRegistrator registrator,\n        Assembly assembly,\n        Func<Type, bool>? selector = null,\n        Action<RegistrationConfigurator>? configurator = null)\n        where TFrom : class =>\n        registrator.RegisterTypesAs(TypeCache<TFrom>.Type,\n            assembly.CollectTypes(),\n            selector,\n            configurator);\n\n    /// <summary>\n    /// Registers a collection of types mapped to a service type.\n    /// </summary>\n    /// <param name=\"typeFrom\">The service type.</param>\n    /// <param name=\"registrator\">The registrator.</param>\n    /// <param name=\"assembly\">Assembly to register.</param>\n    /// <param name=\"selector\">The type selector. Used to filter which types should be excluded/included in the registration process.</param>\n    /// <param name=\"configurator\">The configurator for the registered types.</param>\n    /// <returns>The <see cref=\"IStashboxContainer\"/> instance.</returns>\n    public static IStashboxContainer RegisterTypesAs(this IDependencyCollectionRegistrator registrator,\n        Type typeFrom,\n        Assembly assembly,\n        Func<Type, bool>? selector = null,\n        Action<RegistrationConfigurator>? configurator = null) =>\n        registrator.RegisterTypesAs(typeFrom,\n            assembly.CollectTypes(),\n            selector,\n            configurator);\n\n    /// <summary>\n    /// Registers types from an assembly.\n    /// </summary>\n    /// <param name=\"registrator\">The registrator.</param>\n    /// <param name=\"assembly\">The assembly containing the types to register.</param>\n    /// <param name=\"selector\">The type selector. Used to filter which types should be excluded/included in the registration process.</param>\n    /// <param name=\"serviceTypeSelector\">The service type selector. Used to filter which interface or base types the implementation should be mapped to.</param>\n    /// <param name=\"registerSelf\">If it's true the types will be registered to their own type too.</param>\n    /// <param name=\"configurator\">The configurator for the registered types.</param>\n    /// <returns>The <see cref=\"IStashboxContainer\"/> instance.</returns>\n    public static IStashboxContainer RegisterAssembly(this IDependencyCollectionRegistrator registrator,\n        Assembly assembly,\n        Func<Type, bool>? selector = null,\n        Func<Type, Type, bool>? serviceTypeSelector = null,\n        bool registerSelf = true,\n        Action<RegistrationConfigurator>? configurator = null) =>\n        registrator.RegisterTypes(assembly.CollectTypes(),\n            selector,\n            serviceTypeSelector,\n            registerSelf,\n            configurator);\n\n    /// <summary>\n    /// Registers types from an assembly collection.\n    /// </summary>\n    /// <param name=\"registrator\">The registrator.</param>\n    /// <param name=\"assemblies\">The assemblies holding the types to register.</param>\n    /// <param name=\"selector\">The type selector. Used to filter which types should be excluded/included in the registration process.</param>\n    /// <param name=\"serviceTypeSelector\">The service type selector. Used to filter which interface or base types the implementation should be mapped to.</param>\n    /// <param name=\"registerSelf\">If it's true the types will be registered to their own type too.</param>\n    /// <param name=\"configurator\">The configurator for the registered types.</param>\n    /// <returns>The <see cref=\"IStashboxContainer\"/> instance.</returns>\n    public static IStashboxContainer RegisterAssemblies(this IDependencyCollectionRegistrator registrator,\n        IEnumerable<Assembly> assemblies,\n        Func<Type, bool>? selector = null,\n        Func<Type, Type, bool>? serviceTypeSelector = null,\n        bool registerSelf = true,\n        Action<RegistrationConfigurator>? configurator = null)\n    {\n        Shield.EnsureNotNull(assemblies, nameof(assemblies));\n\n        foreach (var assembly in assemblies)\n            registrator.RegisterAssembly(assembly,\n                selector,\n                serviceTypeSelector,\n                registerSelf,\n                configurator);\n\n        return (IStashboxContainer)registrator;\n    }\n\n    /// <summary>\n    /// Registers types from an assembly that contains the given service type.\n    /// </summary>\n    /// <typeparam name=\"TFrom\">The service type the assembly contains.</typeparam>\n    /// <param name=\"registrator\">The registrator.</param>\n    /// <param name=\"selector\">The type selector. Used to filter which types should be excluded/included in the registration process.</param>\n    /// <param name=\"serviceTypeSelector\">The service type selector. Used to filter which interface or base types the implementation should be mapped to.</param>\n    /// <param name=\"registerSelf\">If it's true the types will be registered to their own type too.</param>\n    /// <param name=\"configurator\">The configurator for the registered types.</param>\n    /// <returns>The <see cref=\"IStashboxContainer\"/> instance.</returns>\n    public static IStashboxContainer RegisterAssemblyContaining<TFrom>(this IDependencyCollectionRegistrator registrator,\n        Func<Type, bool>? selector = null,\n        Func<Type, Type, bool>? serviceTypeSelector = null,\n        bool registerSelf = true,\n        Action<RegistrationConfigurator>? configurator = null)\n        where TFrom : class =>\n        registrator.RegisterAssemblyContaining(TypeCache<TFrom>.Type,\n            selector,\n            serviceTypeSelector,\n            registerSelf,\n            configurator);\n\n    /// <summary>\n    /// Registers types from an assembly that contains the given service type.\n    /// </summary>\n    /// <param name=\"registrator\">The registrator.</param>\n    /// <param name=\"typeFrom\">The type the assembly contains.</param>\n    /// <param name=\"selector\">The type selector. Used to filter which types should be excluded/included in the registration process.</param>\n    /// <param name=\"serviceTypeSelector\">The service type selector. Used to filter which interface or base types the implementation should be mapped to.</param>\n    /// <param name=\"registerSelf\">If it's true the types will be registered to their own type too.</param>\n    /// <param name=\"configurator\">The configurator for the registered types.</param>\n    /// <returns>The <see cref=\"IStashboxContainer\"/> instance.</returns>\n    public static IStashboxContainer RegisterAssemblyContaining(this IDependencyCollectionRegistrator registrator,\n        Type typeFrom,\n        Func<Type, bool>? selector = null,\n        Func<Type, Type, bool>? serviceTypeSelector = null,\n        bool registerSelf = true,\n        Action<RegistrationConfigurator>? configurator = null) =>\n        registrator.RegisterAssembly(typeFrom.Assembly,\n            selector,\n            serviceTypeSelector,\n            registerSelf,\n            configurator);\n\n    /// <summary>\n    /// Scans the given assemblies for <see cref=\"ICompositionRoot\"/> implementations and invokes their <see cref=\"ICompositionRoot.Compose\"/> method.\n    /// </summary>\n    /// <param name=\"registrator\">The registrator.</param>\n    /// <param name=\"assemblies\">The assemblies to scan.</param>\n    /// <param name=\"selector\">The type selector. Used to filter which types should be excluded/included in the registration process.</param>\n    /// <returns>The <see cref=\"IStashboxContainer\"/> instance.</returns>\n    public static IStashboxContainer ComposeAssemblies(this IDependencyCollectionRegistrator registrator,\n        IEnumerable<Assembly> assemblies,\n        Func<Type, bool>? selector = null)\n    {\n        Shield.EnsureNotNull(assemblies, nameof(assemblies));\n\n        foreach (var assembly in assemblies)\n            registrator.ComposeAssembly(assembly, selector);\n\n        return (IStashboxContainer)registrator;\n    }\n\n    /// <summary>\n    /// Composes services by calling the <see cref=\"ICompositionRoot.Compose\"/> method of the given root.\n    /// </summary>\n    /// <typeparam name=\"TCompositionRoot\">The type of an <see cref=\"ICompositionRoot\"/> implementation.</typeparam>\n    /// <param name=\"registrator\">The registrator.</param>\n    /// <param name=\"compositionRootArguments\">Optional composition root constructor arguments.</param>\n    /// <returns>The <see cref=\"IStashboxContainer\"/> instance.</returns>\n    public static IStashboxContainer ComposeBy<TCompositionRoot>(this IDependencyCollectionRegistrator registrator,\n        params object[] compositionRootArguments)\n        where TCompositionRoot : class, ICompositionRoot =>\n        registrator.ComposeBy(TypeCache<TCompositionRoot>.Type, compositionRootArguments);\n\n    /// <summary>\n    /// Scans the given assembly for <see cref=\"ICompositionRoot\"/> implementations and invokes their <see cref=\"ICompositionRoot.Compose\"/> method.\n    /// </summary>\n    /// <param name=\"registrator\">The registrator.</param>\n    /// <param name=\"assembly\">The assembly to scan.</param>\n    /// <param name=\"selector\">The type selector. Used to filter which types should be excluded/included in the registration process.</param>\n    /// <returns>The <see cref=\"IStashboxContainer\"/> instance.</returns>\n    public static IStashboxContainer ComposeAssembly(this IDependencyCollectionRegistrator registrator,\n        Assembly assembly,\n        Func<Type, bool>? selector = null)\n    {\n        Shield.EnsureNotNull(assembly, nameof(assembly));\n\n        var types = selector == null ? assembly.CollectTypes() : assembly.CollectTypes().Where(selector);\n        var compositionRootTypes = types.Where(type => type.IsResolvableType() && type.IsCompositionRoot()).CastToArray();\n\n        if (!compositionRootTypes.Any())\n            throw new CompositionRootNotFoundException(assembly);\n\n        foreach (var compositionRootType in compositionRootTypes)\n            registrator.ComposeBy(compositionRootType);\n\n        return (IStashboxContainer)registrator;\n    }\n\n}"
  },
  {
    "path": "src/Registration/Extensions/DependencyRegistratorExtensions.cs",
    "content": "﻿using System.Collections.Generic;\n\nnamespace Stashbox;\n\n/// <summary>\n/// Represents the extension methods of <see cref=\"IDependencyRegistrator\"/>.\n/// </summary>\npublic static class DependencyRegistratorExtensions\n{\n    /// <summary>\n    /// Registers instances that are already constructed.\n    /// </summary>\n    /// <param name=\"registrator\">The dependency registrator.</param>\n    /// <param name=\"instances\">The collection of the constructed instances.</param>\n    /// <param name=\"withoutDisposalTracking\">If it's set to true the container will exclude the instance from the disposal tracking.</param>\n    /// <returns>The <see cref=\"IStashboxContainer\"/> instance.</returns>\n    public static IStashboxContainer RegisterInstances<TFrom>(this IDependencyRegistrator registrator,\n        IEnumerable<TFrom> instances, bool withoutDisposalTracking = false)\n        where TFrom : class\n    {\n        foreach (var instance in instances)\n            registrator.RegisterInstance(instance, withoutDisposalTracking: withoutDisposalTracking);\n\n        return (IStashboxContainer)registrator;\n    }\n\n    /// <summary>\n    /// Registers instances that are already constructed.\n    /// </summary>\n    /// <param name=\"registrator\">The dependency registrator.</param>\n    /// <param name=\"instances\">The collection of the constructed instances.</param>\n    /// <returns>The <see cref=\"IStashboxContainer\"/> instance.</returns>\n    public static IStashboxContainer RegisterInstances<TFrom>(this IDependencyRegistrator registrator,\n        params TFrom[] instances)\n        where TFrom : class => registrator.RegisterInstances(instances, false);\n}"
  },
  {
    "path": "src/Registration/Extensions/DependencyRemapperExtensions.cs",
    "content": "﻿using Stashbox.Registration.Fluent;\nusing System;\n\nnamespace Stashbox;\n\n/// <summary>\n/// Represents the extension methods of <see cref=\"IDependencyReMapper\"/>.\n/// </summary>\npublic static class DependencyReMapperExtensions\n{\n    /// <summary>\n    /// Re-maps an existing registration.\n    /// </summary>\n    /// <param name=\"reMapper\">The re-mapper.</param>\n    /// <param name=\"typeTo\">The service/implementation type.</param>\n    /// <param name=\"configurator\">The configurator for the registered type.</param>\n    /// <returns>The <see cref=\"IStashboxContainer\"/> instance.</returns>\n    public static IStashboxContainer ReMap(this IDependencyReMapper reMapper, Type typeTo, Action<RegistrationConfigurator>? configurator = null) =>\n        reMapper.ReMap(typeTo, typeTo, configurator);\n}"
  },
  {
    "path": "src/Registration/Extensions/ServiceRepositoryExtensions.cs",
    "content": "﻿using Stashbox.Registration.SelectionRules;\nusing Stashbox.Resolution;\nusing Stashbox.Utils.Data;\nusing Stashbox.Utils.Data.Immutable;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\n\nnamespace Stashbox.Registration.Extensions;\n\ninternal static class ServiceRepositoryExtensions\n{\n    public static bool ContainsRegistration(this ImmutableTree<Type, ImmutableBucket<ServiceRegistration>> repository, Type type, object? name, bool includeOpenGenerics)\n    {\n        var registrations = repository.GetOrDefaultByRef(type);\n        if (name != null && registrations != null)\n            return Array.Exists(registrations.Repository, reg => name.Equals(reg.Name));\n\n        if (registrations != null || !includeOpenGenerics || !type.IsClosedGenericType()) return registrations != null;\n\n        registrations = repository.GetOrDefaultByRef(type.GetGenericTypeDefinition());\n        return registrations?.Repository != null && Array.Exists(registrations.Repository, reg => reg.ImplementationType.SatisfiesGenericConstraintsOf(type));\n    }\n\n    public static ServiceRegistration? SelectOrDefault(this IEnumerable<ServiceRegistration> registrations,\n        TypeInformation typeInformation,\n        ResolutionContext resolutionContext,\n        IRegistrationSelectionRule[] registrationSelectionRules)\n    {\n        var maxWeight = 0;\n        ServiceRegistration? result = null;\n\n        foreach (var serviceRegistration in registrations)\n        {\n            if (!registrationSelectionRules.IsSelectionPassed(typeInformation, serviceRegistration, resolutionContext, out var weight))\n                continue;\n\n            if (weight < maxWeight) continue;\n            maxWeight = weight;\n            result = serviceRegistration;\n        }\n\n        return result;\n    }\n\n    public static IEnumerable<ServiceRegistration>? FilterExclusiveOrDefault(this IEnumerable<ServiceRegistration> registrations,\n        TypeInformation typeInformation,\n        ResolutionContext resolutionContext,\n        IRegistrationSelectionRule[] registrationSelectionRules)\n    {\n        var common = new ExpandableArray<ServiceRegistration>();\n        var priority = new ExpandableArray<ServiceRegistration>();\n\n        foreach (var serviceRegistration in registrations)\n        {\n            if (!registrationSelectionRules.IsSelectionPassed(typeInformation, serviceRegistration, resolutionContext, out var weight))\n                continue;\n\n            if (weight > 0)\n                priority.Add(serviceRegistration);\n            else\n                common.Add(serviceRegistration);\n        }\n\n        if (common.Length == 0 && priority.Length == 0)\n            return null;\n\n        return priority.Length > 0\n            ? priority\n            : common;\n    }\n\n    public static IEnumerable<ServiceRegistration> FilterInclusive(this IEnumerable<ServiceRegistration> registrations,\n        TypeInformation typeInformation,\n        ResolutionContext resolutionContext,\n        IRegistrationSelectionRule[] registrationSelectionRules) =>\n        registrations.Where(serviceRegistration => registrationSelectionRules.IsSelectionPassed(typeInformation, serviceRegistration, resolutionContext, out _));\n\n    private static bool IsSelectionPassed(this IRegistrationSelectionRule[] registrationSelectionRules,\n        TypeInformation typeInformation, ServiceRegistration serviceRegistration,\n        ResolutionContext resolutionContext, out int weight)\n    {\n        weight = 0;\n        var filterLength = registrationSelectionRules.Length;\n        for (var i = 0; i < filterLength; i++)\n        {\n            if (!registrationSelectionRules[i].IsValidForCurrentRequest(typeInformation, serviceRegistration, resolutionContext, out var shouldIncrementWeight))\n                return false;\n\n            if (shouldIncrementWeight)\n                weight++;\n        }\n\n        return true;\n    }\n}"
  },
  {
    "path": "src/Registration/Fluent/BaseDecoratorConfigurator.cs",
    "content": "﻿using Stashbox.Lifetime;\nusing System;\nusing System.Linq;\nusing Stashbox.Utils;\n\nnamespace Stashbox.Registration.Fluent;\n\n/// <summary>\n/// Represents the generic base of the fluent registration api.\n/// </summary>\n/// <typeparam name=\"TConfigurator\"></typeparam>\npublic class BaseDecoratorConfigurator<TConfigurator> : BaseFluentConfigurator<TConfigurator>\n    where TConfigurator : BaseDecoratorConfigurator<TConfigurator>\n{\n    internal BaseDecoratorConfigurator(Type serviceType, Type implementationType, object? name)\n        : base(serviceType, implementationType, name, Lifetimes.Empty, true)\n    { }\n\n    /// <summary>\n    /// Sets a decorated target condition for the registration.\n    /// </summary>\n    /// <typeparam name=\"TTarget\">The type of the parent.</typeparam>\n    /// <returns>The fluent configurator.</returns>\n    public TConfigurator WhenDecoratedServiceIs<TTarget>() where TTarget : class => this.WhenDecoratedServiceIs(TypeCache<TTarget>.Type);\n\n    /// <summary>\n    /// Sets a decorated target condition for the registration.\n    /// </summary>\n    /// <param name=\"targetType\">The type of the decorated service.</param>\n    /// <returns>The fluent configurator.</returns>\n    public TConfigurator WhenDecoratedServiceIs(Type targetType) => this.When(typeInfo => typeInfo.Type == targetType);\n\n    /// <summary>\n    /// Sets a decorated target condition for the registration.\n    /// </summary>\n    /// <param name=\"name\">The name of the decorated service.</param>\n    /// <returns>The fluent configurator.</returns>\n    public TConfigurator WhenDecoratedServiceIs(object name) => this.When(typeInfo => name.Equals(typeInfo.DependencyName));\n\n    /// <summary>\n    /// Sets an attribute condition that the decorated target has to satisfy.\n    /// </summary>\n    /// <typeparam name=\"TAttribute\">The type of the attribute.</typeparam>\n    /// <returns>The fluent configurator.</returns>\n    public TConfigurator WhenDecoratedServiceHas<TAttribute>() where TAttribute : Attribute => this.WhenDecoratedServiceHas(TypeCache<TAttribute>.Type);\n\n    /// <summary>\n    /// Sets an attribute condition that the decorated target has to satisfy.\n    /// </summary>\n    /// <param name=\"attributeType\">The type of the attribute.</param>\n    /// <returns>The fluent configurator.</returns>\n    public TConfigurator WhenDecoratedServiceHas(Type attributeType) =>\n        this.When(t => t.Type.GetCustomAttributes(attributeType, false).FirstOrDefault() != null);\n}"
  },
  {
    "path": "src/Registration/Fluent/BaseFluentConfigurator.cs",
    "content": "﻿using Stashbox.Configuration;\nusing Stashbox.Exceptions;\nusing Stashbox.Lifetime;\nusing Stashbox.Resolution;\nusing Stashbox.Utils;\nusing Stashbox.Utils.Data;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Reflection;\n\nnamespace Stashbox.Registration.Fluent;\n\n/// <summary>\n/// Represents the base of the fluent registration api.\n/// </summary>\n/// <typeparam name=\"TConfigurator\"></typeparam>\npublic class BaseFluentConfigurator<TConfigurator> : ServiceRegistration\n    where TConfigurator : BaseFluentConfigurator<TConfigurator>\n{\n    /// <summary>\n    /// The service type.\n    /// </summary>\n    public Type ServiceType { get; }\n\n    internal BaseFluentConfigurator(Type serviceType, Type implementationType, object? name,\n        LifetimeDescriptor lifetimeDescriptor, bool isDecorator)\n        : base(implementationType, name, lifetimeDescriptor, isDecorator)\n    {\n        this.ServiceType = serviceType;\n    }\n\n    /// <summary>\n    /// Determines whether the registration is mapped to the given service type.\n    /// </summary>\n    /// <typeparam name=\"TService\">The target service type.</typeparam>\n    /// <returns>True when the registration is mapped to the given service type, otherwise false.</returns>\n    public bool HasServiceType<TService>() => this.HasServiceType(TypeCache<TService>.Type);\n    \n    /// <summary>\n    /// Determines whether the registration is mapped to the given service type.\n    /// </summary>\n    /// <param name=\"serviceType\">The target service type.</param>\n    /// <returns>True when the registration is mapped to the given service type, otherwise false.</returns>\n    public bool HasServiceType(Type serviceType)\n    {\n        Shield.EnsureNotNull(serviceType, nameof(serviceType));\n        if (this.ServiceType == serviceType)\n            return true;\n\n        if (this.Options == null)\n            return false;\n        \n        if (this.Options.TryGetValue(RegistrationOption.AdditionalServiceTypes, out var option) && option is ExpandableArray<Type> serviceTypes)\n            return serviceTypes.Contains(serviceType);\n\n        return false;\n    }\n    \n    /// <summary>\n    /// Sets the lifetime of the registration.\n    /// </summary>\n    /// <param name=\"lifetime\">An <see cref=\"LifetimeDescriptor\"/> implementation.</param>\n    /// <returns>The configurator itself.</returns>\n    public TConfigurator WithLifetime(LifetimeDescriptor lifetime)\n    {\n        this.Lifetime = lifetime;\n        return (TConfigurator)this;\n    }\n\n    /// <summary>\n    /// Sets scoped lifetime for the registration.\n    /// </summary>\n    /// <returns>The configurator itself.</returns>\n    public TConfigurator WithScopedLifetime() => this.WithLifetime(Lifetimes.Scoped);\n\n    /// <summary>\n    /// Sets singleton lifetime for the registration.\n    /// </summary>\n    /// <returns>The configurator itself.</returns>\n    public TConfigurator WithSingletonLifetime() => this.WithLifetime(Lifetimes.Singleton);\n\n    /// <summary>\n    /// Sets transient lifetime for the registration.\n    /// </summary>\n    /// <returns>The configurator itself.</returns>\n    public TConfigurator WithTransientLifetime() => this.WithLifetime(Lifetimes.Transient);\n\n    /// <summary>\n    /// Sets the lifetime to <see cref=\"PerRequestLifetime\"/>. This lifetime will create a new instance between resolution requests. \n    /// Within the request the same instance will be re-used.\n    /// </summary>\n    /// <returns>The configurator itself.</returns>\n    public TConfigurator WithPerRequestLifetime() => this.WithLifetime(Lifetimes.PerRequest);\n    \n    /// <summary>\n    /// Sets the lifetime to auto lifetime. This lifetime aligns to the lifetime of the resolved service's dependencies.\n    /// When the underlying service has a dependency with a higher lifespan, this lifetime will inherit that lifespan up to a given boundary.\n    /// </summary>\n    /// <param name=\"boundaryLifetime\">The lifetime that represents a boundary which the derived lifetime must not exceed.</param>\n    /// <returns>The configurator itself.</returns>\n    public TConfigurator WithAutoLifetime(LifetimeDescriptor boundaryLifetime) => this.WithLifetime(Lifetimes.Auto(boundaryLifetime));\n\n    /// <summary>\n    /// Sets a scope name condition for the registration, it will be used only when a scope with the given name requests it.\n    /// </summary>\n    /// <param name=\"scopeName\">The name of the scope.</param>\n    /// <returns>The configurator itself.</returns>\n    public TConfigurator InNamedScope(object scopeName) => this.WithLifetime(Lifetimes.NamedScope(scopeName));\n\n    /// <summary>\n    /// Sets a condition for the registration that it will be used only within the scope defined by the given type.\n    /// </summary>\n    /// <param name=\"type\">The type which defines the scope.</param>\n    /// <returns>The configurator itself.</returns>\n    public TConfigurator InScopeDefinedBy(Type type) => this.WithLifetime(Lifetimes.NamedScope(type));\n\n    /// <summary>\n    /// Sets a condition for the registration that it will be used only within the scope defined by the given type.\n    /// </summary>\n    /// <returns>The configurator itself.</returns>\n    public TConfigurator InScopeDefinedBy<TScopeDefiner>() => this.WithLifetime(Lifetimes.NamedScope(TypeCache<TScopeDefiner>.Type));\n\n    /// <summary>\n    /// Binds a constructor/method parameter or a property/field to a named registration, so the container will perform a named resolution on the bound dependency.\n    /// </summary>\n    /// <param name=\"dependencyName\">The name of the bound named registration.</param>\n    /// <returns>The configurator itself.</returns>\n    public TConfigurator WithDependencyBinding<TDependency>(object? dependencyName = null) =>\n        this.WithDependencyBinding(TypeCache<TDependency>.Type, dependencyName);\n\n    /// <summary>\n    /// Binds a constructor/method parameter or a property/field to a named registration, so the container will perform a named resolution on the bound dependency.\n    /// </summary>\n    /// <param name=\"dependencyType\">The type of the dependency to search for.</param>\n    /// <param name=\"dependencyName\">The name of the bound named registration.</param>\n    /// <returns>The fluent configurator.</returns>\n    public TConfigurator WithDependencyBinding(Type dependencyType, object? dependencyName = null)\n    {\n        Shield.EnsureNotNull(dependencyType, nameof(dependencyType));\n\n        this.Options ??= new Dictionary<RegistrationOption, object?>();\n        if (this.Options.TryGetValue(RegistrationOption.DependencyBindings, out var value) && value is Dictionary<object, object?> bindings)\n            bindings.Add(dependencyType, dependencyName);\n        else\n            this.Options[RegistrationOption.DependencyBindings] = new Dictionary<object, object?> { { dependencyType, dependencyName } };\n\n        return (TConfigurator)this;\n    }\n\n    /// <summary>\n    /// Binds a constructor/method parameter or a property/field to a named registration, so the container will perform a named resolution on the bound dependency.\n    /// </summary>\n    /// <param name=\"parameterName\">The parameter name of the dependency to search for.</param>\n    /// <param name=\"dependencyName\">The name of the bound named registration.</param>\n    /// <returns>The fluent configurator.</returns>\n    public TConfigurator WithDependencyBinding(string parameterName, object? dependencyName = null)\n    {\n        Shield.EnsureNotNull(parameterName, nameof(parameterName));\n\n        this.Options ??= new Dictionary<RegistrationOption, object?>();\n        if (this.Options.TryGetValue(RegistrationOption.DependencyBindings, out var value) && value is Dictionary<object, object?> bindings)\n            bindings.Add(parameterName, dependencyName);\n        else\n            this.Options[RegistrationOption.DependencyBindings] = new Dictionary<object, object?> { { parameterName, dependencyName } };\n\n        return (TConfigurator)this;\n    }\n\n    /// <summary>\n    /// Sets a parent target condition for the registration.\n    /// </summary>\n    /// <typeparam name=\"TTarget\">The type of the parent.</typeparam>\n    /// <param name=\"name\">The optional name of the parent.</param>\n    /// <returns>The configurator itself.</returns>\n    public TConfigurator WhenDependantIs<TTarget>(object? name = null) where TTarget : class => this.WhenDependantIs(TypeCache<TTarget>.Type, name);\n\n    /// <summary>\n    /// Sets a parent target condition for the registration.\n    /// </summary>\n    /// <param name=\"targetType\">The type of the parent.</param>\n    /// <param name=\"name\">The optional name of the parent.</param>\n    /// <returns>The configurator itself.</returns>\n    public TConfigurator WhenDependantIs(Type targetType, object? name = null)\n    {\n        Shield.EnsureNotNull(targetType, nameof(targetType));\n\n        this.Options ??= new Dictionary<RegistrationOption, object?>();\n        if (this.Options.TryGetValue(RegistrationOption.ConditionOptions, out var value) && value is ConditionOptions conditions)\n        {\n            conditions.TargetTypeConditions ??= [];\n            conditions.TargetTypeConditions.Add(new ReadOnlyKeyValue<object?, Type>(name, targetType));\n        }\n        else\n            this.Options[RegistrationOption.ConditionOptions] = \n                new ConditionOptions { TargetTypeConditions = new ExpandableArray<object?, Type> { new ReadOnlyKeyValue<object?, Type>(name, targetType) } };\n\n        return (TConfigurator)this;\n    }\n\n    /// <summary>\n    /// Sets a resolution path condition for the registration. The service will be selected only in the resolution path of the given target.\n    /// This means that only the direct and sub-dependencies of the target type will get the configured service.\n    /// </summary>\n    /// <typeparam name=\"TTarget\">The type of the parent.</typeparam>\n    /// <param name=\"name\">The optional name of the parent.</param>\n    /// <returns>The configurator itself.</returns>\n    public TConfigurator WhenInResolutionPathOf<TTarget>(object? name = null) where TTarget : class => this.WhenInResolutionPathOf(TypeCache<TTarget>.Type, name);\n\n    /// <summary>\n    /// Sets a resolution path condition for the registration. The service will be selected only in the resolution path of the given target.\n    /// This means that only the direct and sub-dependencies of the target type will get the configured service.\n    /// </summary>\n    /// <param name=\"targetType\">The type of the parent.</param>\n    /// <param name=\"name\">The optional name of the parent.</param>\n    /// <returns>The configurator itself.</returns>\n    public TConfigurator WhenInResolutionPathOf(Type targetType, object? name = null)\n    {\n        Shield.EnsureNotNull(targetType, nameof(targetType));\n\n        this.Options ??= new Dictionary<RegistrationOption, object?>();\n        if (this.Options.TryGetValue(RegistrationOption.ConditionOptions, out var value) && value is ConditionOptions conditions)\n        {\n            conditions.TargetTypeInResolutionPathConditions ??= [];\n            conditions.TargetTypeInResolutionPathConditions.Add(new ReadOnlyKeyValue<object?, Type>(name, targetType));\n        }\n        else\n            this.Options[RegistrationOption.ConditionOptions] =\n                new ConditionOptions { TargetTypeInResolutionPathConditions = new ExpandableArray<object?, Type> { new ReadOnlyKeyValue<object?, Type>(name, targetType) } };\n\n        return (TConfigurator)this;\n    }\n\n    /// <summary>\n    /// Sets an attribute condition for the registration.\n    /// </summary>\n    /// <typeparam name=\"TAttribute\">The type of the attribute.</typeparam>\n    /// <returns>The configurator itself.</returns>\n    public TConfigurator WhenHas<TAttribute>(object? name = null) where TAttribute : Attribute => this.WhenHas(TypeCache<TAttribute>.Type);\n\n    /// <summary>\n    /// Sets an attribute condition for the registration.\n    /// </summary>\n    /// <param name=\"attributeType\">The type of the attribute.</param>\n    /// <returns>The configurator itself.</returns>\n    public TConfigurator WhenHas(Type attributeType)\n    {\n        Shield.EnsureNotNull(attributeType, nameof(attributeType));\n\n        this.Options ??= new Dictionary<RegistrationOption, object?>();\n        if (this.Options.TryGetValue(RegistrationOption.ConditionOptions, out var value) && value is ConditionOptions conditions)\n        {\n            conditions.AttributeConditions ??= [];\n            conditions.AttributeConditions.Add(attributeType);\n        }\n        else\n            this.Options[RegistrationOption.ConditionOptions] = \n                new ConditionOptions { AttributeConditions = new ExpandableArray<Type> { attributeType } };\n\n        return (TConfigurator)this;\n    }\n\n    /// <summary>\n    /// Sets a resolution path condition for the registration. The service will be selected only in the resolution path of the target that has the given attribute.\n    /// This means that only the direct and sub-dependencies of the target type that has the given attribute will get the configured service.\n    /// </summary>\n    /// <typeparam name=\"TAttribute\">The type of the attribute.</typeparam>\n    /// <returns>The configurator itself.</returns>\n    public TConfigurator WhenResolutionPathHas<TAttribute>(object? name = null) where TAttribute : Attribute => this.WhenResolutionPathHas(TypeCache<TAttribute>.Type, name);\n\n    /// <summary>\n    /// Sets a resolution path condition for the registration. The service will be selected only in the resolution path of the target that has the given attribute.\n    /// This means that only the direct and sub-dependencies of the target type that has the given attribute will get the configured service.\n    /// </summary>\n    /// <param name=\"attributeType\">The type of the attribute.</param>\n    /// <param name=\"name\">The optional name of the target that has the desired attribute.</param>\n    /// <returns>The configurator itself.</returns>\n    public TConfigurator WhenResolutionPathHas(Type attributeType, object? name = null)\n    {\n        Shield.EnsureNotNull(attributeType, nameof(attributeType));\n\n        this.Options ??= new Dictionary<RegistrationOption, object?>();\n        if (this.Options.TryGetValue(RegistrationOption.ConditionOptions, out var value) && value is ConditionOptions conditions)\n        {\n            conditions.AttributeInResolutionPathConditions ??= [];\n            conditions.AttributeInResolutionPathConditions.Add(new ReadOnlyKeyValue<object?, Type>(name, attributeType));\n        }\n        else\n            this.Options[RegistrationOption.ConditionOptions] =\n                new ConditionOptions { AttributeInResolutionPathConditions = new ExpandableArray<object?, Type> { new ReadOnlyKeyValue<object?, Type>(name, attributeType) } };\n\n        return (TConfigurator)this;\n    }\n\n    /// <summary>\n    /// Sets a generic condition for the registration.\n    /// </summary>\n    /// <param name=\"resolutionCondition\">The predicate.</param>\n    /// <returns>The configurator itself.</returns>\n    public TConfigurator When(Func<TypeInformation, bool> resolutionCondition)\n    {\n        Shield.EnsureNotNull(resolutionCondition, nameof(resolutionCondition));\n\n        this.Options ??= new Dictionary<RegistrationOption, object?>();\n        if (this.Options.TryGetValue(RegistrationOption.ConditionOptions, out var value) && value is ConditionOptions conditions)\n        {\n            conditions.ResolutionConditions ??= [];\n            conditions.ResolutionConditions.Add(resolutionCondition);\n        }\n        else\n            this.Options[RegistrationOption.ConditionOptions] = new ConditionOptions { ResolutionConditions = new ExpandableArray<Func<TypeInformation, bool>> { resolutionCondition } };\n\n        return (TConfigurator)this;\n    }\n\n    /// <summary>\n    /// Sets injection parameters for the registration.\n    /// </summary>\n    /// <param name=\"injectionParameters\">The injection parameters.</param>\n    /// <returns>The fluent configurator.</returns>\n    public TConfigurator WithInjectionParameters(params KeyValuePair<string, object?>[] injectionParameters)\n    {\n        this.Options ??= new Dictionary<RegistrationOption, object?>();\n        if (this.Options.TryGetValue(RegistrationOption.InjectionParameters, out var value) && value is ExpandableArray<KeyValuePair<string, object?>> parameters)\n            parameters.AddRange(injectionParameters);\n        else\n            this.Options[RegistrationOption.InjectionParameters] = new ExpandableArray<KeyValuePair<string, object?>>(injectionParameters);\n\n        return (TConfigurator)this;\n    }\n\n    /// <summary>\n    /// Sets injection parameters for the registration.\n    /// </summary>\n    /// <param name=\"name\">The name of the injection parameter.</param>\n    /// <param name=\"value\">The value of the injection parameter.</param>\n    /// <returns>The fluent configurator.</returns>\n    public TConfigurator WithInjectionParameter(string name, object? value)\n    {\n        Shield.EnsureNotNull(name, nameof(name));\n\n        this.Options ??= new Dictionary<RegistrationOption, object?>();\n        if (this.Options.TryGetValue(RegistrationOption.InjectionParameters, out var injectionParams) && injectionParams is ExpandableArray<KeyValuePair<string, object?>> parameters)\n            parameters.Add(new KeyValuePair<string, object?>(name, value));\n        else\n            this.Options[RegistrationOption.InjectionParameters] = new ExpandableArray<KeyValuePair<string, object?>> { new KeyValuePair<string, object?>(name, value) };\n\n        return (TConfigurator)this;\n    }\n\n    /// <summary>\n    /// Enables auto member injection on the registration.\n    /// </summary>\n    /// <param name=\"rule\">The auto member injection rule.</param>\n    /// <param name=\"filter\">A filter delegate used to determine which members should be auto injected and which are not.</param>\n    /// <returns>The fluent configurator.</returns>\n    public TConfigurator WithAutoMemberInjection(Rules.AutoMemberInjectionRules rule = Rules.AutoMemberInjectionRules.PropertiesWithPublicSetter, Func<MemberInfo, bool>? filter = null)\n    {\n        this.Options ??= new Dictionary<RegistrationOption, object?>();\n        this.Options[RegistrationOption.AutoMemberOptions] = new AutoMemberOptions(rule, filter);\n\n        return (TConfigurator)this;\n    }\n    \n    /// <summary>\n    /// Enables or disables required member injection.\n    /// </summary>\n    /// <param name=\"enabled\">True when the feature should be enabled, otherwise false.</param>\n    /// <returns>The container configurator.</returns>\n    public TConfigurator WithRequiredMemberInjection(bool enabled = true)\n    {\n        this.Options ??= new Dictionary<RegistrationOption, object?>();\n        this.Options[RegistrationOption.RequiredMemberInjectionEnabled] = enabled;\n\n        return (TConfigurator)this;\n    }\n\n    /// <summary>\n    /// The constructor selection rule.\n    /// </summary>\n    /// <param name=\"rule\">The constructor selection rule.</param>\n    /// <returns>The fluent configurator.</returns>\n    public TConfigurator WithConstructorSelectionRule(Func<IEnumerable<ConstructorInfo>, IEnumerable<ConstructorInfo>> rule)\n    {\n        this.Options ??= new Dictionary<RegistrationOption, object?>();\n        this.Options[RegistrationOption.ConstructorSelectionRule] = rule;\n\n        return (TConfigurator)this;\n    }\n\n    /// <summary>\n    /// Sets the selected constructor.\n    /// </summary>\n    /// <param name=\"argumentTypes\">The constructor argument types.</param>\n    /// <returns>The fluent configurator.</returns>\n    /// <exception cref=\"ConstructorNotFoundException\" />\n    public TConfigurator WithConstructorByArgumentTypes(params Type[] argumentTypes)\n    {\n        var constructor = this.ImplementationType.GetConstructor(argumentTypes);\n        if (constructor == null)\n        {\n            ThrowConstructorNotFoundException(this.ImplementationType, argumentTypes);\n            return (TConfigurator)this;\n        }\n\n        this.Options ??= new Dictionary<RegistrationOption, object?>();\n        this.Options[RegistrationOption.ConstructorOptions] = new ConstructorOptions(constructor, null);\n\n        return (TConfigurator)this;\n    }\n\n    /// <summary>\n    /// Sets the selected constructor.\n    /// </summary>\n    /// <param name=\"arguments\">The constructor arguments.</param>\n    /// <returns>The fluent configurator.</returns>\n    /// <exception cref=\"ConstructorNotFoundException\" />\n    public TConfigurator WithConstructorByArguments(params object[] arguments)\n    {\n        var argTypes = arguments.Select(arg => arg.GetType()).ToArray();\n        var constructor = this.ImplementationType.GetConstructor(argTypes);\n        if (constructor == null)\n        {\n            ThrowConstructorNotFoundException(this.ImplementationType, argTypes);\n            return (TConfigurator)this;\n        }\n\n        this.Options ??= new Dictionary<RegistrationOption, object?>();\n        this.Options[RegistrationOption.ConstructorOptions] = new ConstructorOptions(constructor, arguments);\n\n        return (TConfigurator)this;\n    }\n\n    /// <summary>\n    /// Tells the container that it shouldn't track the resolved transient object for disposal.\n    /// </summary>\n    /// <returns>The fluent configurator.</returns>\n    public TConfigurator WithoutDisposalTracking()\n    {\n        this.Options ??= new Dictionary<RegistrationOption, object?>();\n        this.Options[RegistrationOption.IsLifetimeExternallyOwned] = true;\n\n        return (TConfigurator)this;\n    }\n\n    /// <summary>\n    /// Tells the container that it should replace an existing registration with the current one, or add it if there is no existing found.\n    /// </summary>\n    /// <returns>The fluent configurator.</returns>\n    public TConfigurator ReplaceExisting()\n    {\n        this.Options ??= new Dictionary<RegistrationOption, object?>();\n        this.Options[RegistrationOption.ReplaceExistingRegistration] = true;\n\n        return (TConfigurator)this;\n    }\n\n    /// <summary>\n    /// Tells the container that it should replace an existing registration with the current one, but only if there is an existing registration.\n    /// </summary>\n    /// <returns>The fluent configurator.</returns>\n    public TConfigurator ReplaceOnlyIfExists()\n    {\n        this.Options ??= new Dictionary<RegistrationOption, object?>();\n        this.Options[RegistrationOption.ReplaceExistingRegistrationOnlyIfExists] = true;\n\n        return (TConfigurator)this;\n    }\n\n    /// <summary>\n    /// Registers the given service by all of it's implemented types.\n    /// </summary>\n    /// <returns>The configurator itself.</returns>\n    public TConfigurator AsImplementedTypes()\n    {\n        this.Options ??= new Dictionary<RegistrationOption, object?>();\n        var additionalTypes = this.ImplementationType.GetRegisterableInterfaceTypes()\n            .Concat(this.ImplementationType.GetRegisterableBaseTypes());\n        if (this.Options.TryGetValue(RegistrationOption.AdditionalServiceTypes, out var option) && option is ExpandableArray<Type> serviceTypes)\n            serviceTypes.AddRange(additionalTypes);\n        else\n            this.Options[RegistrationOption.AdditionalServiceTypes] = new ExpandableArray<Type>(additionalTypes);\n        \n        return (TConfigurator)this;\n    }\n\n    /// <summary>\n    /// Binds the currently configured registration to an additional service type.\n    /// </summary>\n    /// <returns>The configurator itself.</returns>\n    public TConfigurator AsServiceAlso<TAdditionalService>() =>\n        this.AsServiceAlso(TypeCache<TAdditionalService>.Type);\n\n    /// <summary>\n    /// Binds the currently configured registration to an additional service type.\n    /// </summary>\n    /// <param name=\"serviceType\">The additional service type.</param>\n    /// <returns>The configurator itself.</returns>\n    public TConfigurator AsServiceAlso(Type serviceType)\n    {\n        if (!IsFactory() && !this.ImplementationType.Implements(serviceType))\n            throw new ArgumentException($\"The implementation type {this.ImplementationType} does not implement the given service type {serviceType}.\");\n\n        this.Options ??= new Dictionary<RegistrationOption, object?>();\n        if (this.Options.TryGetValue(RegistrationOption.AdditionalServiceTypes, out var option) && option is ExpandableArray<Type> serviceTypes)\n            serviceTypes.Add(serviceType);\n        else\n            this.Options[RegistrationOption.AdditionalServiceTypes] = new ExpandableArray<Type> { serviceType };\n\n        return (TConfigurator)this;\n    }\n\n    internal void ValidateTypeMap()\n    {\n        if (IsFactory())\n            return;\n\n        Shield.EnsureTypeMapIsValid(ServiceType, ImplementationType);\n    }\n\n    internal void ValidateImplementationIsResolvable()\n    {\n        if (IsFactory())\n            return;\n\n        Shield.EnsureIsResolvable(ImplementationType);\n    }\n\n    private protected TConfigurator SetFactory(Delegate factory, Type implementationType, bool isCompiledLambda, params Type[] parameterTypes)\n    {\n        Shield.EnsureNotNull(implementationType, nameof(implementationType));\n\n        this.ImplementationType = implementationType;\n        return this.SetFactory(factory, isCompiledLambda, parameterTypes);\n    }\n    \n    private protected TConfigurator SetFactory(Delegate factory, bool isCompiledLambda, params Type[] parameterTypes)\n    {\n        Shield.EnsureNotNull(factory, nameof(factory));\n\n        this.Options ??= new Dictionary<RegistrationOption, object?>();\n        this.Options[RegistrationOption.RegistrationTypeOptions] = new FactoryOptions(factory, parameterTypes, isCompiledLambda);\n\n        return (TConfigurator)this;\n    }\n\n    private static void ThrowConstructorNotFoundException(Type type, params Type[] argTypes)\n    {\n        throw argTypes.Length switch\n        {\n            0 => new ConstructorNotFoundException(type),\n            1 => new ConstructorNotFoundException(type, argTypes[0]),\n            _ => new ConstructorNotFoundException(type, argTypes)\n        };\n    }\n}"
  },
  {
    "path": "src/Registration/Fluent/DecoratorConfigurator.cs",
    "content": "﻿using Stashbox.Utils;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq.Expressions;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace Stashbox.Registration.Fluent;\n\n/// <summary>\n/// Represents the fluent service decorator registration api.\n/// </summary>\npublic class DecoratorConfigurator<TService, TImplementation> : BaseDecoratorConfigurator<DecoratorConfigurator<TService, TImplementation>>\n    where TService : class\n    where TImplementation : class, TService\n{\n    internal DecoratorConfigurator(Type serviceType, Type implementationType, object? name = null)\n        : base(serviceType, implementationType, name)\n    { }\n\n    /// <summary>\n    /// Sets a member (property / field) as a dependency that should be filled by the container.\n    /// </summary>\n    /// <param name=\"expression\">The member expression.</param>\n    /// <param name=\"dependencyName\">The name of the dependency.</param>\n    /// <returns>The fluent configurator.</returns>\n    public DecoratorConfigurator<TService, TImplementation> WithDependencyBinding<TResult>(Expression<Func<TImplementation, TResult>> expression, object? dependencyName = null)\n    {\n        if (expression.Body is not MemberExpression memberExpression)\n            throw new ArgumentException(\"The expression must be a member expression (Property or Field)\",\n                nameof(expression));\n\n        this.Options ??= new Dictionary<RegistrationOption, object?>();\n        if (this.Options.TryGetValue(RegistrationOption.DependencyBindings, out var value) && value is Dictionary<object, object?> bindings)\n            bindings.Add(memberExpression.Member.Name, dependencyName);\n        else\n            this.Options[RegistrationOption.DependencyBindings] = new Dictionary<object, object?> { { memberExpression.Member.Name, dependencyName } };\n\n        return this;\n    }\n\n    /// <summary>\n    /// Sets a delegate which will be called when the container is being disposed.\n    /// </summary>\n    /// <param name=\"finalizer\">The cleanup delegate.</param>\n    /// <returns>The fluent configurator.</returns>\n    public DecoratorConfigurator<TService, TImplementation> WithFinalizer(Action<TImplementation> finalizer)\n    {\n        Shield.EnsureNotNull(finalizer, nameof(finalizer));\n\n        this.Options ??= new Dictionary<RegistrationOption, object?>();\n        this.Options[RegistrationOption.Finalizer] = new Action<object>(o => finalizer((TImplementation)o));\n\n        return this;\n    }\n\n    /// <summary>\n    /// Sets a delegate which will be called when the service is being constructed.\n    /// </summary>\n    /// <param name=\"initializer\">The initializer delegate.</param>\n    /// <returns>The fluent configurator.</returns>\n    public DecoratorConfigurator<TService, TImplementation> WithInitializer(Action<TImplementation, IDependencyResolver> initializer)\n    {\n        Shield.EnsureNotNull(initializer, nameof(initializer));\n\n        this.Options ??= new Dictionary<RegistrationOption, object?>();\n        this.Options[RegistrationOption.Initializer] = initializer;\n\n        return this;\n    }\n\n    /// <summary>\n    /// Sets an async initializer delegate which will be called when <see cref=\"IDependencyResolver.InvokeAsyncInitializers\"/> is called.\n    /// </summary>\n    /// <param name=\"initializer\">The async initializer delegate.</param>\n    /// <returns>The fluent configurator.</returns>\n    public DecoratorConfigurator<TService, TImplementation> WithAsyncInitializer(Func<TImplementation, IDependencyResolver, CancellationToken, Task> initializer)\n    {\n        Shield.EnsureNotNull(initializer, nameof(initializer));\n\n        this.Options ??= new Dictionary<RegistrationOption, object?>();\n        this.Options[RegistrationOption.AsyncInitializer] = new Func<object, IDependencyResolver, CancellationToken, Task>((o, r, t) => initializer((TImplementation)o, r, t));\n\n        return this;\n    }\n\n    /// <summary>\n    /// Sets a parameter-less factory delegate for the registration.\n    /// </summary>\n    /// <param name=\"factory\">The factory delegate.</param>\n    /// <param name=\"isCompiledLambda\">Flag that indicates the passed factory delegate is a compiled lambda from <see cref=\"Expression\"/>.</param>\n    /// <returns>The fluent configurator.</returns>\n    public DecoratorConfigurator<TService, TImplementation> WithFactory(Func<TImplementation> factory, bool isCompiledLambda = false) =>\n        this.SetFactory(factory, isCompiledLambda, TypeCache<TImplementation>.Type);\n\n    /// <summary>\n    /// Sets a factory delegate for the registration that takes an <see cref=\"IDependencyResolver\"/> as parameter.\n    /// </summary>\n    /// <param name=\"factory\">The factory delegate.</param>\n    /// <param name=\"isCompiledLambda\">Flag that indicates the passed factory delegate is a compiled lambda from <see cref=\"Expression\"/>.</param>\n    /// <returns>The fluent configurator.</returns>\n    public DecoratorConfigurator<TService, TImplementation> WithFactory(Func<IDependencyResolver, TImplementation> factory, bool isCompiledLambda = false) =>\n        this.SetFactory(factory, isCompiledLambda, TypeCache<IDependencyResolver>.Type, TypeCache<TImplementation>.Type);\n\n    /// <summary>\n    /// Sets a parameterized factory delegate for the registration.\n    /// </summary>\n    /// <param name=\"factory\">The parameterized factory delegate.</param>\n    /// <param name=\"isCompiledLambda\">Flag that indicates the passed factory delegate is a compiled lambda from <see cref=\"Expression\"/>.</param>\n    /// <returns>The fluent configurator.</returns>\n    public DecoratorConfigurator<TService, TImplementation> WithFactory<T1>(Func<T1, TImplementation> factory, bool isCompiledLambda = false) =>\n        this.SetFactory(factory, isCompiledLambda, TypeCache<T1>.Type, TypeCache<TImplementation>.Type);\n\n    /// <summary>\n    /// Sets a parameterized factory delegate for the registration.\n    /// </summary>\n    /// <param name=\"factory\">The parameterized factory delegate.</param>\n    /// <param name=\"isCompiledLambda\">Flag that indicates the passed factory delegate is a compiled lambda from <see cref=\"Expression\"/>.</param>\n    /// <returns>The fluent configurator.</returns>\n    public DecoratorConfigurator<TService, TImplementation> WithFactory<T1, T2>(Func<T1, T2, TImplementation> factory, bool isCompiledLambda = false) =>\n        this.SetFactory(factory, isCompiledLambda, TypeCache<T1>.Type, TypeCache<T2>.Type, TypeCache<TImplementation>.Type);\n\n    /// <summary>\n    /// Sets a parameterized factory delegate for the registration.\n    /// </summary>\n    /// <param name=\"factory\">The parameterized factory delegate.</param>\n    /// <param name=\"isCompiledLambda\">Flag that indicates the passed factory delegate is a compiled lambda from <see cref=\"Expression\"/>.</param>\n    /// <returns>The fluent configurator.</returns>\n    public DecoratorConfigurator<TService, TImplementation> WithFactory<T1, T2, T3>(Func<T1, T2, T3, TImplementation> factory, bool isCompiledLambda = false) =>\n        this.SetFactory(factory, isCompiledLambda, TypeCache<T1>.Type, TypeCache<T2>.Type, TypeCache<T3>.Type, TypeCache<TImplementation>.Type);\n\n    /// <summary>\n    /// Sets a parameterized factory delegate for the registration.\n    /// </summary>\n    /// <param name=\"factory\">The parameterized factory delegate.</param>\n    /// <param name=\"isCompiledLambda\">Flag that indicates the passed factory delegate is a compiled lambda from <see cref=\"Expression\"/>.</param>\n    /// <returns>The fluent configurator.</returns>\n    public DecoratorConfigurator<TService, TImplementation> WithFactory<T1, T2, T3, T4>(Func<T1, T2, T3, T4, TImplementation> factory, bool isCompiledLambda = false) =>\n        this.SetFactory(factory, isCompiledLambda, TypeCache<T1>.Type, TypeCache<T2>.Type, TypeCache<T3>.Type, TypeCache<T4>.Type, TypeCache<TImplementation>.Type);\n\n    /// <summary>\n    /// Sets a parameterized factory delegate for the registration.\n    /// </summary>\n    /// <param name=\"factory\">The parameterized factory delegate.</param>\n    /// <param name=\"isCompiledLambda\">Flag that indicates the passed factory delegate is a compiled lambda from <see cref=\"Expression\"/>.</param>\n    /// <returns>The fluent configurator.</returns>\n    public DecoratorConfigurator<TService, TImplementation> WithFactory<T1, T2, T3, T4, T5>(Func<T1, T2, T3, T4, T5, TImplementation> factory, bool isCompiledLambda = false) =>\n        this.SetFactory(factory, isCompiledLambda, TypeCache<T1>.Type, TypeCache<T2>.Type, TypeCache<T3>.Type, TypeCache<T4>.Type, TypeCache<T5>.Type, TypeCache<TImplementation>.Type);\n}\n\n/// <summary>\n/// Represents the fluent service decorator registration api.\n/// </summary>\npublic class DecoratorConfigurator : BaseDecoratorConfigurator<DecoratorConfigurator>\n{\n    internal DecoratorConfigurator(Type serviceType, Type implementationType, object? name = null)\n        : base(serviceType, implementationType, name)\n    { }\n\n    /// <summary>\n    /// Sets a container factory delegate for the registration.\n    /// </summary>\n    /// <param name=\"factory\">The container factory delegate.</param>\n    /// <param name=\"isCompiledLambda\">Flag that indicates the passed factory delegate is a compiled lambda from <see cref=\"Expression\"/>.</param>\n    /// <returns>The fluent configurator.</returns>\n    public DecoratorConfigurator WithFactory(Func<IDependencyResolver, object> factory, bool isCompiledLambda = false) =>\n        this.SetFactory(factory, isCompiledLambda, TypeCache<IDependencyResolver>.Type, TypeCache<object>.Type);\n\n    /// <summary>\n    /// Sets a parameter-less factory delegate for the registration.\n    /// </summary>\n    /// <param name=\"factory\">The factory delegate.</param>\n    /// <param name=\"isCompiledLambda\">Flag that indicates the passed factory delegate is a compiled lambda from <see cref=\"Expression\"/>.</param>\n    /// <returns>The fluent configurator.</returns>\n    public DecoratorConfigurator WithFactory(Func<object> factory, bool isCompiledLambda = false) =>\n        this.SetFactory(factory, isCompiledLambda, TypeCache<object>.Type);\n\n    /// <summary>\n    /// Sets a parameterized factory delegate for the registration.\n    /// </summary>\n    /// <param name=\"factory\">The parameterized factory delegate.</param>\n    /// <param name=\"isCompiledLambda\">Flag that indicates the passed factory delegate is a compiled lambda from <see cref=\"Expression\"/>.</param>\n    /// <returns>The fluent configurator.</returns>\n    public DecoratorConfigurator WithFactory<T1>(Func<T1, object> factory, bool isCompiledLambda = false) =>\n        this.SetFactory(factory, isCompiledLambda, TypeCache<T1>.Type, TypeCache<object>.Type);\n\n    /// <summary>\n    /// Sets a parameterized factory delegate for the registration.\n    /// </summary>\n    /// <param name=\"factory\">The parameterized factory delegate.</param>\n    /// <param name=\"isCompiledLambda\">Flag that indicates the passed factory delegate is a compiled lambda from <see cref=\"Expression\"/>.</param>\n    /// <returns>The fluent configurator.</returns>\n    public DecoratorConfigurator WithFactory<T1, T2>(Func<T1, T2, object> factory, bool isCompiledLambda = false) =>\n        this.SetFactory(factory, isCompiledLambda, TypeCache<T1>.Type, TypeCache<T2>.Type, TypeCache<object>.Type);\n\n    /// <summary>\n    /// Sets a parameterized factory delegate for the registration.\n    /// </summary>\n    /// <param name=\"factory\">The parameterized factory delegate.</param>\n    /// <param name=\"isCompiledLambda\">Flag that indicates the passed factory delegate is a compiled lambda from <see cref=\"Expression\"/>.</param>\n    /// <returns>The fluent configurator.</returns>\n    public DecoratorConfigurator WithFactory<T1, T2, T3>(Func<T1, T2, T3, object> factory, bool isCompiledLambda = false) =>\n        this.SetFactory(factory, isCompiledLambda, TypeCache<T1>.Type, TypeCache<T2>.Type, TypeCache<T3>.Type, TypeCache<object>.Type);\n\n    /// <summary>\n    /// Sets a parameterized factory delegate for the registration.\n    /// </summary>\n    /// <param name=\"factory\">The parameterized factory delegate.</param>\n    /// <param name=\"isCompiledLambda\">Flag that indicates the passed factory delegate is a compiled lambda from <see cref=\"Expression\"/>.</param>\n    /// <returns>The fluent configurator.</returns>\n    public DecoratorConfigurator WithFactory<T1, T2, T3, T4>(Func<T1, T2, T3, T4, object> factory, bool isCompiledLambda = false) =>\n        this.SetFactory(factory, isCompiledLambda, TypeCache<T1>.Type, TypeCache<T2>.Type, TypeCache<T3>.Type, TypeCache<T4>.Type, TypeCache<object>.Type);\n\n    /// <summary>\n    /// Sets a parameterized factory delegate for the registration.\n    /// </summary>\n    /// <param name=\"factory\">The parameterized factory delegate.</param>\n    /// <param name=\"isCompiledLambda\">Flag that indicates the passed factory delegate is a compiled lambda from <see cref=\"Expression\"/>.</param>\n    /// <returns>The fluent configurator.</returns>\n    public DecoratorConfigurator WithFactory<T1, T2, T3, T4, T5>(Func<T1, T2, T3, T4, T5, object> factory, bool isCompiledLambda = false) =>\n        this.SetFactory(factory, isCompiledLambda, TypeCache<T1>.Type, TypeCache<T2>.Type, TypeCache<T3>.Type, TypeCache<T4>.Type, TypeCache<T5>.Type, TypeCache<object>.Type);\n}"
  },
  {
    "path": "src/Registration/Fluent/FluentServiceConfigurator.cs",
    "content": "﻿using Stashbox.Lifetime;\nusing Stashbox.Utils;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq.Expressions;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Stashbox.Resolution;\n\nnamespace Stashbox.Registration.Fluent;\n\n/// <summary>\n/// Represents the generic fluent service registration api.\n/// </summary>\npublic class FluentServiceConfigurator<TService, TImplementation, TConfigurator> : FluentServiceConfigurator<TConfigurator>\n    where TConfigurator : FluentServiceConfigurator<TService, TImplementation, TConfigurator>\n    where TService : class\n    where TImplementation : class, TService\n{\n    internal FluentServiceConfigurator(Type serviceType, Type implementationType, object? name,\n        LifetimeDescriptor lifetimeDescriptor, bool isDecorator)\n        : base(serviceType, implementationType, name, lifetimeDescriptor, isDecorator)\n    { }\n\n    /// <summary>\n    /// Sets a member (property / field) as a dependency that should be filled by the container.\n    /// </summary>\n    /// <param name=\"expression\">The member expression.</param>\n    /// <param name=\"dependencyName\">The name of the dependency.</param>\n    /// <returns>The fluent configurator.</returns>\n    public TConfigurator WithDependencyBinding<TResult>(Expression<Func<TImplementation, TResult>> expression, object? dependencyName = null)\n    {\n        if (expression.Body is not MemberExpression memberExpression)\n            throw new ArgumentException(\"The expression must be a member expression (Property or Field)\",\n                nameof(expression));\n\n        this.Options ??= new Dictionary<RegistrationOption, object?>();\n        if (this.Options.TryGetValue(RegistrationOption.DependencyBindings, out var value) && value is Dictionary<object, object?> bindings)\n            bindings.Add(memberExpression.Member.Name, dependencyName);\n        else\n            this.Options[RegistrationOption.DependencyBindings] = new Dictionary<object, object?> { { memberExpression.Member.Name, dependencyName } };\n\n        return (TConfigurator)this;\n\n    }\n\n    /// <summary>\n    /// Sets a delegate which will be called when the container is being disposed.\n    /// </summary>\n    /// <param name=\"finalizer\">The cleanup delegate.</param>\n    /// <returns>The fluent configurator.</returns>\n    public TConfigurator WithFinalizer(Action<TImplementation> finalizer)\n    {\n        Shield.EnsureNotNull(finalizer, nameof(finalizer));\n\n        this.Options ??= new Dictionary<RegistrationOption, object?>();\n        this.Options[RegistrationOption.Finalizer] = new Action<object>(o => finalizer((TImplementation)o));\n\n        return (TConfigurator)this;\n    }\n\n    /// <summary>\n    /// Sets a delegate which will be called when the service is being constructed.\n    /// </summary>\n    /// <param name=\"initializer\">The initializer delegate.</param>\n    /// <returns>The fluent configurator.</returns>\n    public TConfigurator WithInitializer(Action<TImplementation, IDependencyResolver> initializer)\n    {\n        Shield.EnsureNotNull(initializer, nameof(initializer));\n\n        this.Options ??= new Dictionary<RegistrationOption, object?>();\n        this.Options[RegistrationOption.Initializer] = initializer;\n\n        return (TConfigurator)this;\n    }\n\n    /// <summary>\n    /// Sets an async initializer delegate which will be called when <see cref=\"IDependencyResolver.InvokeAsyncInitializers\"/> is called.\n    /// </summary>\n    /// <param name=\"initializer\">The async initializer delegate.</param>\n    /// <returns>The fluent configurator.</returns>\n    public TConfigurator WithAsyncInitializer(Func<TImplementation, IDependencyResolver, CancellationToken, Task> initializer)\n    {\n        Shield.EnsureNotNull(initializer, nameof(initializer));\n\n        this.Options ??= new Dictionary<RegistrationOption, object?>();\n        this.Options[RegistrationOption.AsyncInitializer] = new Func<object, IDependencyResolver, CancellationToken, Task>((o, r, t) => initializer((TImplementation)o, r, t));\n\n        return (TConfigurator)this;\n    }\n\n    /// <summary>\n    /// Sets a parameter-less factory delegate for the registration.\n    /// </summary>\n    /// <param name=\"factory\">The factory delegate.</param>\n    /// <param name=\"isCompiledLambda\">Flag that indicates the passed factory delegate is a compiled lambda from <see cref=\"Expression\"/>.</param>\n    /// <returns>The fluent configurator.</returns>\n    public TConfigurator WithFactory(Func<TImplementation> factory, bool isCompiledLambda = false)\n    {\n        this.SetFactory(factory, isCompiledLambda, TypeCache<TImplementation>.Type);\n        return (TConfigurator)this;\n    }\n    \n    /// <summary>\n    /// Sets a parameter-less factory delegate for the registration.\n    /// </summary>\n    /// <param name=\"factory\">The factory delegate.</param>\n    /// <param name=\"isCompiledLambda\">Flag that indicates the passed factory delegate is a compiled lambda from <see cref=\"Expression\"/>.</param>\n    /// <returns>The fluent configurator.</returns>\n    public TConfigurator WithFactory<TImpl>(Func<TImpl> factory, bool isCompiledLambda = false)\n    {\n        this.SetFactory(factory, TypeCache<TImpl>.Type, isCompiledLambda, TypeCache<TImpl>.Type);\n        return (TConfigurator)this;\n    }\n\n    /// <summary>\n    /// Sets a factory delegate for the registration that takes an <see cref=\"IDependencyResolver\"/> as parameter.\n    /// </summary>\n    /// <param name=\"factory\">The factory delegate.</param>\n    /// <param name=\"isCompiledLambda\">Flag that indicates the passed factory delegate is a compiled lambda from <see cref=\"Expression\"/>.</param>\n    /// <returns>The fluent configurator.</returns>\n    public TConfigurator WithFactory(Func<IDependencyResolver, TImplementation> factory, bool isCompiledLambda = false)\n    {\n        this.SetFactory(factory, isCompiledLambda, TypeCache<IDependencyResolver>.Type, TypeCache<TImplementation>.Type);\n        return (TConfigurator)this;\n    }\n    \n    /// <summary>\n    /// Sets a factory delegate for the registration that takes an <see cref=\"IDependencyResolver\"/> as parameter.\n    /// </summary>\n    /// <param name=\"factory\">The factory delegate.</param>\n    /// <param name=\"isCompiledLambda\">Flag that indicates the passed factory delegate is a compiled lambda from <see cref=\"Expression\"/>.</param>\n    /// <returns>The fluent configurator.</returns>\n    public TConfigurator WithFactory<TImpl>(Func<IDependencyResolver, TImpl> factory, bool isCompiledLambda = false)\n    {\n        this.SetFactory(factory, TypeCache<TImpl>.Type, isCompiledLambda, TypeCache<IDependencyResolver>.Type, TypeCache<TImpl>.Type);\n        return (TConfigurator)this;\n    }\n\n    /// <summary>\n    /// Sets a parameterized factory delegate for the registration.\n    /// </summary>\n    /// <param name=\"factory\">The parameterized factory delegate.</param>\n    /// <param name=\"isCompiledLambda\">Flag that indicates the passed factory delegate is a compiled lambda from <see cref=\"Expression\"/>.</param>\n    /// <returns>The fluent configurator.</returns>\n    public TConfigurator WithFactory<T1>(Func<T1, TImplementation> factory, bool isCompiledLambda = false)\n    {\n        this.SetFactory(factory, isCompiledLambda, TypeCache<T1>.Type, TypeCache<TImplementation>.Type);\n        return (TConfigurator)this;\n    }\n    \n    /// <summary>\n    /// Sets a parameterized factory delegate for the registration.\n    /// </summary>\n    /// <param name=\"factory\">The parameterized factory delegate.</param>\n    /// <param name=\"isCompiledLambda\">Flag that indicates the passed factory delegate is a compiled lambda from <see cref=\"Expression\"/>.</param>\n    /// <returns>The fluent configurator.</returns>\n    public TConfigurator WithFactory<T1, TImpl>(Func<T1, TImpl> factory, bool isCompiledLambda = false)\n    {\n        this.SetFactory(factory, TypeCache<TImpl>.Type, isCompiledLambda, TypeCache<T1>.Type, TypeCache<TImpl>.Type);\n        return (TConfigurator)this;\n    }\n\n    /// <summary>\n    /// Sets a parameterized factory delegate for the registration.\n    /// </summary>\n    /// <param name=\"factory\">The parameterized factory delegate.</param>\n    /// <param name=\"isCompiledLambda\">Flag that indicates the passed factory delegate is a compiled lambda from <see cref=\"Expression\"/>.</param>\n    /// <returns>The fluent configurator.</returns>\n    public TConfigurator WithFactory<T1, T2>(Func<T1, T2, TImplementation> factory, bool isCompiledLambda = false)\n    {\n        this.SetFactory(factory, isCompiledLambda, TypeCache<T1>.Type, TypeCache<T2>.Type, TypeCache<TImplementation>.Type);\n        return (TConfigurator)this;\n    }\n\n    /// <summary>\n    /// Sets a parameterized factory delegate for the registration.\n    /// </summary>\n    /// <param name=\"factory\">The parameterized factory delegate.</param>\n    /// <param name=\"isCompiledLambda\">Flag that indicates the passed factory delegate is a compiled lambda from <see cref=\"Expression\"/>.</param>\n    /// <returns>The fluent configurator.</returns>\n    public TConfigurator WithFactory<T1, T2, T3>(Func<T1, T2, T3, TImplementation> factory, bool isCompiledLambda = false)\n    {\n        this.SetFactory(factory, isCompiledLambda, TypeCache<T1>.Type, TypeCache<T2>.Type, TypeCache<T3>.Type, TypeCache<TImplementation>.Type);\n        return (TConfigurator)this;\n    }\n\n    /// <summary>\n    /// Sets a parameterized factory delegate for the registration.\n    /// </summary>\n    /// <param name=\"factory\">The parameterized factory delegate.</param>\n    /// <param name=\"isCompiledLambda\">Flag that indicates the passed factory delegate is a compiled lambda from <see cref=\"Expression\"/>.</param>\n    /// <returns>The fluent configurator.</returns>\n    public TConfigurator WithFactory<T1, T2, T3, T4>(Func<T1, T2, T3, T4, TImplementation> factory, bool isCompiledLambda = false)\n    {\n        this.SetFactory(factory, isCompiledLambda, TypeCache<T1>.Type, TypeCache<T2>.Type, TypeCache<T3>.Type, TypeCache<T4>.Type, TypeCache<TImplementation>.Type);\n        return (TConfigurator)this;\n    }\n\n    /// <summary>\n    /// Sets a parameterized factory delegate for the registration.\n    /// </summary>\n    /// <param name=\"factory\">The parameterized factory delegate.</param>\n    /// <param name=\"isCompiledLambda\">Flag that indicates the passed factory delegate is a compiled lambda from <see cref=\"Expression\"/>.</param>\n    /// <returns>The fluent configurator.</returns>\n    public TConfigurator WithFactory<T1, T2, T3, T4, T5>(Func<T1, T2, T3, T4, T5, TImplementation> factory, bool isCompiledLambda = false)\n    {\n        this.SetFactory(factory, isCompiledLambda, TypeCache<T1>.Type, TypeCache<T2>.Type, TypeCache<T3>.Type, TypeCache<T4>.Type, TypeCache<T5>.Type, TypeCache<TImplementation>.Type);\n        return (TConfigurator)this;\n    }\n}\n\n/// <summary>\n/// Represents the fluent service registration api.\n/// </summary>\npublic class FluentServiceConfigurator<TConfigurator> : BaseFluentConfigurator<TConfigurator>\n    where TConfigurator : FluentServiceConfigurator<TConfigurator>\n{\n    internal FluentServiceConfigurator(Type serviceType, Type implementationType, object? name,\n        LifetimeDescriptor lifetimeDescriptor, bool isDecorator)\n        : base(serviceType, implementationType, name, lifetimeDescriptor, isDecorator)\n    { }\n\n    /// <summary>\n    /// Indicates that the service's resolution should be handled by a dynamic <see cref=\"IDependencyResolver.Resolve(Type)\"/> call on the current <see cref=\"IDependencyResolver\"/> instead of a pre-built instantiation expression.\n    /// </summary>\n    /// <returns></returns>\n    public TConfigurator WithDynamicResolution()\n    {\n        this.Options ??= new Dictionary<RegistrationOption, object?>();\n        this.Options[RegistrationOption.IsResolutionCallRequired] = true;\n\n        return (TConfigurator)this;\n    }\n\n    /// <summary>\n    /// Sets the metadata.\n    /// </summary>\n    /// <param name=\"metadata\">The metadata.</param>\n    /// <returns>The fluent configurator.</returns>\n    public TConfigurator WithMetadata(object? metadata)\n    {\n        this.Options ??= new Dictionary<RegistrationOption, object?>();\n        this.Options[RegistrationOption.Metadata] = metadata;\n\n        return (TConfigurator)this;\n    }\n\n    /// <summary>\n    /// Sets the name of the registration.\n    /// </summary>\n    /// <param name=\"name\">The name of the registration.</param>\n    /// <returns>The fluent configurator.</returns>\n    public TConfigurator WithName(object? name)\n    {\n        this.Name = name;\n\n        return (TConfigurator)this;\n    }\n\n    /// <summary>\n    /// This registration is used as a logical scope for it's dependencies. Dependencies registered with the <see cref=\"BaseFluentConfigurator{TConfigurator}.InNamedScope\"/> with the same name will be preferred during resolution.\n    /// </summary>\n    /// <param name=\"scopeName\">The name of the scope. When the name is null, the type which defines the scope is used as name.</param>\n    /// <returns>The fluent configurator.</returns>\n    public TConfigurator DefinesScope(object? scopeName = null)\n    {\n        this.Options ??= new Dictionary<RegistrationOption, object?>();\n        this.Options[RegistrationOption.DefinedScopeName] = scopeName ?? this.ImplementationType;\n\n        return (TConfigurator)this;\n    }\n\n    /// <summary>\n    /// Sets a container factory delegate for the registration.\n    /// </summary>\n    /// <param name=\"factory\">The container factory delegate.</param>\n    /// <param name=\"isCompiledLambda\">Flag that indicates the passed factory delegate is a compiled lambda from <see cref=\"Expression\"/>.</param>\n    /// <returns>The fluent configurator.</returns>\n    public TConfigurator WithFactory(Func<IDependencyResolver, object> factory, bool isCompiledLambda = false) =>\n        this.SetFactory(factory, isCompiledLambda, TypeCache<IDependencyResolver>.Type, TypeCache<object>.Type);\n\n    /// <summary>\n    /// Sets a parameter-less factory delegate for the registration.\n    /// </summary>\n    /// <param name=\"factory\">The factory delegate.</param>\n    /// <param name=\"isCompiledLambda\">Flag that indicates the passed factory delegate is a compiled lambda from <see cref=\"Expression\"/>.</param>\n    /// <returns>The fluent configurator.</returns>\n    public TConfigurator WithFactory(Func<object> factory, bool isCompiledLambda = false) =>\n        this.SetFactory(factory, isCompiledLambda, TypeCache<object>.Type);\n\n    /// <summary>\n    /// Sets a parameterized factory delegate for the registration.\n    /// </summary>\n    /// <param name=\"factory\">The parameterized factory delegate.</param>\n    /// <param name=\"isCompiledLambda\">Flag that indicates the passed factory delegate is a compiled lambda from <see cref=\"Expression\"/>.</param>\n    /// <returns>The fluent configurator.</returns>\n    public TConfigurator WithFactory<T1>(Func<T1, object> factory, bool isCompiledLambda = false) =>\n        this.SetFactory(factory, isCompiledLambda, TypeCache<T1>.Type, TypeCache<object>.Type);\n\n    /// <summary>\n    /// Sets a parameterized factory delegate for the registration.\n    /// </summary>\n    /// <param name=\"factory\">The parameterized factory delegate.</param>\n    /// <param name=\"isCompiledLambda\">Flag that indicates the passed factory delegate is a compiled lambda from <see cref=\"Expression\"/>.</param>\n    /// <returns>The fluent configurator.</returns>\n    public TConfigurator WithFactory<T1, T2>(Func<T1, T2, object> factory, bool isCompiledLambda = false) =>\n        this.SetFactory(factory, isCompiledLambda, TypeCache<T1>.Type, TypeCache<T2>.Type, TypeCache<object>.Type);\n\n    /// <summary>\n    /// Sets a parameterized factory delegate for the registration.\n    /// </summary>\n    /// <param name=\"factory\">The parameterized factory delegate.</param>\n    /// <param name=\"isCompiledLambda\">Flag that indicates the passed factory delegate is a compiled lambda from <see cref=\"Expression\"/>.</param>\n    /// <returns>The fluent configurator.</returns>\n    public TConfigurator WithFactory<T1, T2, T3>(Func<T1, T2, T3, object> factory, bool isCompiledLambda = false) =>\n        this.SetFactory(factory, isCompiledLambda, TypeCache<T1>.Type, TypeCache<T2>.Type, TypeCache<T3>.Type, TypeCache<object>.Type);\n\n    /// <summary>\n    /// Sets a parameterized factory delegate for the registration.\n    /// </summary>\n    /// <param name=\"factory\">The parameterized factory delegate.</param>\n    /// <param name=\"isCompiledLambda\">Flag that indicates the passed factory delegate is a compiled lambda from <see cref=\"Expression\"/>.</param>\n    /// <returns>The fluent configurator.</returns>\n    public TConfigurator WithFactory<T1, T2, T3, T4>(Func<T1, T2, T3, T4, object> factory, bool isCompiledLambda = false) =>\n        this.SetFactory(factory, isCompiledLambda, TypeCache<T1>.Type, TypeCache<T2>.Type, TypeCache<T3>.Type, TypeCache<T4>.Type, TypeCache<object>.Type);\n\n    /// <summary>\n    /// Sets a parameterized factory delegate for the registration.\n    /// </summary>\n    /// <param name=\"factory\">The parameterized factory delegate.</param>\n    /// <param name=\"isCompiledLambda\">Flag that indicates the passed factory delegate is a compiled lambda from <see cref=\"Expression\"/>.</param>\n    /// <returns>The fluent configurator.</returns>\n    public TConfigurator WithFactory<T1, T2, T3, T4, T5>(Func<T1, T2, T3, T4, T5, object> factory, bool isCompiledLambda = false) =>\n        this.SetFactory(factory, isCompiledLambda, TypeCache<T1>.Type, TypeCache<T2>.Type, TypeCache<T3>.Type, TypeCache<T4>.Type, TypeCache<T5>.Type, TypeCache<object>.Type);\n}"
  },
  {
    "path": "src/Registration/Fluent/RegistrationConfigurator.cs",
    "content": "﻿using Stashbox.Lifetime;\nusing Stashbox.Utils;\nusing System;\nusing System.Collections.Generic;\n\nnamespace Stashbox.Registration.Fluent;\n\n/// <summary>\n/// Represents the generic fluent service registration api.\n/// </summary>\npublic class RegistrationConfigurator<TService, TImplementation> :\n    FluentServiceConfigurator<TService, TImplementation, RegistrationConfigurator<TService, TImplementation>>\n    where TService : class\n    where TImplementation : class, TService\n{\n    internal RegistrationConfigurator(Type serviceType, Type implementationType,\n        LifetimeDescriptor lifetimeDescriptor, object? name = null)\n        : base(serviceType, implementationType, name, lifetimeDescriptor, false)\n    { }\n\n    /// <summary>\n    /// Sets an instance as the resolution target of the registration.\n    /// </summary>\n    /// <param name=\"instance\">The instance.</param>\n    /// <param name=\"wireUp\">If true, the instance will be wired into the container, it will perform member and method injection on it.</param>\n    /// <returns>The fluent configurator.</returns>\n    public RegistrationConfigurator<TService, TImplementation> WithInstance(TService instance, bool wireUp = false)\n    {\n        Shield.EnsureNotNull(instance, nameof(instance));\n\n        this.Options ??= new Dictionary<RegistrationOption, object?>();\n        this.Options[RegistrationOption.RegistrationTypeOptions] = new InstanceOptions(instance, wireUp);\n        this.ImplementationType = instance.GetType();\n\n        return this;\n    }\n}\n\n/// <summary>\n/// Represents the fluent service registration api.\n/// </summary>\npublic class RegistrationConfigurator : FluentServiceConfigurator<RegistrationConfigurator>\n{\n    internal RegistrationConfigurator(Type serviceType, Type implementationType,\n        LifetimeDescriptor lifetimeDescriptor, object? name = null)\n        : base(serviceType, implementationType, name, lifetimeDescriptor, false)\n    { }\n\n    /// <summary>\n    /// Sets an instance as the resolution target of the registration.\n    /// </summary>\n    /// <param name=\"instance\">The instance.</param>\n    /// <param name=\"wireUp\">If true, the instance will be wired into the container, it will perform member and method injection on it.</param>\n    /// <returns>The fluent configurator.</returns>\n    public RegistrationConfigurator WithInstance(object instance, bool wireUp = false)\n    {\n        Shield.EnsureNotNull(instance, nameof(instance));\n\n        this.Options ??= new Dictionary<RegistrationOption, object?>();\n        this.Options[RegistrationOption.RegistrationTypeOptions] = new InstanceOptions(instance, wireUp);\n        this.ImplementationType = instance.GetType();\n\n        return this;\n    }\n}"
  },
  {
    "path": "src/Registration/Fluent/UnknownRegistrationConfigurator.cs",
    "content": "﻿using Stashbox.Lifetime;\nusing System;\n\nnamespace Stashbox.Registration.Fluent;\n\n/// <summary>\n/// Represents the fluent service registration api.\n/// </summary>\npublic class UnknownRegistrationConfigurator : RegistrationConfigurator\n{\n    internal bool RegistrationShouldBeSkipped { get; private set; }\n\n    internal UnknownRegistrationConfigurator(Type serviceType, Type implementationType, object? name,\n        LifetimeDescriptor lifetimeDescriptor)\n        : base(serviceType, implementationType, lifetimeDescriptor, name)\n    { }\n\n    /// <summary>\n    /// Sets the current registration's implementation type.\n    /// </summary>\n    /// <param name=\"implementationType\">The implementation type.</param>\n    /// <returns>The fluent configurator.</returns>\n    public UnknownRegistrationConfigurator SetImplementationType(Type implementationType)\n    {\n        if (!implementationType.Implements(this.ServiceType))\n            throw new ArgumentException($\"The type {implementationType} does not implement the actual service type {this.ServiceType}.\");\n\n        this.ImplementationType = implementationType;\n        return this;\n\n    }\n\n    /// <summary>\n    /// Marks the current unknown type registration as skipped.\n    /// </summary>\n    /// <returns>The fluent configurator.</returns>\n    public UnknownRegistrationConfigurator Skip()\n    {\n        this.RegistrationShouldBeSkipped = true;\n        return this;\n    }\n}"
  },
  {
    "path": "src/Registration/IDecoratorRepository.cs",
    "content": "﻿using Stashbox.Resolution;\nusing System;\nusing System.Collections.Generic;\n\nnamespace Stashbox.Registration;\n\n/// <summary>\n/// Represents a decorator registration repository.\n/// </summary>\npublic interface IDecoratorRepository\n{\n    /// <summary>\n    /// Adds a decorator to the repository.\n    /// </summary>\n    /// <param name=\"type\">The decorated type.</param>\n    /// <param name=\"serviceRegistration\">The decorator registration.</param>\n    /// <param name=\"remap\">If true, all the registrations mapped to a service type will be replaced.</param>\n    void AddDecorator(Type type, ServiceRegistration serviceRegistration, bool remap);\n\n    /// <summary>\n    /// Gets all decorator registration.\n    /// </summary>\n    /// <param name=\"implementationTypeToDecorate\">The implementation type to decorate.</param>\n    /// <param name=\"typeInformation\">The info about the decorated type.</param>\n    /// <param name=\"resolutionContext\">The resolution context.</param>\n    /// <returns>The decorator registrations if any exists, otherwise null.</returns>\n    IEnumerable<ServiceRegistration>? GetDecoratorsOrDefault(Type implementationTypeToDecorate, TypeInformation typeInformation, ResolutionContext resolutionContext);\n\n    /// <summary>\n    /// Returns all registration mappings.\n    /// </summary>\n    /// <returns>The registration mappings.</returns>\n    IEnumerable<KeyValuePair<Type, ServiceRegistration>> GetRegistrationMappings();\n}"
  },
  {
    "path": "src/Registration/IRegistrationRepository.cs",
    "content": "﻿using Stashbox.Resolution;\nusing System;\nusing System.Collections.Generic;\n\nnamespace Stashbox.Registration;\n\n/// <summary>\n/// Represents a registration repository.\n/// </summary>\npublic interface IRegistrationRepository\n{\n    /// <summary>\n    /// Adds or updates an element in the repository.\n    /// </summary>\n    /// <param name=\"registration\">The registration.</param>\n    /// <param name=\"serviceType\">The service type of the registration. Used as the key for the registration mapping.</param>\n    /// <returns>True when the repository changed, otherwise false.</returns>\n    bool AddOrUpdateRegistration(ServiceRegistration registration, Type serviceType);\n\n    /// <summary>\n    /// Remaps all the registrations mapped to a service type.\n    /// </summary>\n    /// <param name=\"registration\">The registration.</param>\n    /// <param name=\"serviceType\">The service type of the registration. Used as the key for the registration mapping.</param>\n    /// <returns>True when the repository changed, otherwise false.</returns>\n    bool AddOrReMapRegistration(ServiceRegistration registration, Type serviceType);\n\n    /// <summary>\n    /// Returns a registration.\n    /// </summary>\n    /// <param name=\"typeInfo\">The type info.</param>\n    /// <param name=\"resolutionContext\">The resolution context.</param>\n    /// <returns>The registration or null, if it doesn't exist.</returns>\n    ServiceRegistration? GetRegistrationOrDefault(TypeInformation typeInfo, ResolutionContext resolutionContext);\n\n    /// <summary>\n    /// Returns all registrations for a type.\n    /// </summary>\n    /// <param name=\"typeInfo\">The requested type.</param>\n    /// <param name=\"resolutionContext\">The resolution context.</param>\n    /// <returns>The registrations or null, if it doesn't exist.</returns>\n    IEnumerable<ServiceRegistration>? GetRegistrationsOrDefault(TypeInformation typeInfo, ResolutionContext resolutionContext);\n\n    /// <summary>\n    /// Returns all registration mappings.\n    /// </summary>\n    /// <returns>The registration mappings.</returns>\n    IEnumerable<KeyValuePair<Type, ServiceRegistration>> GetRegistrationMappings();\n\n    /// <summary>\n    /// Checks whether a type is registered in the repository.\n    /// </summary>\n    /// <param name=\"type\">The requested type.</param>\n    /// <param name=\"name\">The requested name.</param>\n    /// <param name=\"includeOpenGenerics\">Determines whether open generic registrations should be taken into account when the given type is closed generic.</param>\n    /// <returns>True if the registration found, otherwise false.</returns>\n    bool ContainsRegistration(Type type, object? name, bool includeOpenGenerics = true);\n}"
  },
  {
    "path": "src/Registration/OpenGenericRegistration.cs",
    "content": "﻿using Stashbox.Utils.Data.Immutable;\nusing Stashbox.Utils;\nusing System;\n\nnamespace Stashbox.Registration;\n\n/// <summary>\n/// Describes an open-generic service registration.\n/// </summary>\npublic class OpenGenericRegistration : ServiceRegistration\n{\n    private ImmutableTree<Type, ServiceRegistration> closedGenericRegistrations = ImmutableTree<Type, ServiceRegistration>.Empty;\n        \n    internal OpenGenericRegistration(ServiceRegistration serviceRegistration)\n        : base(serviceRegistration.ImplementationType, serviceRegistration.Name, serviceRegistration.Lifetime, serviceRegistration.IsDecorator,\n            serviceRegistration.Options, serviceRegistration.RegistrationId, serviceRegistration.RegistrationOrder)\n    { }\n\n    internal ServiceRegistration ProduceClosedRegistration(Type requestedType)\n    {\n        var found = closedGenericRegistrations.GetOrDefaultByRef(requestedType);\n        if (found != null) return found;\n        var genericType = ImplementationType.MakeGenericType(requestedType.GetGenericArguments());\n        var newRegistration = new ServiceRegistration(genericType, null, Lifetime, IsDecorator, Options);\n        return Swap.SwapValue(ref closedGenericRegistrations, (t1, t2, _, _, items) =>\n            items.AddOrUpdate(t1, t2, true), requestedType, newRegistration, Constants.DelegatePlaceholder, Constants.DelegatePlaceholder)\n            ? newRegistration\n            : closedGenericRegistrations.GetOrDefaultByRef(requestedType)!;\n    }\n}"
  },
  {
    "path": "src/Registration/RegistrationDiagnosticsInfo.cs",
    "content": "﻿using System;\n\nnamespace Stashbox.Registration;\n\n/// <summary>\n/// Details about a registration.\n/// </summary>\npublic readonly struct RegistrationDiagnosticsInfo\n{\n    /// <summary>\n    /// The service type.\n    /// </summary>\n    public readonly Type ServiceType;\n\n    /// <summary>\n    /// The implementation type.\n    /// </summary>\n    public readonly Type ImplementationType;\n\n    /// <summary>\n    /// The registration name.\n    /// </summary>\n    public readonly object? Name;\n\n    /// <summary>\n    /// Constructs a <see cref=\"RegistrationDiagnosticsInfo\"/>.\n    /// </summary>\n    /// <param name=\"serviceType\">The service type.</param>\n    /// <param name=\"implementationType\">The implementation type.</param>\n    /// <param name=\"name\">The registration name.</param>\n    public RegistrationDiagnosticsInfo(Type serviceType, Type implementationType, object? name) : this()\n    {\n        this.ServiceType = serviceType;\n        this.ImplementationType = implementationType;\n        this.Name = name;\n    }\n\n    /// <summary>\n    /// The string representation of the registration.\n    /// </summary>\n    /// <returns>The string representation of the registration.</returns>\n    public override string ToString() => $\"{this.ServiceType.GetDiagnosticsView()} => {this.ImplementationType.GetDiagnosticsView()}, name: {this.Name ?? \"null\"}\";\n}"
  },
  {
    "path": "src/Registration/RegistrationRepository.cs",
    "content": "﻿using Stashbox.Configuration;\nusing Stashbox.Exceptions;\nusing Stashbox.Registration.Extensions;\nusing Stashbox.Registration.SelectionRules;\nusing Stashbox.Resolution;\nusing Stashbox.Utils;\nusing Stashbox.Utils.Data.Immutable;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\n\nnamespace Stashbox.Registration;\n\ninternal class RegistrationRepository(ContainerConfiguration containerConfiguration) : IRegistrationRepository\n{\n    private ImmutableTree<Type, ImmutableBucket<ServiceRegistration>> serviceRepository = ImmutableTree<Type, ImmutableBucket<ServiceRegistration>>.Empty;\n\n    private readonly IRegistrationSelectionRule[] filters =\n    [\n        RegistrationSelectionRules.GenericFilter,\n        RegistrationSelectionRules.NameFilter,\n        RegistrationSelectionRules.MetadataFilter,\n        RegistrationSelectionRules.ScopeNameFilter,\n        RegistrationSelectionRules.ConditionFilter\n    ];\n\n    private readonly IRegistrationSelectionRule[] topLevelFilters =\n    [\n        RegistrationSelectionRules.GenericFilter,\n        RegistrationSelectionRules.NameFilter,\n        RegistrationSelectionRules.MetadataFilter,\n        RegistrationSelectionRules.ScopeNameFilter\n    ];\n\n    private readonly IRegistrationSelectionRule[] enumerableFilters =\n    [\n        RegistrationSelectionRules.GenericFilter,\n        RegistrationSelectionRules.EnumerableNameFilter,\n        RegistrationSelectionRules.ScopeNameFilter,\n        RegistrationSelectionRules.ConditionFilter,\n        RegistrationSelectionRules.MetadataFilter\n    ];\n\n    public bool AddOrUpdateRegistration(ServiceRegistration registration, Type serviceType)\n    {\n        if (registration.Options.IsOn(RegistrationOption.ReplaceExistingRegistrationOnlyIfExists))\n            return Swap.SwapValue(ref this.serviceRepository, (reg, type, _, _, repo) =>\n                    repo.UpdateIfExists(type, true, regs =>\n                    {\n                        var existingIndex = -1;\n                        for (var i = 0; i < regs.Length; i++)\n                        {\n                            var current = regs[i];\n                            var existingDiscriminator = current.Name ?? current.ImplementationType;\n                            var newDiscriminator = reg.Name ?? reg.ImplementationType;\n                            if (existingDiscriminator.Equals(newDiscriminator))\n                                existingIndex = i;\n                        }\n\n                        if (existingIndex == -1) return regs;\n                        var replaced = regs[existingIndex];\n                        reg.Replaces(replaced);\n                        return regs.ReplaceAt(existingIndex, reg);\n\n                    }),\n                registration,\n                serviceType,\n                Constants.DelegatePlaceholder,\n                Constants.DelegatePlaceholder);\n\n        return Swap.SwapValue(ref this.serviceRepository, (reg, type, newRepo, regBehavior, repo) =>\n                repo.AddOrUpdate(type, newRepo, true,\n                    (oldValue, _) =>\n                    {\n                        var replaceExisting = reg.Options.IsOn(RegistrationOption.ReplaceExistingRegistration);\n                        var allowUpdate = replaceExisting || regBehavior == Rules.RegistrationBehavior.ReplaceExisting;\n\n                        if (!allowUpdate && regBehavior == Rules.RegistrationBehavior.PreserveDuplications)\n                            return oldValue.Add(reg);\n\n                        var existingIndex = -1;\n                        for (var i = 0; i < oldValue.Length; i++)\n                        {\n                            var current = oldValue[i];\n                            if (!replaceExisting && current.ImplementationType != reg.ImplementationType) continue;\n                            var existingDiscriminator = current.Name ?? current.ImplementationType;\n                            var newDiscriminator = reg.Name ?? reg.ImplementationType;\n                            if (existingDiscriminator.Equals(newDiscriminator))\n                                existingIndex = i;\n                        }\n\n                        if (existingIndex == -1) return oldValue.Add(reg);\n                        switch (allowUpdate)\n                        {\n                            case false when regBehavior == Rules.RegistrationBehavior.ThrowException:\n                                throw new ServiceAlreadyRegisteredException(reg.ImplementationType);\n                            case false:\n                                return oldValue;\n                            default:\n                                var replaced = oldValue[existingIndex];\n                                reg.Replaces(replaced);\n                                return oldValue.ReplaceAt(existingIndex, reg);\n                        }\n                    }),\n            registration,\n            serviceType,\n            new ImmutableBucket<ServiceRegistration>(registration),\n            containerConfiguration.RegistrationBehavior);\n    }\n\n    public bool AddOrReMapRegistration(ServiceRegistration registration, Type serviceType) =>\n        registration.Options.IsOn(RegistrationOption.ReplaceExistingRegistrationOnlyIfExists)\n            ? Swap.SwapValue(ref this.serviceRepository, (type, newRepo, _, _, repo) =>\n                    repo.UpdateIfExists(type, newRepo, true), serviceType,\n                new ImmutableBucket<ServiceRegistration>(registration),\n                Constants.DelegatePlaceholder,\n                Constants.DelegatePlaceholder)\n            : Swap.SwapValue(ref this.serviceRepository, (type, newRepo, _, _, repo) =>\n                    repo.AddOrUpdate(type, newRepo, true, true), serviceType,\n                new ImmutableBucket<ServiceRegistration>(registration),\n                Constants.DelegatePlaceholder,\n                Constants.DelegatePlaceholder);\n\n    public bool ContainsRegistration(Type type, object? name, bool includeOpenGenerics = true) =>\n        serviceRepository.ContainsRegistration(type, name, includeOpenGenerics);\n\n    public IEnumerable<KeyValuePair<Type, ServiceRegistration>> GetRegistrationMappings() =>\n        serviceRepository.Walk().SelectMany(reg => reg.Value.Repository.Select(r => new KeyValuePair<Type, ServiceRegistration>(reg.Key, r)));\n\n    public ServiceRegistration? GetRegistrationOrDefault(TypeInformation typeInfo, ResolutionContext resolutionContext) =>\n        this.GetRegistrationsForType(typeInfo.Type)?.SelectOrDefault(typeInfo, resolutionContext,\n            !typeInfo.IsDependency ? this.topLevelFilters : this.filters);\n\n    public IEnumerable<ServiceRegistration>? GetRegistrationsOrDefault(TypeInformation typeInfo, ResolutionContext resolutionContext) =>\n        this.GetRegistrationsForType(typeInfo.Type)\n            ?.FilterExclusiveOrDefault(typeInfo, resolutionContext, this.enumerableFilters)\n            ?.OrderBy(reg => reg.RegistrationOrder);\n\n    private IEnumerable<ServiceRegistration>? GetRegistrationsForType(Type type)\n    {\n        IEnumerable<ServiceRegistration>? registrations = serviceRepository.GetOrDefaultByRef(type)?.Repository;\n        if (!type.IsClosedGenericType()) return registrations;\n\n        var openGenerics = serviceRepository.GetOrDefaultByRef(type.GetGenericTypeDefinition())?.Repository;\n\n        if (openGenerics != null)\n            registrations = registrations == null ? openGenerics : openGenerics.Concat(registrations);\n\n        if (!containerConfiguration.VariantGenericTypesEnabled)\n            return registrations;\n        \n        var variantGenerics = serviceRepository.Walk()\n            .Where(r => r.Key.IsGenericType &&\n                        r.Key.GetGenericTypeDefinition() == type.GetGenericTypeDefinition() &&\n                        r.Key != type &&\n                        r.Key.ImplementsWithoutGenericCheck(type))\n            .SelectMany(r => r.Value.Repository).ToArray();\n\n        if (variantGenerics.Length > 0)\n            registrations = registrations == null ? variantGenerics : variantGenerics.Concat(registrations);\n\n        return registrations;\n    }\n}"
  },
  {
    "path": "src/Registration/SelectionRules/ConditionRule.cs",
    "content": "﻿using Stashbox.Resolution;\nusing System.Collections.Generic;\n\nnamespace Stashbox.Registration.SelectionRules;\n\ninternal class ConditionRule : IRegistrationSelectionRule\n{\n    public bool IsValidForCurrentRequest(TypeInformation typeInformation,\n        ServiceRegistration registration, ResolutionContext resolutionContext, out bool shouldIncrementWeight)\n    {\n        var conditions = registration.Options.GetOrDefault<ConditionOptions>(RegistrationOption.ConditionOptions);\n        if (conditions != null)\n        {\n            shouldIncrementWeight = ServiceRegistration.IsUsableForCurrentContext(typeInformation, conditions);\n            return shouldIncrementWeight;\n        }\n\n        shouldIncrementWeight = false;\n        return conditions is null;\n    }\n}"
  },
  {
    "path": "src/Registration/SelectionRules/DecoratorRule.cs",
    "content": "﻿using Stashbox.Resolution;\n\nnamespace Stashbox.Registration.SelectionRules;\n\ninternal class DecoratorRule : IRegistrationSelectionRule\n{\n    public bool IsValidForCurrentRequest(TypeInformation typeInformation, ServiceRegistration registration,\n        ResolutionContext resolutionContext, out bool shouldIncrementWeight)\n    {\n        shouldIncrementWeight = false;\n        return !resolutionContext.CurrentDecorators.ContainsReference(registration);\n    }\n}"
  },
  {
    "path": "src/Registration/SelectionRules/EnumerableNameRule.cs",
    "content": "﻿using Stashbox.Resolution;\n\nnamespace Stashbox.Registration.SelectionRules;\n\ninternal class EnumerableNameRule : IRegistrationSelectionRule\n{\n    public bool IsValidForCurrentRequest(TypeInformation typeInformation,\n        ServiceRegistration registration, ResolutionContext resolutionContext, out bool shouldIncrementWeight)\n    {\n        if (typeInformation.DependencyName == null)\n        {\n            shouldIncrementWeight = false;\n            return resolutionContext.CurrentContainerContext.ContainerConfiguration.NamedDependencyResolutionForUnNamedCollectionRequestsEnabled || registration.Name == null;\n        }\n\n        if (resolutionContext.CurrentContainerContext.ContainerConfiguration.IgnoreServicesWithUniversalNameForUniversalNamedRequests &&\n            typeInformation.DependencyName != null && typeInformation.DependencyName.Equals(resolutionContext.CurrentContainerContext.ContainerConfiguration.UniversalName) &&\n            registration.Name != null && registration.Name.Equals(resolutionContext.CurrentContainerContext.ContainerConfiguration.UniversalName))\n        {\n            shouldIncrementWeight = false;\n            return false;\n        }\n        \n        if (typeInformation.DependencyName != null &&\n            registration.Name != null &&\n            registration.Name.Equals(typeInformation.DependencyName))\n        {\n            shouldIncrementWeight = true;\n            return true;\n        }\n        \n        if (typeInformation.DependencyName != null &&\n            typeInformation.DependencyName.Equals(resolutionContext.CurrentContainerContext.ContainerConfiguration.UniversalName) &&\n            registration.Name != null)\n        {\n            shouldIncrementWeight = true;\n            return true;\n        }\n\n        if (typeInformation.DependencyName != null &&\n            resolutionContext.CurrentContainerContext.ContainerConfiguration.TreatingParameterAndMemberNameAsDependencyNameEnabled &&\n            (registration.Name == null || (registration.Name != null && registration.Name.Equals(typeInformation.DependencyName))))\n        {\n            shouldIncrementWeight = false;\n            return true;\n        }\n\n        shouldIncrementWeight = false;\n        return false;\n    }\n}"
  },
  {
    "path": "src/Registration/SelectionRules/IRegistrationSelectionRule.cs",
    "content": "﻿using Stashbox.Resolution;\n\nnamespace Stashbox.Registration.SelectionRules;\n\ninternal interface IRegistrationSelectionRule\n{\n    bool IsValidForCurrentRequest(TypeInformation typeInformation,\n        ServiceRegistration registration, ResolutionContext resolutionContext, out bool shouldIncrementWeight);\n}"
  },
  {
    "path": "src/Registration/SelectionRules/MetadataRule.cs",
    "content": "﻿using Stashbox.Resolution;\nusing System.Collections.Generic;\n\nnamespace Stashbox.Registration.SelectionRules;\n\ninternal class MetadataRule : IRegistrationSelectionRule\n{\n    public bool IsValidForCurrentRequest(TypeInformation typeInformation,\n        ServiceRegistration registration, ResolutionContext resolutionContext, out bool shouldIncrementWeight)\n    {\n        shouldIncrementWeight = false;\n        if (typeInformation.MetadataType != null)\n        {\n            var metadata = registration.Options.GetOrDefault(RegistrationOption.Metadata);\n\n            shouldIncrementWeight = metadata != null && typeInformation.MetadataType.IsInstanceOfType(metadata);\n            return shouldIncrementWeight;\n        }\n\n        return true;\n    }\n}"
  },
  {
    "path": "src/Registration/SelectionRules/NameRule.cs",
    "content": "﻿using Stashbox.Resolution;\n\nnamespace Stashbox.Registration.SelectionRules;\n\ninternal class NameRule : IRegistrationSelectionRule\n{\n    public bool IsValidForCurrentRequest(TypeInformation typeInformation,\n        ServiceRegistration registration, ResolutionContext resolutionContext, out bool shouldIncrementWeight)\n    {\n        if (typeInformation.DependencyName == null &&\n            registration.Name == null)\n        {\n            shouldIncrementWeight = false;\n            return true;\n        }\n        \n        if (resolutionContext.CurrentContainerContext.ContainerConfiguration.IgnoreServicesWithUniversalNameForUniversalNamedRequests &&\n            typeInformation.DependencyName != null && typeInformation.DependencyName.Equals(resolutionContext.CurrentContainerContext.ContainerConfiguration.UniversalName))\n        {\n            shouldIncrementWeight = false;\n            return false;\n        }\n\n        if (typeInformation.DependencyName != null &&\n            registration.Name != null &&\n            registration.Name.Equals(typeInformation.DependencyName))\n        {\n            shouldIncrementWeight = true;\n            return true;\n        }\n        \n        if (typeInformation.DependencyName != null &&\n            registration.Name != null &&\n            registration.Name.Equals(resolutionContext.CurrentContainerContext.ContainerConfiguration.UniversalName))\n        {\n            shouldIncrementWeight = false;\n            return true;\n        }\n        \n        if (typeInformation.DependencyName != null &&\n            typeInformation.DependencyName.Equals(resolutionContext.CurrentContainerContext.ContainerConfiguration.UniversalName) &&\n            registration.Name != null)\n        {\n            shouldIncrementWeight = false;\n            return true;\n        }\n\n        if (typeInformation.DependencyName == null &&\n            registration.Name != null &&\n            resolutionContext.CurrentContainerContext.ContainerConfiguration.NamedDependencyResolutionForUnNamedRequestsEnabled)\n        {\n            shouldIncrementWeight = false;\n            return true;\n        }\n\n        if (typeInformation.DependencyName != null &&\n            resolutionContext.CurrentContainerContext.ContainerConfiguration.TreatingParameterAndMemberNameAsDependencyNameEnabled &&\n            (registration.Name == null || (registration.Name != null && registration.Name.Equals(typeInformation.DependencyName))))\n        {\n            shouldIncrementWeight = false;\n            return true;\n        }\n\n        shouldIncrementWeight = false;\n        return false;\n    }\n}"
  },
  {
    "path": "src/Registration/SelectionRules/OpenGenericRule.cs",
    "content": "﻿using Stashbox.Resolution;\nusing System;\n\nnamespace Stashbox.Registration.SelectionRules;\n\ninternal class OpenGenericRule : IRegistrationSelectionRule\n{\n    public bool IsValidForCurrentRequest(TypeInformation typeInformation,\n        ServiceRegistration registration, ResolutionContext resolutionContext, out bool shouldIncrementWeight)\n    {\n        shouldIncrementWeight = false;\n        return !typeInformation.Type.IsClosedGenericType() ||\n               registration.ImplementationType.SatisfiesGenericConstraintsOf(typeInformation.Type);\n    }\n}"
  },
  {
    "path": "src/Registration/SelectionRules/RegistrationSelectionRules.cs",
    "content": "﻿namespace Stashbox.Registration.SelectionRules;\n\ninternal static class RegistrationSelectionRules\n{\n    public static readonly IRegistrationSelectionRule ConditionFilter = new ConditionRule();\n    public static readonly IRegistrationSelectionRule GenericFilter = new OpenGenericRule();\n    public static readonly IRegistrationSelectionRule ScopeNameFilter = new ScopeNameRule();\n    public static readonly IRegistrationSelectionRule NameFilter = new NameRule();\n    public static readonly IRegistrationSelectionRule EnumerableNameFilter = new EnumerableNameRule();\n    public static readonly IRegistrationSelectionRule MetadataFilter = new MetadataRule();\n    public static readonly IRegistrationSelectionRule DecoratorFilter = new DecoratorRule();\n}"
  },
  {
    "path": "src/Registration/SelectionRules/ScopeNameRule.cs",
    "content": "﻿using Stashbox.Lifetime;\nusing Stashbox.Resolution;\n\nnamespace Stashbox.Registration.SelectionRules;\n\ninternal class ScopeNameRule : IRegistrationSelectionRule\n{\n    public bool IsValidForCurrentRequest(TypeInformation typeInformation,\n        ServiceRegistration registration, ResolutionContext resolutionContext, out bool shouldIncrementWeight)\n    {\n        if (registration.Lifetime is not NamedScopeLifetime namedScopeLifetime)\n        {\n            shouldIncrementWeight = false;\n            return true;\n        }\n\n        shouldIncrementWeight = false;\n        if (resolutionContext.ScopeNames.Length == 0)\n            return false;\n\n        shouldIncrementWeight = resolutionContext.ScopeNames.First().Equals(namedScopeLifetime.ScopeName);\n        return resolutionContext.ScopeNames.Contains(namedScopeLifetime.ScopeName);\n    }\n}"
  },
  {
    "path": "src/Registration/ServiceRegistration.cs",
    "content": "﻿using Stashbox.Configuration;\nusing Stashbox.Lifetime;\nusing Stashbox.Resolution;\nusing Stashbox.Utils.Data;\nusing System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Linq;\nusing System.Linq.Expressions;\nusing System.Reflection;\nusing System.Threading;\n\nnamespace Stashbox.Registration;\n\n/// <summary>\n/// Represents a service registration.\n/// </summary>\n[DebuggerDisplay(\"Name = {Name}, Lifetime = {Lifetime.Name}\", Name = \"{ImplementationType}\")]\npublic class ServiceRegistration\n{\n    private static int globalRegistrationId = int.MinValue;\n\n    private static int globalRegistrationOrder = int.MinValue;\n\n    /// <summary>\n    /// The registration id.\n    /// </summary>\n    public readonly int RegistrationId;\n\n    /// <summary>\n    /// True if the registration is a decorator.\n    /// </summary>\n    public readonly bool IsDecorator;\n\n    /// <summary>\n    /// Name of the registration.\n    /// </summary>\n    public object? Name { get; internal set; }\n\n    /// <summary>\n    /// Lifetime of the registration.\n    /// </summary>\n    public LifetimeDescriptor Lifetime { get; internal set; }\n\n    /// <summary>\n    /// The registration order indicator.\n    /// </summary>\n    public int RegistrationOrder { get; private set; }\n\n    /// <summary>\n    /// The implementation type.\n    /// </summary>\n    public Type ImplementationType { get; internal set; }\n\n    /// <summary>\n    /// Advanced registration options.\n    /// </summary>\n    public IReadOnlyDictionary<RegistrationOption, object?>? RegistrationOptions => this.Options;\n\n    [DebuggerBrowsable(DebuggerBrowsableState.Never)]\n    internal Dictionary<RegistrationOption, object?>? Options;\n\n    internal ServiceRegistration(Type implementationType, object? name,\n        LifetimeDescriptor lifetimeDescriptor, bool isDecorator, Dictionary<RegistrationOption, object?>? options = null,\n        int? registrationId = null, int? order = null)\n    {\n        this.ImplementationType = implementationType;\n        this.IsDecorator = isDecorator;\n        this.Name = name;\n        this.Lifetime = lifetimeDescriptor;\n        this.Options = options;\n        this.RegistrationId = registrationId ?? ReserveRegistrationId();\n        this.RegistrationOrder = order ?? ReserveRegistrationOrder();\n    }\n\n    /// <summary>\n    /// Returns the service discriminator used to distinguish service instances.\n    /// If <see cref=\"ContainerConfiguration.UniversalName\"/> used for service name it returns the requested dependency name's hash.\n    /// Otherwise, the service's registration identifier is used.\n    /// </summary>\n    /// <param name=\"typeInformation\">The type info of the requested type.</param>\n    /// <param name=\"containerConfiguration\">The container configuration.</param>\n    /// <returns>The registration's discriminator.</returns>\n    public int GetDiscriminator(TypeInformation typeInformation, ContainerConfiguration containerConfiguration)\n    {\n        if (containerConfiguration.UniversalName != null && \n            containerConfiguration.UniversalName.Equals(this.Name) && \n            typeInformation.DependencyName != null)\n            return typeInformation.DependencyName.GetHashCode() ^ this.RegistrationId;\n\n        return this.RegistrationId;\n    }\n\n    internal void Replaces(ServiceRegistration serviceRegistration) =>\n        this.RegistrationOrder = serviceRegistration.RegistrationOrder;\n\n    internal bool IsFactory() => Options.GetOrDefault(RegistrationOption.RegistrationTypeOptions) is FactoryOptions;\n\n    internal bool IsInstance() => Options.GetOrDefault(RegistrationOption.RegistrationTypeOptions) is InstanceOptions;\n\n    internal static bool IsUsableForCurrentContext(TypeInformation typeInfo, ConditionOptions conditionOptions) =>\n        HasParentTypeConditionAndMatch(typeInfo, conditionOptions) ||\n        HasAttributeConditionAndMatch(typeInfo, conditionOptions) ||\n        HasResolutionConditionAndMatch(typeInfo, conditionOptions);\n\n    private static bool HasParentTypeConditionAndMatch(TypeInformation typeInfo, ConditionOptions conditionOptions) =>\n        (conditionOptions.TargetTypeConditions != null && CheckTypeConditions(conditionOptions.TargetTypeConditions, typeInfo)) ||\n        (conditionOptions.TargetTypeInResolutionPathConditions != null && CheckInPathTypeConditions(conditionOptions.TargetTypeInResolutionPathConditions, typeInfo));\n\n    private static bool HasAttributeConditionAndMatch(TypeInformation typeInfo, ConditionOptions conditionOptions) =>\n        (conditionOptions.AttributeConditions != null &&\n         typeInfo.CustomAttributes != null &&\n         conditionOptions.AttributeConditions.Intersect(typeInfo.CustomAttributes.Select(attribute => attribute.GetType())).Any()) ||\n        (conditionOptions.AttributeInResolutionPathConditions != null && CheckInPathAttributeConditions(conditionOptions.AttributeInResolutionPathConditions, typeInfo));\n\n    private static bool HasResolutionConditionAndMatch(TypeInformation typeInfo, ConditionOptions conditionOptions)\n    {\n        if (conditionOptions.ResolutionConditions == null)\n            return false;\n        var length = conditionOptions.ResolutionConditions.Length;\n        for (var i = 0; i < length; i++)\n        {\n            if (conditionOptions.ResolutionConditions[i](typeInfo))\n                return true;\n        }\n        return false;\n    }\n\n    private static bool CheckInPathTypeConditions(ExpandableArray<object?, Type> conditions, TypeInformation typeInformation)\n    {\n        var current = typeInformation;\n        do\n        {\n            if (CheckTypeConditions(conditions, current))\n                return true;\n            current = current.Parent;\n        } while (current != null);\n        return false;\n    }\n\n    private static bool CheckTypeConditions(ExpandableArray<object?, Type> conditions, TypeInformation typeInformation)\n    {\n        if (typeInformation.ParentType == null) return false;\n\n        var length = conditions.Length;\n        for (var i = 0; i < length; i++)\n        {\n            var item = conditions[i];\n            if (CheckSingleCondition(item, typeInformation))\n                return true;\n        }\n\n        return false;\n\n        static bool CheckSingleCondition(ReadOnlyKeyValue<object?, Type> condition, TypeInformation typeInformation)\n        {\n            if (condition.Key != null)\n            {\n                if (typeInformation.Parent == null) return false;\n                return condition.Key.Equals(typeInformation.Parent.DependencyName) && condition.Value == typeInformation.ParentType;\n            }\n            return condition.Value == typeInformation.ParentType;\n        }\n    }\n\n    private static bool CheckInPathAttributeConditions(ExpandableArray<object?, Type> attributes, TypeInformation typeInformation)\n    {\n        var current = typeInformation;\n        do\n        {\n            if (CheckAttributeConditions(attributes, current))\n                return true;\n            current = current.Parent;\n        } while (current != null);\n        return false;\n    }\n\n    private static bool CheckAttributeConditions(ExpandableArray<object?, Type> attributes, TypeInformation typeInformation)\n    {\n        if (typeInformation.CustomAttributes == null) return false;\n        var customAttributes = typeInformation.CustomAttributes.Select(attribute => attribute.GetType()).ToList();\n        if (customAttributes.Count == 0) return false;\n        var length = attributes.Length;\n        for (var i = 0; i < length; i++)\n        {\n            var item = attributes[i];\n            if (item.Key != null)\n            {\n                if (typeInformation.Parent == null) continue;\n                if(item.Key.Equals(typeInformation.Parent.DependencyName) && customAttributes.Contains(item.Value))\n                    return true;\n            }\n            if (customAttributes.Contains(item.Value))\n                return true;\n        }\n\n        return false;\n    }\n\n    private static int ReserveRegistrationId() =>\n        Interlocked.Increment(ref globalRegistrationId);\n\n    private static int ReserveRegistrationOrder() =>\n        Interlocked.Increment(ref globalRegistrationOrder);\n\n}\n\n/// <summary>\n/// Represents the registration option types.\n/// </summary>\npublic enum RegistrationOption\n{\n    /// <summary>\n    /// Determines whether the service's resolution should be handled by a dynamic <see cref=\"IDependencyResolver.Resolve(Type)\"/> call on the current <see cref=\"IDependencyResolver\"/> instead of a pre-built instantiation expression.\n    /// </summary>\n    IsResolutionCallRequired,\n\n    /// <summary>\n    /// Constructor related registration options.\n    /// </summary>\n    ConstructorOptions,\n\n    /// <summary>\n    /// Auto member injection related registration options.\n    /// </summary>\n    AutoMemberOptions,\n\n    /// <summary>\n    /// Dependency names or types that are bound to named registrations.\n    /// </summary>\n    DependencyBindings,\n\n    /// <summary>\n    /// The cleanup delegate.\n    /// </summary>\n    Finalizer,\n\n    /// <summary>\n    /// The initializer delegate.\n    /// </summary>\n    Initializer,\n\n    /// <summary>\n    /// The async initializer delegate.\n    /// </summary>\n    AsyncInitializer,\n\n    /// <summary>\n    /// True if the lifetime of the service is owned externally.\n    /// </summary>\n    IsLifetimeExternallyOwned,\n\n    /// <summary>\n    /// The name of the scope this registration defines.\n    /// </summary>\n    DefinedScopeName,\n\n    /// <summary>\n    /// The constructor selection rule.\n    /// </summary>\n    ConstructorSelectionRule,\n\n    /// <summary>\n    /// The additional metadata.\n    /// </summary>\n    Metadata,\n\n    /// <summary>\n    /// Indicates whether this registration should replace an existing registration.\n    /// </summary>\n    ReplaceExistingRegistration,\n\n    /// <summary>\n    /// Indicates whether this registration should replace a registration only when it's exist.\n    /// </summary>\n    ReplaceExistingRegistrationOnlyIfExists,\n\n    /// <summary>\n    /// Additional service types to map.\n    /// </summary>\n    AdditionalServiceTypes,\n\n    /// <summary>\n    /// Injection parameters.\n    /// </summary>\n    InjectionParameters,\n\n    /// <summary>\n    /// Condition related registration options.\n    /// </summary>\n    ConditionOptions,\n\n    /// <summary>\n    /// Options related to instance or factory registrations.\n    /// </summary>\n    RegistrationTypeOptions,\n    \n    /// <summary>\n    /// Required member injection related registration options.\n    /// </summary>\n    RequiredMemberInjectionEnabled,\n}\n\n/// <summary>\n/// Represents the factory registration options.\n/// </summary>\npublic class FactoryOptions\n{\n    /// <summary>\n    /// Container factory of the registration.\n    /// </summary>\n    public readonly Delegate Factory;\n\n    /// <summary>\n    /// Parameters to inject for the factory registration.\n    /// </summary>\n    public readonly Type[] FactoryParameters;\n\n    /// <summary>\n    /// Flag that indicates the passed factory delegate is a compiled lambda from <see cref=\"Expression\"/>.\n    /// </summary>\n    public readonly bool IsFactoryDelegateACompiledLambda;\n\n    internal FactoryOptions(Delegate factory, Type[] factoryParameters, bool isCompiledLambda)\n    {\n        this.Factory = factory;\n        this.FactoryParameters = factoryParameters;\n        this.IsFactoryDelegateACompiledLambda = isCompiledLambda;\n    }\n}\n\n/// <summary>\n/// Represents the instance registration options.\n/// </summary>\npublic class InstanceOptions\n{\n    /// <summary>\n    /// If true, the existing instance will be wired into the container, it will perform member and method injection on it.\n    /// </summary>\n    public readonly bool IsWireUp;\n\n    /// <summary>\n    /// The already stored instance which was provided by instance or wired up registration.\n    /// </summary>\n    public readonly object ExistingInstance;\n\n    internal InstanceOptions(object existingInstance, bool isWireUp)\n    {\n        this.IsWireUp = isWireUp;\n        this.ExistingInstance = existingInstance;\n    }\n}\n\n/// <summary>\n/// Represents the auto member injection related registration options.\n/// </summary>\npublic class AutoMemberOptions\n{\n    /// <summary>\n    /// The auto member injection rule for the registration.\n    /// </summary>\n    public readonly Rules.AutoMemberInjectionRules AutoMemberInjectionRule;\n\n    /// <summary>\n    /// A filter delegate used to determine which members should be auto injected and which are not.\n    /// </summary>\n    public readonly Func<MemberInfo, bool>? AutoMemberInjectionFilter;\n\n    internal AutoMemberOptions(Rules.AutoMemberInjectionRules autoMemberInjectionRule, Func<MemberInfo, bool>? autoMemberInjectionFilter)\n    {\n        this.AutoMemberInjectionRule = autoMemberInjectionRule;\n        this.AutoMemberInjectionFilter = autoMemberInjectionFilter;\n    }\n}\n\n/// <summary>\n/// Represents the constructor related registration options.\n/// </summary>\npublic class ConstructorOptions\n{\n    /// <summary>\n    /// The selected constructor if any was set.\n    /// </summary>\n    public readonly ConstructorInfo SelectedConstructor;\n\n    /// <summary>\n    /// The arguments of the selected constructor if any was set.\n    /// </summary>\n    public readonly object[]? ConstructorArguments;\n\n    internal ConstructorOptions(ConstructorInfo selectedConstructor, object[]? constructorArguments)\n    {\n        this.SelectedConstructor = selectedConstructor;\n        this.ConstructorArguments = constructorArguments;\n    }\n}\n\ninternal class ConditionOptions\n{\n    internal ExpandableArray<object?, Type>? TargetTypeConditions { get; set; }\n    internal ExpandableArray<object?, Type>? TargetTypeInResolutionPathConditions { get; set; }\n    internal ExpandableArray<Func<TypeInformation, bool>>? ResolutionConditions { get; set; }\n    internal ExpandableArray<Type>? AttributeConditions { get; set; }\n    internal ExpandableArray<object?, Type>? AttributeInResolutionPathConditions { get; set; }\n}"
  },
  {
    "path": "src/Registration/ServiceRegistrator.cs",
    "content": "﻿using Stashbox.Lifetime;\nusing Stashbox.Utils.Data;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\n\nnamespace Stashbox.Registration;\n\ninternal static class ServiceRegistrator\n{\n    public static void Register(IContainerContext containerContext, ServiceRegistration serviceRegistration, Type serviceType)\n    {\n        if (serviceRegistration.ImplementationType.IsOpenGenericType())\n            serviceRegistration = new OpenGenericRegistration(serviceRegistration);\n\n        PreProcessRegistration(containerContext, serviceRegistration);\n\n        if (serviceRegistration.Options.TryGet(RegistrationOption.AdditionalServiceTypes, out var types) && types is ExpandableArray<Type> additionalTypes)\n            foreach (var additionalServiceType in additionalTypes.Distinct())\n            {\n                if (additionalServiceType.IsOpenGenericType())\n                {\n                    RegisterInternal(containerContext, serviceRegistration, additionalServiceType.GetGenericTypeDefinition());\n                    continue;\n                }\n\n                RegisterInternal(containerContext, serviceRegistration, additionalServiceType);\n            }\n\n        RegisterInternal(containerContext, serviceRegistration, serviceType);\n    }\n\n    public static void ReMap(IContainerContext containerContext, ServiceRegistration serviceRegistration, Type serviceType)\n    {\n        if (serviceRegistration.ImplementationType.IsOpenGenericType())\n            serviceRegistration = new OpenGenericRegistration(serviceRegistration);\n\n        PreProcessRegistration(containerContext, serviceRegistration);\n\n        if (serviceRegistration.Options.TryGet(RegistrationOption.AdditionalServiceTypes, out var types) && types is ExpandableArray<Type> additionalTypes)\n            foreach (var additionalServiceType in additionalTypes.Distinct())\n                ReMapInternal(containerContext, serviceRegistration, additionalServiceType);\n\n        ReMapInternal(containerContext, serviceRegistration, serviceType);\n    }\n\n    private static void RegisterInternal(IContainerContext containerContext, ServiceRegistration serviceRegistration, Type serviceType)\n    {\n        if (serviceRegistration.IsDecorator)\n        {\n            containerContext.DecoratorRepository.AddDecorator(serviceType, serviceRegistration, false);\n            containerContext.RootScope.InvalidateDelegateCache();\n        }\n        else if (containerContext.RegistrationRepository.AddOrUpdateRegistration(serviceRegistration, serviceType))\n            containerContext.RootScope.InvalidateDelegateCache();\n    }\n\n    private static void ReMapInternal(IContainerContext containerContext, ServiceRegistration serviceRegistration, Type serviceType)\n    {\n        if (serviceRegistration.IsDecorator)\n            containerContext.DecoratorRepository.AddDecorator(serviceType, serviceRegistration, true);\n        else\n            containerContext.RegistrationRepository.AddOrReMapRegistration(serviceRegistration, serviceType);\n\n        containerContext.RootScope.InvalidateDelegateCache();\n    }\n\n    private static void PreProcessRegistration(IContainerContext containerContext, ServiceRegistration serviceRegistration)\n    {\n        if (!serviceRegistration.Options.TryGet(RegistrationOption.RegistrationTypeOptions, out var opts) ||\n            opts is not InstanceOptions instanceOptions) return;\n        \n        PreProcessExistingInstanceIfNeeded(containerContext, instanceOptions.ExistingInstance, serviceRegistration.Options.IsOn(RegistrationOption.IsLifetimeExternallyOwned), \n            serviceRegistration.Options.GetOrDefault<Action<object>>(RegistrationOption.Finalizer), serviceRegistration.ImplementationType);\n\n        if (instanceOptions.IsWireUp)\n            serviceRegistration.Lifetime = Lifetimes.Singleton;\n    }\n\n    private static void PreProcessExistingInstanceIfNeeded(IContainerContext containerContext, object? instance,\n        bool isLifetimeExternallyOwned, Action<object>? finalizer, Type implementationType)\n    {\n        if (instance == null) return;\n\n        if (!isLifetimeExternallyOwned && implementationType.IsDisposable())\n            containerContext.RootScope.AddDisposableTracking(instance);\n\n        if (finalizer == null) return;\n        containerContext.RootScope.AddWithFinalizer(instance, finalizer);\n    }\n}"
  },
  {
    "path": "src/Resolution/DelegateCache.cs",
    "content": "﻿using Stashbox.Utils;\nusing Stashbox.Utils.Data.Immutable;\nusing System;\n\nnamespace Stashbox.Resolution;\n\ninternal class DelegateCache\n{\n    public ImmutableTree<Type, ImmutableTree<CacheEntry>> ServiceDelegates = ImmutableTree<Type, ImmutableTree<CacheEntry>>.Empty;\n    public ImmutableTree<Type, ImmutableTree<CacheEntry>> RequestContextAwareDelegates = ImmutableTree<Type, ImmutableTree<CacheEntry>>.Empty;\n}\n\ninternal class CacheEntry\n{\n    public readonly Func<IResolutionScope, IRequestContext, object>? ServiceFactory;\n\n    public readonly ImmutableTree<object, Func<IResolutionScope, IRequestContext, object>>? NamedFactories;\n\n    public CacheEntry(Func<IResolutionScope, IRequestContext, object>? serviceFactory, ImmutableTree<object, Func<IResolutionScope, IRequestContext, object>>? namedFactories)\n    {\n        this.ServiceFactory = serviceFactory;\n        this.NamedFactories = namedFactories;\n    }\n}\n\ninternal class DelegateCacheProvider\n{\n    public readonly DelegateCache DefaultCache = new();\n    public ImmutableTree<object, DelegateCache> NamedCache = ImmutableTree<object, DelegateCache>.Empty;\n\n    public DelegateCache GetNamedCache(object name)\n    {\n        var cache = this.NamedCache.GetOrDefaultByValue(name);\n        if (cache != null) return cache;\n\n        var newCache = new DelegateCache();\n        return Swap.SwapValue(ref this.NamedCache, (t1, t2, _, _, items) =>\n            items.AddOrUpdate(t1, t2, false), name, newCache, Constants.DelegatePlaceholder, Constants.DelegatePlaceholder)\n            ? newCache\n            : this.NamedCache.GetOrDefaultByValue(name) ?? newCache;\n    }\n}"
  },
  {
    "path": "src/Resolution/DelegateCacheEntry.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\n\nnamespace Stashbox.Resolution;\n\n/// <summary>\n/// Details about Stashbox's internal delegate cache state.\n/// </summary>\npublic readonly struct DelegateCacheEntry\n{\n    /// <summary>\n    /// The service type.\n    /// </summary>\n    public readonly Type ServiceType;\n\n    /// <summary>\n    /// The resolution behavior that was used to construct this cache entry.\n    /// </summary>\n    public readonly ResolutionBehavior ResolutionBehavior;\n    \n    /// <summary>\n    /// The cached resolution delegate.\n    /// </summary>\n    public readonly Func<IResolutionScope, IRequestContext, object>? CachedDelegate;\n\n    /// <summary>\n    /// Named resolution delegates cached for this service.\n    /// </summary>\n    public readonly IEnumerable<NamedCacheEntry>? NamedCacheEntries;\n\n    /// <summary>\n    /// Constructs a <see cref=\"DelegateCacheEntry\"/>.\n    /// </summary>\n    /// <param name=\"serviceType\">The service type.</param>\n    /// <param name=\"cachedDelegate\">The cached resolution delegate.</param>\n    /// <param name=\"namedCacheEntries\">Named resolution delegates cached for this service.</param>\n    /// <param name=\"resolutionBehavior\">The resolution behavior.</param>\n    public DelegateCacheEntry(Type serviceType, Func<IResolutionScope, IRequestContext, object>? cachedDelegate, IEnumerable<NamedCacheEntry>? namedCacheEntries, ResolutionBehavior resolutionBehavior) : this()\n    {\n        this.ServiceType = serviceType;\n        this.CachedDelegate = cachedDelegate;\n        this.NamedCacheEntries = namedCacheEntries;\n        this.ResolutionBehavior = resolutionBehavior;\n    }\n}\n\n/// <summary>\n/// Details about a named delegate cache entry.\n/// </summary>\npublic readonly struct NamedCacheEntry\n{\n    /// <summary>\n    /// The service name.\n    /// </summary>\n    public readonly object Name;\n\n    /// <summary>\n    /// The cached resolution delegate.\n    /// </summary>\n    public readonly Func<IResolutionScope, IRequestContext, object> CachedDelegate;\n\n    /// <summary>\n    /// Constructs a <see cref=\"NamedCacheEntry\"/>.\n    /// </summary>\n    /// <param name=\"name\">The service name.</param>\n    /// <param name=\"cachedDelegate\">The cached resolution delegate.</param>\n    public NamedCacheEntry(object name, Func<IResolutionScope, IRequestContext, object> cachedDelegate) : this()\n    {\n        this.Name = name;\n        this.CachedDelegate = cachedDelegate;\n    }\n}"
  },
  {
    "path": "src/Resolution/Extensions/DependencyResolverExtensions.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Runtime.CompilerServices;\nusing Stashbox.Resolution;\nusing Stashbox.Utils;\n\nnamespace Stashbox;\n\n/// <summary>\n/// Represents the extensions of the <see cref=\"IDependencyResolver\"/>.\n/// </summary>\npublic static class DependencyResolverExtensions\n{\n    /// <summary>\n    /// Resolves an instance from the container.\n    /// </summary>\n    /// <typeparam name=\"TKey\">The type of the requested instance.</typeparam>\n    /// <param name=\"resolver\">The dependency resolver.</param>\n    /// <returns>The resolved object.</returns>\n    public static TKey Resolve<TKey>(this IDependencyResolver resolver) =>\n        (TKey)resolver.Resolve(TypeCache<TKey>.Type);\n\n    /// <summary>\n    /// Resolves an instance from the container.\n    /// </summary>\n    /// <typeparam name=\"TKey\">The type of the requested instance.</typeparam>\n    /// <param name=\"resolver\">The dependency resolver.</param>\n    /// <param name=\"resolutionBehavior\">The resolution behavior.</param>\n    /// <returns>The resolved object.</returns>\n    public static TKey Resolve<TKey>(this IDependencyResolver resolver, ResolutionBehavior resolutionBehavior) =>\n        (TKey)resolver.Resolve(TypeCache<TKey>.Type, null, null, resolutionBehavior);\n\n    /// <summary>\n    /// Resolves an instance from the container with dependency overrides.\n    /// </summary>\n    /// <typeparam name=\"TKey\">The type of the requested instance.</typeparam>\n    /// <param name=\"resolver\">The dependency resolver.</param>\n    /// <param name=\"dependencyOverrides\">A collection of objects which are used to override certain dependencies of the requested service.</param>\n    /// <param name=\"resolutionBehavior\">The resolution behavior.</param>\n    /// <returns>The resolved object.</returns>\n    public static TKey Resolve<TKey>(this IDependencyResolver resolver, object[] dependencyOverrides, ResolutionBehavior resolutionBehavior = ResolutionBehavior.Default) =>\n        (TKey)resolver.Resolve(TypeCache<TKey>.Type, null, dependencyOverrides, resolutionBehavior);\n\n    /// <summary>\n    /// Resolves a named instance from the container.\n    /// </summary>\n    /// <typeparam name=\"TKey\">The type of the requested instance.</typeparam>\n    /// <param name=\"resolver\">The dependency resolver.</param>\n    /// <param name=\"name\">The name of the requested registration.</param>\n    /// <param name=\"resolutionBehavior\">The resolution behavior.</param>\n    /// <returns>The resolved object.</returns>\n    public static TKey Resolve<TKey>(this IDependencyResolver resolver, object? name, ResolutionBehavior resolutionBehavior = ResolutionBehavior.Default) =>\n        (TKey)resolver.Resolve(TypeCache<TKey>.Type, name, null, resolutionBehavior);\n\n    /// <summary>\n    /// Resolves a named instance from the container with dependency overrides.\n    /// </summary>\n    /// <typeparam name=\"TKey\">The type of the requested instance.</typeparam>\n    /// <param name=\"resolver\">The dependency resolver.</param>\n    /// <param name=\"name\">The name of the requested registration.</param>\n    /// <param name=\"dependencyOverrides\">A collection of objects which are used to override certain dependencies of the requested service.</param>\n    /// <param name=\"resolutionBehavior\">The resolution behavior.</param>\n    /// <returns>The resolved object.</returns>\n    public static TKey Resolve<TKey>(this IDependencyResolver resolver, object? name, object[] dependencyOverrides, ResolutionBehavior resolutionBehavior = ResolutionBehavior.Default) =>\n        (TKey)resolver.Resolve(TypeCache<TKey>.Type, name, dependencyOverrides, resolutionBehavior);\n\n    /// <summary>\n    /// Resolves an instance from the container.\n    /// </summary>\n    /// <param name=\"resolver\">The dependency resolver.</param>\n    /// <param name=\"typeFrom\">The type of the requested service.</param>\n    /// <param name=\"resolutionBehavior\">The resolution behavior.</param>\n    /// <returns>The resolved object.</returns>\n    public static object Resolve(this IDependencyResolver resolver, Type typeFrom, ResolutionBehavior resolutionBehavior) =>\n        resolver.Resolve(typeFrom, null, null, resolutionBehavior);\n    \n    /// <summary>\n    /// Resolves an instance from the container with dependency overrides.\n    /// </summary>\n    /// <param name=\"resolver\">The dependency resolver.</param>\n    /// <param name=\"typeFrom\">The type of the requested service.</param>\n    /// <param name=\"dependencyOverrides\">A collection of objects which are used to override certain dependencies of the requested service.</param>\n    /// <param name=\"resolutionBehavior\">The resolution behavior.</param>\n    /// <returns>The resolved object.</returns>\n    public static object Resolve(this IDependencyResolver resolver, Type typeFrom, object[] dependencyOverrides, ResolutionBehavior resolutionBehavior = ResolutionBehavior.Default) =>\n        resolver.Resolve(typeFrom, null, dependencyOverrides, resolutionBehavior);\n\n    /// <summary>\n    /// Resolves a named instance from the container.\n    /// </summary>\n    /// <param name=\"resolver\">The dependency resolver.</param>\n    /// <param name=\"typeFrom\">The type of the requested service.</param>\n    /// <param name=\"name\">The name of the requested service.</param>\n    /// <param name=\"resolutionBehavior\">The resolution behavior.</param>\n    /// <returns>The resolved object.</returns>\n    public static object Resolve(this IDependencyResolver resolver, Type typeFrom, object? name, ResolutionBehavior resolutionBehavior = ResolutionBehavior.Default) =>\n        resolver.Resolve(typeFrom, name, null, resolutionBehavior);\n    \n    /// <summary>\n    /// Resolves a named instance from the container or returns default if the type is not resolvable.\n    /// </summary>\n    /// <typeparam name=\"TKey\">The type of the requested instance.</typeparam>\n    /// <param name=\"resolver\">The dependency resolver.</param>\n    /// <param name=\"name\">The name of the requested registration.</param>\n    /// <param name=\"resolutionBehavior\">The resolution behavior.</param>\n    /// <returns>The resolved object.</returns>\n    public static TKey? ResolveOrDefault<TKey>(this IDependencyResolver resolver, object? name, ResolutionBehavior resolutionBehavior = ResolutionBehavior.Default) =>\n        (TKey?)(resolver.ResolveOrDefault(TypeCache<TKey>.Type, name, null, resolutionBehavior) ?? default(TKey));\n\n    /// <summary>\n    /// Resolves a named instance from the container with dependency overrides or returns default if the type is not resolvable.\n    /// </summary>\n    /// <typeparam name=\"TKey\">The type of the requested instance.</typeparam>\n    /// <param name=\"resolver\">The dependency resolver.</param>\n    /// <param name=\"name\">The name of the requested registration.</param>\n    /// <param name=\"dependencyOverrides\">A collection of objects which are used to override certain dependencies of the requested service.</param>\n    /// <param name=\"resolutionBehavior\">The resolution behavior.</param>\n    /// <returns>The resolved object.</returns>\n    public static TKey? ResolveOrDefault<TKey>(this IDependencyResolver resolver, object? name, object[] dependencyOverrides, ResolutionBehavior resolutionBehavior = ResolutionBehavior.Default) =>\n        (TKey?)(resolver.ResolveOrDefault(TypeCache<TKey>.Type, name, dependencyOverrides, resolutionBehavior) ?? default(TKey));\n\n    /// <summary>\n    /// Resolves an instance from the container or returns default if the type is not resolvable.\n    /// </summary>\n    /// <typeparam name=\"TKey\">The type of the requested instance.</typeparam>\n    /// <param name=\"resolver\">The dependency resolver.</param>\n    /// <returns>The resolved object.</returns>\n    public static TKey? ResolveOrDefault<TKey>(this IDependencyResolver resolver) =>\n        (TKey?)(resolver.ResolveOrDefault(TypeCache<TKey>.Type) ?? default(TKey));\n    \n    /// <summary>\n    /// Resolves an instance from the container or returns default if the type is not resolvable.\n    /// </summary>\n    /// <typeparam name=\"TKey\">The type of the requested instance.</typeparam>\n    /// <param name=\"resolver\">The dependency resolver.</param>\n    /// <param name=\"resolutionBehavior\">The resolution behavior.</param>\n    /// <returns>The resolved object.</returns>\n    public static TKey? ResolveOrDefault<TKey>(this IDependencyResolver resolver, ResolutionBehavior resolutionBehavior) =>\n        (TKey?)(resolver.ResolveOrDefault(TypeCache<TKey>.Type, null, null, resolutionBehavior) ?? default(TKey));\n\n    /// <summary>\n    /// Resolves an instance from the container with dependency overrides or returns default if the type is not resolvable.\n    /// </summary>\n    /// <typeparam name=\"TKey\">The type of the requested instance.</typeparam>\n    /// <param name=\"resolver\">The dependency resolver.</param>\n    /// <param name=\"dependencyOverrides\">A collection of objects which are used to override certain dependencies of the requested service.</param>\n    /// <param name=\"resolutionBehavior\">The resolution behavior.</param>\n    /// <returns>The resolved object.</returns>\n    public static TKey? ResolveOrDefault<TKey>(this IDependencyResolver resolver, object[] dependencyOverrides, ResolutionBehavior resolutionBehavior = ResolutionBehavior.Default) =>\n        (TKey?)(resolver.ResolveOrDefault(TypeCache<TKey>.Type, null, dependencyOverrides, resolutionBehavior) ?? default(TKey));\n\n    /// <summary>\n    /// Resolves an instance from the container or returns default if the type is not resolvable.\n    /// </summary>\n    /// <param name=\"resolver\">The dependency resolver.</param>\n    /// <param name=\"typeFrom\">The type of the requested service.</param>\n    /// <param name=\"resolutionBehavior\">The resolution behavior.</param>\n    /// <returns>The resolved object.</returns>\n    public static object? ResolveOrDefault(this IDependencyResolver resolver, Type typeFrom, ResolutionBehavior resolutionBehavior) =>\n        resolver.ResolveOrDefault(typeFrom, null, null, resolutionBehavior);\n\n    /// <summary>\n    /// Resolves an instance from the container with dependency overrides or returns default if the type is not resolvable.\n    /// </summary>\n    /// <param name=\"resolver\">The dependency resolver.</param>\n    /// <param name=\"typeFrom\">The type of the requested service.</param>\n    /// <param name=\"dependencyOverrides\">A collection of objects which are used to override certain dependencies of the requested service.</param>\n    /// <param name=\"resolutionBehavior\">The resolution behavior.</param>\n    /// <returns>The resolved object.</returns>\n    public static object? ResolveOrDefault(this IDependencyResolver resolver, Type typeFrom, object[] dependencyOverrides, ResolutionBehavior resolutionBehavior = ResolutionBehavior.Default) =>\n        resolver.ResolveOrDefault(typeFrom, null, dependencyOverrides, resolutionBehavior);\n\n    /// <summary>\n    /// Resolves a named instance from the container or returns default if the type is not resolvable.\n    /// </summary>\n    /// <param name=\"resolver\">The dependency resolver.</param>\n    /// <param name=\"typeFrom\">The type of the requested service.</param>\n    /// <param name=\"name\">The name of the requested service.</param>\n    /// <param name=\"resolutionBehavior\">The resolution behavior.</param>\n    /// <returns>The resolved object.</returns>\n    public static object? ResolveOrDefault(this IDependencyResolver resolver, Type typeFrom, object? name, ResolutionBehavior resolutionBehavior = ResolutionBehavior.Default) =>\n        resolver.ResolveOrDefault(typeFrom, name, null, resolutionBehavior);\n\n    /// <summary>\n    /// Resolves all registered implementations of a service.\n    /// </summary>\n    /// <typeparam name=\"TKey\">The type of the requested service.</typeparam>\n    /// <param name=\"resolver\">The dependency resolver.</param>\n    /// <returns>The resolved object.</returns>\n    public static IEnumerable<TKey> ResolveAll<TKey>(this IDependencyResolver resolver) =>\n        (IEnumerable<TKey>)resolver.Resolve(TypeCache<IEnumerable<TKey>>.Type);\n    \n    /// <summary>\n    /// Resolves all registered implementations of a service.\n    /// </summary>\n    /// <typeparam name=\"TKey\">The type of the requested service.</typeparam>\n    /// <param name=\"resolver\">The dependency resolver.</param>\n    /// <param name=\"resolutionBehavior\">The resolution behavior.</param>\n    /// <returns>The resolved object.</returns>\n    public static IEnumerable<TKey> ResolveAll<TKey>(this IDependencyResolver resolver, ResolutionBehavior resolutionBehavior) =>\n        (IEnumerable<TKey>)resolver.Resolve(TypeCache<IEnumerable<TKey>>.Type, null, null, resolutionBehavior);\n\n    /// <summary>\n    /// Resolves all registered implementations of a service identified by a name.\n    /// </summary>\n    /// <typeparam name=\"TKey\">The type of the requested service.</typeparam>\n    /// <param name=\"resolver\">The dependency resolver.</param>\n    /// <param name=\"name\">The name of the requested service.</param>\n    /// <param name=\"resolutionBehavior\">The resolution behavior.</param>\n    /// <returns>The resolved object.</returns>\n    public static IEnumerable<TKey> ResolveAll<TKey>(this IDependencyResolver resolver, object? name, ResolutionBehavior resolutionBehavior = ResolutionBehavior.Default) =>\n        (IEnumerable<TKey>)resolver.Resolve(TypeCache<IEnumerable<TKey>>.Type, name, null, resolutionBehavior);\n\n    /// <summary>\n    /// Resolves all registered implementations of a service with dependency overrides.\n    /// </summary>\n    /// <typeparam name=\"TKey\">The type of the requested service.</typeparam>\n    /// <param name=\"resolver\">The dependency resolver.</param>\n    /// <param name=\"dependencyOverrides\">A collection of objects which are used to override certain dependencies of the requested services.</param>\n    /// <param name=\"resolutionBehavior\">The resolution behavior.</param>\n    /// <returns>The resolved object.</returns>\n    public static IEnumerable<TKey> ResolveAll<TKey>(this IDependencyResolver resolver, object[] dependencyOverrides, ResolutionBehavior resolutionBehavior = ResolutionBehavior.Default) =>\n        (IEnumerable<TKey>)resolver.Resolve(TypeCache<IEnumerable<TKey>>.Type, null, dependencyOverrides, resolutionBehavior);\n\n    /// <summary>\n    /// Resolves all registered implementations of a service identified by a name and with dependency overrides.\n    /// </summary>\n    /// <typeparam name=\"TKey\">The type of the requested services.</typeparam>\n    /// <param name=\"resolver\">The dependency resolver.</param>\n    /// <param name=\"name\">The name of the requested services.</param>\n    /// <param name=\"dependencyOverrides\">A collection of objects which are used to override certain dependencies of the requested services.</param>\n    /// <param name=\"resolutionBehavior\">The resolution behavior.</param>\n    /// <returns>The resolved object.</returns>\n    public static IEnumerable<TKey> ResolveAll<TKey>(this IDependencyResolver resolver, object? name, object[] dependencyOverrides, ResolutionBehavior resolutionBehavior = ResolutionBehavior.Default) =>\n        (IEnumerable<TKey>)resolver.Resolve(TypeCache<IEnumerable<TKey>>.Type, name, dependencyOverrides, resolutionBehavior);\n\n    /// <summary>\n    /// Resolves all registered implementations of a service.\n    /// </summary>\n    /// <param name=\"resolver\">The dependency resolver.</param>\n    /// <param name=\"typeFrom\">The type of the requested services.</param>\n    /// <returns>The resolved object.</returns>\n    public static IEnumerable<object> ResolveAll(this IDependencyResolver resolver, Type typeFrom)\n    {\n        var type = TypeCache.EnumerableType.MakeGenericType(typeFrom);\n        return (IEnumerable<object>)resolver.Resolve(type);\n    }\n    \n    /// <summary>\n    /// Resolves all registered implementations of a service.\n    /// </summary>\n    /// <param name=\"resolver\">The dependency resolver.</param>\n    /// <param name=\"typeFrom\">The type of the requested services.</param>\n    /// <param name=\"resolutionBehavior\">The resolution behavior.</param>\n    /// <returns>The resolved object.</returns>\n    public static IEnumerable<object> ResolveAll(this IDependencyResolver resolver, Type typeFrom,\n        ResolutionBehavior resolutionBehavior)\n    {\n        var type = TypeCache.EnumerableType.MakeGenericType(typeFrom);\n        return (IEnumerable<object>)resolver.Resolve(type, null, null, resolutionBehavior);\n    }\n\n    /// <summary>\n    /// Resolves all registered implementations of a service.\n    /// </summary>\n    /// <param name=\"resolver\">The dependency resolver.</param>\n    /// <param name=\"typeFrom\">The type of the requested services.</param>\n    /// <param name=\"name\">The name of the requested services.</param>\n    /// <param name=\"resolutionBehavior\">The resolution behavior.</param>\n    /// <returns>The resolved object.</returns>\n    public static IEnumerable<object> ResolveAll(this IDependencyResolver resolver, Type typeFrom, object? name, ResolutionBehavior resolutionBehavior = ResolutionBehavior.Default)\n    {\n        var type = TypeCache.EnumerableType.MakeGenericType(typeFrom);\n        return (IEnumerable<object>)resolver.Resolve(type, name, null, resolutionBehavior);\n    }\n\n    /// <summary>\n    /// Resolves all registered implementations of a service with dependency overrides.\n    /// </summary>\n    /// <param name=\"resolver\">The dependency resolver.</param>\n    /// <param name=\"typeFrom\">The type of the requested services.</param>\n    /// <param name=\"dependencyOverrides\">A collection of objects which are used to override certain dependencies of the requested services.</param>\n    /// <param name=\"resolutionBehavior\">The resolution behavior.</param>\n    /// <returns>The resolved object.</returns>\n    public static IEnumerable<object> ResolveAll(this IDependencyResolver resolver, Type typeFrom, object[] dependencyOverrides, ResolutionBehavior resolutionBehavior = ResolutionBehavior.Default)\n    {\n        var type = TypeCache.EnumerableType.MakeGenericType(typeFrom);\n        return (IEnumerable<object>)resolver.Resolve(type, null, dependencyOverrides, resolutionBehavior);\n    }\n\n    /// <summary>\n    /// Resolves all registered implementations of a service with dependency overrides.\n    /// </summary>\n    /// <param name=\"resolver\">The dependency resolver.</param>\n    /// <param name=\"typeFrom\">The type of the requested services.</param>\n    /// <param name=\"name\">The name of the requested services.</param>\n    /// <param name=\"dependencyOverrides\">A collection of objects which are used to override certain dependencies of the requested services.</param>\n    /// <param name=\"resolutionBehavior\">The resolution behavior.</param>\n    /// <returns>The resolved object.</returns>\n    public static IEnumerable<object> ResolveAll(this IDependencyResolver resolver, Type typeFrom, object? name, object[] dependencyOverrides, ResolutionBehavior resolutionBehavior = ResolutionBehavior.Default)\n    {\n        var type = TypeCache.EnumerableType.MakeGenericType(typeFrom);\n        return (IEnumerable<object>)resolver.Resolve(type, name, dependencyOverrides, resolutionBehavior);\n    }\n    \n    /// <summary>\n    /// On the fly activates an object without registering it into the container. If you want to resolve a\n    /// registered service use the <see cref=\"IDependencyResolver.Resolve(Type)\" /> instead.\n    /// </summary>\n    /// <typeparam name=\"TTo\">The service type.</typeparam>\n    /// <param name=\"resolver\">The dependency resolver.</param>\n    /// <param name=\"arguments\">Optional dependency overrides.</param>\n    /// <returns>The built object.</returns>\n    public static TTo Activate<TTo>(this IDependencyResolver resolver, params object[] arguments) =>\n        (TTo)resolver.Activate(TypeCache<TTo>.Type, arguments);\n\n    /// <summary>\n    /// Activates an object without registering it into the container. If you want to resolve a\n    /// registered service use the <see cref=\"IDependencyResolver.Resolve(Type)\" /> method instead.\n    /// </summary>\n    /// <param name=\"resolver\">The dependency resolver.</param>\n    /// <param name=\"type\">The type to activate.</param>\n    /// <param name=\"arguments\">Optional dependency overrides.</param>\n    /// <returns>The built object.</returns>\n    public static object Activate(this IDependencyResolver resolver, Type type, params object[] arguments) =>\n        resolver.Activate(type, Constants.DefaultResolutionBehavior, arguments);\n    \n    /// <summary>\n    /// On the fly activates an object without registering it into the container. If you want to resolve a\n    /// registered service use the <see cref=\"IDependencyResolver.Resolve(Type)\" /> instead.\n    /// </summary>\n    /// <typeparam name=\"TTo\">The service type.</typeparam>\n    /// <param name=\"resolver\">The dependency resolver.</param>\n    /// <param name=\"arguments\">Optional dependency overrides.</param>\n    /// <param name=\"resolutionBehavior\">The resolution behavior.</param>\n    /// <returns>The built object.</returns>\n    public static TTo Activate<TTo>(this IDependencyResolver resolver, ResolutionBehavior resolutionBehavior, params object[] arguments) =>\n        (TTo)resolver.Activate(TypeCache<TTo>.Type, resolutionBehavior, arguments);\n\n    /// <summary>\n    /// Puts an instance into the scope which will be dropped when the scope is being disposed.\n    /// </summary>\n    /// <typeparam name=\"TFrom\">The service type.</typeparam>\n    /// <param name=\"resolver\">The resolver.</param>\n    /// <param name=\"instance\">The instance.</param>\n    /// <param name=\"withoutDisposalTracking\">If it's set to true the container will exclude the instance from the disposal tracking.</param>\n    /// <param name=\"name\">The identifier.</param>\n    /// <returns>The scope.</returns>\n    public static void PutInstanceInScope<TFrom>(this IDependencyResolver resolver, TFrom instance, bool withoutDisposalTracking = false, object? name = null)\n        where TFrom : class =>\n        resolver.PutInstanceInScope(TypeCache<TFrom>.Type, instance, withoutDisposalTracking, name);\n    \n    /// <summary>\n    /// Checks whether a type can be resolved by the container, or not.\n    /// </summary>\n    /// <typeparam name=\"TFrom\">The service type.</typeparam>\n    /// <param name=\"resolver\">The resolver.</param>\n    /// <param name=\"name\">The registration name.</param>\n    /// <param name=\"resolutionBehavior\">The resolution behavior.</param>\n    /// <returns>True if the service can be resolved, otherwise false.</returns>\n    public static bool CanResolve<TFrom>(this IDependencyResolver resolver, object? name = null, ResolutionBehavior resolutionBehavior = ResolutionBehavior.Default) =>\n        resolver.CanResolve(TypeCache<TFrom>.Type, name, resolutionBehavior);\n}"
  },
  {
    "path": "src/Resolution/Extensions/InjectionParameterExtensions.cs",
    "content": "﻿using Stashbox.Utils;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Linq.Expressions;\n\nnamespace Stashbox.Resolution.Extensions;\n\ninternal static class InjectionParameterExtensions\n{\n    public static Expression? SelectInjectionParameterOrDefault(this IEnumerable<KeyValuePair<string, object?>> injectionParameters,\n        TypeInformation typeInformation)\n    {\n        var memberName = typeInformation.ParameterOrMemberName;\n        var matchingParam = injectionParameters.FirstOrDefault(param => param.Key == memberName);\n        if (matchingParam.Equals(default(KeyValuePair<string, object?>))) return null;\n\n        if (matchingParam.Value == null)\n            return typeInformation.Type == TypeCache<object>.Type\n                ? matchingParam.Value.AsConstant()\n                : matchingParam.Value.AsConstant().ConvertTo(typeInformation.Type);\n\n        return matchingParam.Value.GetType() == typeInformation.Type\n            ? matchingParam.Value.AsConstant()\n            : matchingParam.Value.AsConstant().ConvertTo(typeInformation.Type);\n\n    }\n}"
  },
  {
    "path": "src/Resolution/Extensions/ResolutionBehaviorExtensions.cs",
    "content": "﻿namespace Stashbox.Resolution;\n\ninternal static class ResolutionBehaviorExtensions\n{\n    public static bool Has(this ResolutionBehavior resolutionBehavior, ResolutionBehavior toCheck) =>\n        (resolutionBehavior & toCheck) == toCheck;\n}"
  },
  {
    "path": "src/Resolution/ILookupResolver.cs",
    "content": "﻿namespace Stashbox.Resolution;\n\ninternal interface ILookup\n{\n    bool CanLookupService(TypeInformation typeInfo, ResolutionContext resolutionContext);\n}"
  },
  {
    "path": "src/Resolution/IRequestContext.cs",
    "content": "﻿using System;\n\nnamespace Stashbox.Resolution;\n\n/// <summary>\n/// Represents an information storage for resolution requests.\n/// </summary>\npublic interface IRequestContext\n{\n    /// <summary>\n    /// Returns a dependency override for a given type.\n    /// </summary>\n    /// <param name=\"dependencyType\">The type of the dependency override.</param>\n    /// <returns>The object used to override a dependency.</returns>\n    object? GetDependencyOverrideOrDefault(Type dependencyType);\n\n    /// <summary>\n    /// Returns a dependency override for a given type.\n    /// </summary>\n    /// <typeparam name=\"TResult\">The type of the dependency override.</typeparam>\n    /// <returns>The object used to override a dependency.</returns>\n    TResult? GetDependencyOverrideOrDefault<TResult>();\n\n    /// <summary>\n    /// Returns each dependency override passed to the resolution request.\n    /// </summary>\n    object[] GetOverrides();\n\n    /// <summary>\n    /// Marks an instance as non-disposable, so the container will exclude it from disposal tracking.\n    /// </summary>\n    /// <param name=\"value\">The instance to mark.</param>\n    /// <returns>The instance.</returns>\n    TInstance ExcludeFromTracking<TInstance>(TInstance value)\n        where TInstance : class;\n}\n\ninternal interface IInternalRequestContext : IRequestContext\n{\n    object GetOrAddInstance(int key, Func<IResolutionScope, IRequestContext, object> factory, IResolutionScope scope);\n\n    bool IsInstanceExcludedFromTracking(object instance);\n}"
  },
  {
    "path": "src/Resolution/IResolutionStrategy.cs",
    "content": "﻿using System;\nusing Stashbox.Registration;\nusing System.Collections.Generic;\n\nnamespace Stashbox.Resolution;\n\n/// <summary>\n/// Represents a resolution strategy.\n/// </summary>\npublic interface IResolutionStrategy\n{\n    /// <summary>\n    /// Registers an <see cref=\"IResolver\"/>.\n    /// </summary>\n    /// <param name=\"resolver\">The resolver implementation.</param>\n    void RegisterResolver(IResolver resolver);\n\n    /// <summary>\n    /// Builds the resolution expression for the requested service.\n    /// </summary>\n    /// <param name=\"resolutionContext\">The resolution context.</param>\n    /// <param name=\"typeInformation\">The type info of the requested service.</param>\n    /// <returns>The built expression tree.</returns>\n    ServiceContext BuildExpressionForType(ResolutionContext resolutionContext, TypeInformation typeInformation);\n\n    /// <summary>\n    /// Builds all the resolution expressions for the enumerable service request.\n    /// </summary>\n    /// <param name=\"resolutionContext\">The resolution context.</param>\n    /// <param name=\"typeInformation\">The type information of the enumerable item type.</param>\n    /// <returns>The built expression tree.</returns>\n    IEnumerable<ServiceContext> BuildExpressionsForEnumerableRequest(ResolutionContext resolutionContext, TypeInformation typeInformation);\n\n    /// <summary>\n    /// Builds the resolution expression for the requested service registration.\n    /// </summary>\n    /// <param name=\"serviceRegistration\">The service registration.</param>\n    /// <param name=\"resolutionContext\">The resolution context.</param>\n    /// <param name=\"typeInformation\">The type info of the requested service.</param>\n    /// <returns>The built expression tree.</returns>\n    ServiceContext BuildExpressionForRegistration(ServiceRegistration serviceRegistration, ResolutionContext resolutionContext, TypeInformation typeInformation);\n\n    /// <summary>\n    /// Determines whether a type is resolvable with the current container state or not.\n    /// </summary>\n    /// <param name=\"resolutionContext\">The resolution context.</param>\n    /// <param name=\"typeInformation\">The type info of the requested service.</param>\n    /// <returns>True if a type is resolvable, otherwise false.</returns>\n    bool IsTypeResolvable(ResolutionContext resolutionContext, TypeInformation typeInformation);\n}"
  },
  {
    "path": "src/Resolution/IResolver.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\n\nnamespace Stashbox.Resolution;\n\n/// <summary>\n/// The base interface for wrappers and resolvers.\n/// </summary>\npublic interface IResolver;\n    \n/// <summary>\n/// Represents a dependency resolver.\n/// </summary>\npublic interface IServiceResolver : IResolver\n{\n    /// <summary>\n    /// Produces an expression for creating an instance.\n    /// </summary>\n    /// <param name=\"resolutionStrategy\">The resolution strategy used to build the underlying resolution expression tree.</param>\n    /// <param name=\"typeInfo\">The information about the type to resolve.</param>\n    /// <param name=\"resolutionContext\">The contextual information about the current resolution call.</param>\n    /// <returns>The built resolution expression.</returns>\n    ServiceContext GetExpression(\n        IResolutionStrategy resolutionStrategy,\n        TypeInformation typeInfo,\n        ResolutionContext resolutionContext);\n\n    /// <summary>\n    /// Returns true, if the resolver can be used to activate the requested service, otherwise false.\n    /// </summary>\n    /// <param name=\"typeInfo\">The information about the type to resolve.</param>\n    /// <param name=\"resolutionContext\">The contextual information about the current resolution call.</param>\n    /// <returns>Returns true, if the resolver can be used to activate the requested service, otherwise false.</returns>\n    bool CanUseForResolution(TypeInformation typeInfo,\n        ResolutionContext resolutionContext);\n}\n\n/// <summary>\n/// Represents a dependency resolver that can produce a collection of services.\n/// </summary>\npublic interface IEnumerableSupportedResolver : IServiceResolver\n{\n    /// <summary>\n    /// Produces an array of expressions, one for every registered service identified by the requested type.\n    /// </summary>\n    /// <param name=\"resolutionStrategy\">The resolution strategy used to build the underlying resolution expression tree.</param>\n    /// <param name=\"typeInfo\">The information about the enumerable item type to resolve.</param>\n    /// <param name=\"resolutionContext\">The contextual information about the current resolution call.</param>\n    /// <returns>The array of all the resolution expression built by the resolver.</returns>\n    IEnumerable<ServiceContext> GetExpressionsForEnumerableRequest(\n        IResolutionStrategy resolutionStrategy,\n        TypeInformation typeInfo,\n        ResolutionContext resolutionContext);\n}"
  },
  {
    "path": "src/Resolution/IWrapper.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq.Expressions;\n\nnamespace Stashbox.Resolution;\n\n/// <summary>\n/// Represents a wrapper that can wrap a service.\n/// </summary>\npublic interface IServiceWrapper : IResolver\n{\n    /// <summary>\n    /// Wraps the expression that describes the service.\n    /// </summary>\n    /// <param name=\"originalTypeInformation\">The requested type's meta information.</param>\n    /// <param name=\"wrappedTypeInformation\">The wrapped type's meta information.</param>\n    /// <param name=\"serviceContext\">The wrapped service's context that contains the actual instantiation expression and additional meta information.</param>\n    /// <returns>The wrapped service expression.</returns>\n    Expression WrapExpression(TypeInformation originalTypeInformation,\n        TypeInformation wrappedTypeInformation,\n        ServiceContext serviceContext);\n\n    /// <summary>\n    /// Un-wraps the underlying service type from a wrapped type request.\n    /// </summary>\n    /// <param name=\"type\">The requested type to unwrap.</param>\n    /// <param name=\"unWrappedType\">The un-wrapped service type.</param>\n    /// <returns>True if the un-wrapping was successful, otherwise false.</returns>\n    bool TryUnWrap(Type type, out Type unWrappedType);\n}\n\n/// <summary>\n/// Represents a wrapper that can wrap a collection of a service.\n/// </summary>\npublic interface IEnumerableWrapper : IResolver\n{\n    /// <summary>\n    /// Wraps the expression that describes the service.\n    /// </summary>\n    /// <param name=\"originalTypeInformation\">The requested type's meta information.</param>\n    /// <param name=\"wrappedTypeInformation\">The wrapped type's meta information.</param>\n    /// <param name=\"serviceContexts\">The service contexts that contains the actual instantiation expressions and additional meta information.</param>\n    /// <returns>The wrapped service expression.</returns>\n    Expression WrapExpression(TypeInformation originalTypeInformation, TypeInformation wrappedTypeInformation,\n        IEnumerable<ServiceContext> serviceContexts);\n\n    /// <summary>\n    /// Un-wraps the underlying service type from a wrapped type request.\n    /// </summary>\n    /// <param name=\"type\">The requested type to unwrap.</param>\n    /// <param name=\"unWrappedType\">The un-wrapped service type.</param>\n    /// <returns>True if the un-wrapping was successful, otherwise false.</returns>\n    bool TryUnWrap(Type type, out Type unWrappedType);\n}\n\n/// <summary>\n/// Represents a wrapper that can wrap a service with function parameters.\n/// </summary>\npublic interface IParameterizedWrapper : IResolver\n{\n    /// <summary>\n    /// Wraps the expression that describes the service.\n    /// </summary>\n    /// <param name=\"originalTypeInformation\">The requested type's meta information.</param>\n    /// <param name=\"wrappedTypeInformation\">The wrapped type's meta information.</param>\n    /// <param name=\"serviceContext\">The wrapped service's context that contains the actual instantiation expression and additional meta information.</param>\n    /// <param name=\"parameterExpressions\">The wrapper's parameter expressions.</param>\n    /// <returns>The wrapped service expression.</returns>\n    Expression WrapExpression(TypeInformation originalTypeInformation, TypeInformation wrappedTypeInformation,\n        ServiceContext serviceContext, IEnumerable<ParameterExpression> parameterExpressions);\n\n    /// <summary>\n    /// Un-wraps the underlying service type from a wrapped type request.\n    /// </summary>\n    /// <param name=\"type\">The requested type to unwrap.</param>\n    /// <param name=\"unWrappedType\">The un-wrapped service type.</param>\n    /// <param name=\"parameterTypes\">The wrapper's parameter types.</param>\n    /// <returns>True if the un-wrapping was successful, otherwise false.</returns>\n    bool TryUnWrap(Type type, out Type unWrappedType, out IEnumerable<Type> parameterTypes);\n}\n\n/// <summary>\n/// Represents a wrapper that can wrap a service with metadata.\n/// </summary>\npublic interface IMetadataWrapper : IResolver\n{\n    /// <summary>\n    /// Wraps the expression that describes the service.\n    /// </summary>\n    /// <param name=\"originalTypeInformation\">The requested type's meta information.</param>\n    /// <param name=\"wrappedTypeInformation\">The wrapped type's meta information.</param>\n    /// <param name=\"serviceContext\">The wrapped service's context that contains the actual instantiation expression and additional meta information.</param>\n    /// <returns>The wrapped service expression.</returns>\n    Expression WrapExpression(TypeInformation originalTypeInformation, TypeInformation wrappedTypeInformation,\n        ServiceContext serviceContext);\n\n    /// <summary>\n    /// Un-wraps the underlying service type from a wrapped type request.\n    /// </summary>\n    /// <param name=\"type\">The requested type to unwrap.</param>\n    /// <param name=\"unWrappedType\">The un-wrapped service type.</param>\n    /// <param name=\"metadataType\">The wrapper's metadata types.</param>\n    /// <returns>True if the un-wrapping was successful, otherwise false.</returns>\n    bool TryUnWrap(Type type, out Type unWrappedType, out Type metadataType);\n}"
  },
  {
    "path": "src/Resolution/RequestContext.cs",
    "content": "﻿using Stashbox.Utils;\nusing Stashbox.Utils.Data;\nusing System;\nusing System.Linq;\n\nnamespace Stashbox.Resolution;\n\ninternal class RequestContext : IInternalRequestContext\n{\n    public static readonly RequestContext Empty = new();\n\n    public static RequestContext FromOverrides(object[]? overrides) => new(overrides);\n\n    public static RequestContext Begin() => new();\n\n    private readonly Tree<object> excludedInstances = new();\n    private readonly Tree<object> perRequestInstances = new();\n    private readonly object[]? overrides;\n\n    private RequestContext(object[]? overrides = null)\n    {\n        this.overrides = overrides;\n    }\n\n    public object GetOrAddInstance(int key, Func<IResolutionScope, IRequestContext, object> factory, IResolutionScope scope)\n    {\n        var instance = this.perRequestInstances.GetOrDefault(key);\n        if (instance != null) return instance;\n\n        instance = factory(scope, this);\n        this.perRequestInstances.Add(key, instance);\n        return instance;\n    }\n\n    public object? GetDependencyOverrideOrDefault(Type dependencyType) =>\n        this.overrides == null ? null : Array.Find(this.overrides, dependencyType.IsInstanceOfType);\n\n    public TResult? GetDependencyOverrideOrDefault<TResult>() =>\n        (TResult?)this.GetDependencyOverrideOrDefault(TypeCache<TResult>.Type);\n\n    public object[] GetOverrides() => this.overrides ?? TypeCache.EmptyArray<object>();\n\n    public bool IsInstanceExcludedFromTracking(object instance)\n    {\n        var excluded = this.excludedInstances.GetOrDefault(instance.GetHashCode());\n        return excluded != null && ReferenceEquals(excluded, instance);\n    }\n\n    public TInstance ExcludeFromTracking<TInstance>(TInstance value)\n        where TInstance : class\n    {\n        this.excludedInstances.Add(value.GetHashCode(), value);\n        return value;\n    }\n}"
  },
  {
    "path": "src/Resolution/ResolutionBehavior.cs",
    "content": "﻿using System;\n\nnamespace Stashbox.Resolution;\n\n/// <summary>\n/// Service resolution behavior.\n/// </summary>\n[Flags]\npublic enum ResolutionBehavior\n{\n    /// <summary>\n    /// Indicates that both the current container (which initiated the resolution request) and its parents can participate in the resolution request's service selection.\n    /// </summary>\n    Default = Current | Parent,\n\n    /// <summary>\n    /// Indicates that parent containers (including all indirect ancestors) can participate in the resolution request's service selection.\n    /// </summary>\n    Parent = 1 << 0,\n\n    /// <summary>\n    /// Indicates that the current container (which initiated the resolution request) can participate in the service selection.\n    /// </summary>\n    Current = 1 << 1,\n    \n    /// <summary>\n    /// Indicates that parent containers (including all indirect ancestors) can only provide dependencies for services that are already selected for resolution.\n    /// </summary>\n    ParentDependency = 1 << 2,\n    \n    /// <summary>\n    /// Upon enumerable resolution, when both <see cref=\"Current\"/> and <see cref=\"Parent\"/> behaviors are enabled, and the current container has the appropriate services, the resolution will prefer those and ignore the parent containers. When the current container doesn't have the requested services, the parent containers will serve the request.\n    /// </summary>\n    PreferEnumerableInCurrent = 1 << 3,\n}"
  },
  {
    "path": "src/Resolution/ResolutionContext.cs",
    "content": "﻿using Stashbox.Registration;\nusing Stashbox.Utils;\nusing Stashbox.Utils.Data;\nusing Stashbox.Utils.Data.Immutable;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Linq.Expressions;\nusing System.Runtime.CompilerServices;\nusing Stashbox.Exceptions;\nusing Stashbox.Lifetime;\n\nnamespace Stashbox.Resolution;\n\n/// <summary>\n/// Represents information about the actual resolution flow.\n/// </summary>\npublic class ResolutionContext\n{\n    internal class PerRequestConfiguration\n    {\n        public bool RequiresRequestContext;\n        public bool FactoryDelegateCacheEnabled;\n    }\n\n    internal class AutoLifetimeTracker\n    {\n        public LifetimeDescriptor HighestRankingLifetime = Lifetimes.Transient;\n    }\n    \n    private readonly bool shouldFallBackToRequestInitiatorContext;\n\n    internal readonly Tree<Expression> ExpressionCache;\n    internal readonly Utils.Data.Stack<object> ScopeNames;\n    internal readonly PerRequestConfiguration RequestConfiguration;\n    internal readonly Utils.Data.Stack<int> CircularDependencyBarrier;\n    internal readonly Tree<Func<IResolutionScope, IRequestContext, object>> FactoryCache;\n    internal readonly HashTree<Type, ExpandableArray<Override>>? ExpressionOverrides;\n    internal readonly ExpandableArray<Expression> SingleInstructions;\n    internal readonly Tree<ParameterExpression> DefinedVariables;\n    internal readonly ExpandableArray<Pair<bool, ParameterExpression>[]> ParameterExpressions;\n    internal readonly ExpandableArray<Type, Utils.Data.Stack<ServiceRegistration>> RemainingDecorators;\n    internal readonly ExpandableArray<ServiceRegistration> CurrentDecorators;\n    internal readonly IContainerContext RequestInitiatorContainerContext;\n    internal readonly ResolutionBehavior RequestInitiatorResolutionBehavior;\n    internal readonly int CurrentLifeSpan;\n    internal readonly string? NameOfServiceLifeSpanValidatingAgainst;\n    internal readonly bool PerResolutionRequestCacheEnabled;\n    internal readonly bool UnknownTypeCheckDisabled;\n    internal readonly RequestContext RequestContext;\n    internal readonly bool IsValidationContext;\n    internal readonly AutoLifetimeTracker? AutoLifetimeTracking;\n\n    /// <summary>\n    /// True if the resolution is currently in the parent context.\n    /// </summary>\n    public readonly bool IsInParentContext;\n    \n    /// <summary>\n    /// True if a null result is allowed, otherwise false.\n    /// </summary>\n    public readonly bool NullResultAllowed;\n\n    /// <summary>\n    /// When it's true, it indicates that the current resolution request was made from the root scope.\n    /// </summary>\n    public readonly bool IsRequestedFromRoot;\n\n    /// <summary>\n    /// The currently resolving scope.\n    /// </summary>\n    public readonly ParameterExpression RequestContextParameter;\n\n    /// <summary>\n    /// The currently resolving scope.\n    /// </summary>\n    public readonly ParameterExpression CurrentScopeParameter;\n\n    /// <summary>\n    /// The context of the current container instance.\n    /// </summary>\n    public readonly IContainerContext CurrentContainerContext;\n    \n    /// <summary>\n    /// The resolution behavior.\n    /// </summary>\n    public readonly ResolutionBehavior ResolutionBehavior;\n\n    private ResolutionContext(IEnumerable<object> initialScopeNames,\n        IContainerContext currentContainerContext,\n        ResolutionBehavior resolutionBehavior,\n        bool isRequestedFromRoot,\n        bool nullResultAllowed,\n        bool isValidationContext,\n        object[]? dependencyOverrides,\n        ImmutableTree<Type, ImmutableBucket<Override>>? knownInstances,\n        ParameterExpression[]? initialParameters)\n    {\n        this.RequestConfiguration = new PerRequestConfiguration();\n        this.DefinedVariables = new Tree<ParameterExpression>();\n        this.SingleInstructions = [];\n        this.RemainingDecorators = [];\n        this.CurrentDecorators = [];\n        this.CircularDependencyBarrier = [];\n        this.ExpressionCache = new Tree<Expression>();\n        this.FactoryCache = new Tree<Func<IResolutionScope, IRequestContext, object>>();\n        this.ResolutionBehavior = this.RequestInitiatorResolutionBehavior = resolutionBehavior;\n        this.NullResultAllowed = nullResultAllowed;\n        this.IsRequestedFromRoot = isRequestedFromRoot;\n        this.ScopeNames = initialScopeNames.AsStack();\n        this.CurrentScopeParameter = Constants.ResolutionScopeParameter;\n        this.RequestContextParameter = Constants.RequestContextParameter;\n        this.CurrentContainerContext = this.RequestInitiatorContainerContext = currentContainerContext;\n        this.RequestConfiguration.FactoryDelegateCacheEnabled = this.PerResolutionRequestCacheEnabled = dependencyOverrides == null;\n        this.RequestContext = dependencyOverrides != null ? RequestContext.FromOverrides(dependencyOverrides) : RequestContext.Begin();\n        this.IsValidationContext = isValidationContext;\n        this.AutoLifetimeTracking = null;\n\n        this.ExpressionOverrides = dependencyOverrides == null && (knownInstances == null || knownInstances.IsEmpty)\n            ? null\n            : ProcessDependencyOverrides(dependencyOverrides, knownInstances);\n\n        this.ParameterExpressions = initialParameters != null\n            ? [initialParameters.AsParameterPairs()]\n            : [];\n    }\n\n    private ResolutionContext(PerRequestConfiguration perRequestConfiguration,\n        Tree<ParameterExpression> definedVariables,\n        ExpandableArray<Expression> singleInstructions,\n        ExpandableArray<Type, Utils.Data.Stack<ServiceRegistration>> remainingDecorators,\n        ExpandableArray<ServiceRegistration> currentDecorators,\n        Utils.Data.Stack<int> circularDependencyBarrier,\n        Tree<Expression> cachedExpressions,\n        Tree<Func<IResolutionScope, IRequestContext, object>> factoryCache,\n        Utils.Data.Stack<object> scopeNames,\n        ParameterExpression currentScopeParameter,\n        ParameterExpression requestContextParameter,\n        IContainerContext currentContainerContext,\n        IContainerContext requestInitiatorContainerContext,\n        HashTree<Type, ExpandableArray<Override>>? expressionOverrides,\n        ExpandableArray<Pair<bool, ParameterExpression>[]> parameterExpressions,\n        RequestContext requestContext,\n        AutoLifetimeTracker? autoLifetimeTracker,\n        ResolutionBehavior resolutionBehavior,\n        ResolutionBehavior requestInitiatorResolutionBehavior,\n        bool nullResultAllowed,\n        bool isRequestedFromRoot,\n        string? nameOfServiceLifeSpanValidatingAgainst,\n        int currentLifeSpan,\n        bool perResolutionRequestCacheEnabled,\n        bool unknownTypeCheckDisabled,\n        bool shouldFallBackToRequestInitiatorContext,\n        bool isValidationContext)\n    {\n        this.RequestConfiguration = perRequestConfiguration;\n        this.DefinedVariables = definedVariables;\n        this.SingleInstructions = singleInstructions;\n        this.RemainingDecorators = remainingDecorators;\n        this.CurrentDecorators = currentDecorators;\n        this.CircularDependencyBarrier = circularDependencyBarrier;\n        this.ExpressionCache = cachedExpressions;\n        this.FactoryCache = factoryCache;\n        this.NullResultAllowed = nullResultAllowed;\n        this.IsRequestedFromRoot = isRequestedFromRoot;\n        this.ScopeNames = scopeNames;\n        this.CurrentScopeParameter = currentScopeParameter;\n        this.RequestContextParameter = requestContextParameter;\n        this.CurrentContainerContext = currentContainerContext;\n        this.RequestInitiatorContainerContext = requestInitiatorContainerContext;\n        this.ExpressionOverrides = expressionOverrides;\n        this.ParameterExpressions = parameterExpressions;\n        this.NameOfServiceLifeSpanValidatingAgainst = nameOfServiceLifeSpanValidatingAgainst;\n        this.CurrentLifeSpan = currentLifeSpan;\n        this.PerResolutionRequestCacheEnabled = perResolutionRequestCacheEnabled;\n        this.UnknownTypeCheckDisabled = unknownTypeCheckDisabled;\n        this.shouldFallBackToRequestInitiatorContext = shouldFallBackToRequestInitiatorContext;\n        this.RequestContext = requestContext;\n        this.IsValidationContext = isValidationContext;\n        this.ResolutionBehavior = resolutionBehavior;\n        this.RequestInitiatorResolutionBehavior = requestInitiatorResolutionBehavior;\n        this.AutoLifetimeTracking = autoLifetimeTracker;\n        this.IsInParentContext = requestInitiatorContainerContext != currentContainerContext;\n    }\n\n    /// <summary>\n    /// Adds a custom expression to the instruction list\n    /// </summary>\n    /// <param name=\"instruction\">The custom expression.</param>\n    public void AddInstruction(Expression instruction) =>\n        this.SingleInstructions.Add(instruction);\n\n    /// <summary>\n    /// Adds a global keyed variable to the compiled expression tree.\n    /// </summary>\n    /// <param name=\"key\">The key of the variable.</param>\n    /// <param name=\"parameter\">The variable.</param>\n    public void AddDefinedVariable(int key, ParameterExpression parameter) =>\n        this.DefinedVariables.Add(key, parameter);\n\n    /// <summary>\n    /// Adds a global variable to the compiled expression tree.\n    /// </summary>\n    /// <param name=\"parameter\">The variable.</param>\n    public void AddDefinedVariable(ParameterExpression parameter) =>\n        this.DefinedVariables.Add(RuntimeHelpers.GetHashCode(parameter), parameter);\n\n    internal void CacheExpression(int key, Expression expression) =>\n        this.ExpressionCache.Add(key, expression);\n\n    internal static ResolutionContext BeginTopLevelContext(\n        IEnumerable<object> initialScopeNames,\n        IContainerContext currentContainerContext,\n        ResolutionBehavior resolutionBehavior,\n        bool isRequestedFromRoot,\n        bool nullResultAllowed,\n        object[]? dependencyOverrides = null,\n        ImmutableTree<Type, ImmutableBucket<Override>>? knownInstances = null,\n        ParameterExpression[]? initialParameters = null) =>\n        new(initialScopeNames,\n            currentContainerContext,\n            resolutionBehavior,\n            isRequestedFromRoot,\n            nullResultAllowed,\n            false,\n            dependencyOverrides,\n            knownInstances,\n            initialParameters);\n\n    internal static ResolutionContext BeginValidationContext(IContainerContext currentContainerContext, ResolutionBehavior resolutionBehavior) =>\n        new(TypeCache.EmptyArray<object>(), currentContainerContext, resolutionBehavior, false, false, true, null, null, null);\n\n    internal ResolutionContext BeginParentContainerContext(IContainerContext currentContainerContext) =>\n        this.Clone(currentContainerContext: currentContainerContext,\n            shouldFallBackToRequestInitiator: this.RequestInitiatorContainerContext != currentContainerContext,\n            resolutionBehavior: this.ResolutionBehavior | ResolutionBehavior.Current);\n    \n    internal ResolutionContext FallBackToRequestInitiatorIfNeeded() =>\n        this.shouldFallBackToRequestInitiatorContext\n            ? this.Clone(currentContainerContext: this.RequestInitiatorContainerContext,\n                shouldFallBackToRequestInitiator: false,\n                resolutionBehavior: this.RequestInitiatorResolutionBehavior)\n            : this;\n\n    internal ResolutionContext BeginNewScopeContext(ReadOnlyKeyValue<object, ParameterExpression> scopeParameter)\n    {\n        this.ScopeNames.PushBack(scopeParameter.Key);\n        return this.Clone(definedVariables: new Tree<ParameterExpression>(),\n            singleInstructions: [],\n            cachedExpressions: new Tree<Expression>(),\n            scopeNames: this.ScopeNames,\n            currentScopeParameter: scopeParameter.Value);\n    }\n\n    internal ResolutionContext BeginSubGraph() =>\n        this.Clone(definedVariables: new Tree<ParameterExpression>(),\n            singleInstructions: [],\n            cachedExpressions: new Tree<Expression>());\n\n    internal ResolutionContext BeginUnknownTypeCheckDisabledContext() =>\n        this.UnknownTypeCheckDisabled ? this : this.Clone(unknownTypeCheckDisabled: true);\n\n    internal ResolutionContext BeginContextWithFunctionParameters(ParameterExpression[] parameterExpressions) =>\n        this.Clone(parameterExpressions: new ExpandableArray<Pair<bool, ParameterExpression>[]>(this.ParameterExpressions)\n            {parameterExpressions.AsParameterPairs()}, perResolutionRequestCacheEnabled: false);\n\n    internal ResolutionContext BeginDecoratingContext(Type decoratingType, IEnumerable<ServiceRegistration> serviceRegistrations)\n    {\n        var newStack = new Utils.Data.Stack<ServiceRegistration>(serviceRegistrations);\n        var current = newStack.Pop();\n        var decorators = new ExpandableArray<Type, Utils.Data.Stack<ServiceRegistration>>(this.RemainingDecorators);\n        decorators.AddOrUpdate(decoratingType, newStack);\n\n        return this.Clone(currentDecorators: new ExpandableArray<ServiceRegistration>(this.CurrentDecorators) { current },\n            remainingDecorators: decorators);\n    }\n\n    internal ResolutionContext BeginLifetimeValidationContext(int lifeSpan, string currentlyLifeSpanValidatingService) =>\n        this.Clone(currentLifeSpan: lifeSpan, nameOfServiceLifeSpanValidatingAgainst: currentlyLifeSpanValidatingService);\n\n    internal ResolutionContext BeginAutoLifetimeTrackingContext(AutoLifetimeTracker autoLifetimeTracker) =>\n        this.Clone(autoLifetimeTracker: autoLifetimeTracker,\n            definedVariables: new Tree<ParameterExpression>(),\n            singleInstructions: [],\n            cachedExpressions: new Tree<Expression>());\n    \n    private static HashTree<Type, ExpandableArray<Override>> ProcessDependencyOverrides(object[]? dependencyOverrides, ImmutableTree<Type, ImmutableBucket<Override>>? knownInstances)\n    {\n        var overrides = new HashTree<Type, ExpandableArray<Override>>();\n\n        if (knownInstances is { IsEmpty: false })\n            foreach (var lateKnownInstance in knownInstances.Walk())\n                overrides.Add(lateKnownInstance.Key, new ExpandableArray<Override>(lateKnownInstance.Value.Repository));\n\n        if (dependencyOverrides == null) return overrides;\n\n        foreach (var dependencyOverride in dependencyOverrides)\n        {\n            if (dependencyOverride is Override @override)\n            {\n                var arr = overrides.GetOrDefault(@override.Type);\n                if (arr != null) \n                    arr.Add(@override);\n                else\n                    overrides.Add(@override.Type, [@override]);\n                continue;\n            }\n            \n            var type = dependencyOverride.GetType();\n            Type[] allTypes = [type, .. type.GetRegisterableInterfaceTypes().Concat(type.GetRegisterableBaseTypes())];\n            foreach (var depType in allTypes)\n            {\n                var expOverride = Override.Of(depType, instance: dependencyOverride);\n                var depOverride = overrides.GetOrDefault(depType);\n                if (depOverride != null) \n                    depOverride.Add(expOverride);\n                else \n                    overrides.Add(depType, new ExpandableArray<Override>(new [] {expOverride}));\n            }\n        }\n\n        return overrides;\n    }\n\n    private ResolutionContext Clone(\n        Tree<ParameterExpression>? definedVariables = null,\n        ExpandableArray<Expression>? singleInstructions = null,\n        ExpandableArray<Type, Utils.Data.Stack<ServiceRegistration>>? remainingDecorators = null,\n        ExpandableArray<ServiceRegistration>? currentDecorators = null,\n        Tree<Expression>? cachedExpressions = null,\n        Utils.Data.Stack<object>? scopeNames = null,\n        ParameterExpression? currentScopeParameter = null,\n        IContainerContext? currentContainerContext = null,\n        ExpandableArray<Pair<bool, ParameterExpression>[]>? parameterExpressions = null,\n        ResolutionBehavior? resolutionBehavior = null,\n        AutoLifetimeTracker? autoLifetimeTracker = null,\n        string? nameOfServiceLifeSpanValidatingAgainst = null,\n        int? currentLifeSpan = null,\n        bool? perResolutionRequestCacheEnabled = null,\n        bool? unknownTypeCheckDisabled = null,\n        bool? shouldFallBackToRequestInitiator = null,\n        bool? nullResultAllowed = null) =>\n        new(this.RequestConfiguration,\n            definedVariables ?? this.DefinedVariables,\n            singleInstructions ?? this.SingleInstructions,\n            remainingDecorators ?? this.RemainingDecorators,\n            currentDecorators ?? this.CurrentDecorators,\n            this.CircularDependencyBarrier,\n            cachedExpressions ?? this.ExpressionCache,\n            this.FactoryCache,\n            scopeNames ?? this.ScopeNames,\n            currentScopeParameter ?? this.CurrentScopeParameter,\n            this.RequestContextParameter,\n            currentContainerContext ?? this.CurrentContainerContext,\n            this.RequestInitiatorContainerContext,\n            this.ExpressionOverrides,\n            parameterExpressions ?? this.ParameterExpressions,\n            this.RequestContext,\n            autoLifetimeTracker ?? this.AutoLifetimeTracking,\n            resolutionBehavior ?? this.ResolutionBehavior,\n            this.RequestInitiatorResolutionBehavior,\n            nullResultAllowed ?? this.NullResultAllowed,\n            this.IsRequestedFromRoot,\n            nameOfServiceLifeSpanValidatingAgainst ?? this.NameOfServiceLifeSpanValidatingAgainst,\n            currentLifeSpan ?? this.CurrentLifeSpan,\n            perResolutionRequestCacheEnabled ?? this.PerResolutionRequestCacheEnabled,\n            unknownTypeCheckDisabled ?? this.UnknownTypeCheckDisabled,\n            shouldFallBackToRequestInitiator ?? this.shouldFallBackToRequestInitiatorContext,\n            this.IsValidationContext);\n}\n"
  },
  {
    "path": "src/Resolution/ResolutionStrategy.cs",
    "content": "﻿using Stashbox.Expressions;\nusing Stashbox.Lifetime;\nusing Stashbox.Registration;\nusing Stashbox.Resolution.Resolvers;\nusing Stashbox.Resolution.Wrappers;\nusing Stashbox.Utils;\nusing Stashbox.Utils.Data.Immutable;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Linq.Expressions;\nusing Stashbox.Exceptions;\n\nnamespace Stashbox.Resolution;\n\ninternal class ResolutionStrategy : IResolutionStrategy\n{\n    private readonly ParentContainerResolver parentContainerResolver;\n    private ImmutableBucket<IResolver> resolverRepository;\n\n    public ResolutionStrategy()\n    {\n        this.parentContainerResolver = new ParentContainerResolver();\n        this.resolverRepository = new ImmutableBucket<IResolver>([\n            new EnumerableWrapper(),\n            new LazyWrapper(),\n            new FuncWrapper(),\n            new MetadataWrapper(),\n            new KeyValueWrapper(),\n\n            new ServiceProviderResolver(),\n            new OptionalValueResolver(),\n            new DefaultValueResolver(),\n            this.parentContainerResolver,\n            new UnknownTypeResolver()\n        ]);\n    }\n\n    public ServiceContext BuildExpressionForType(ResolutionContext resolutionContext, TypeInformation typeInformation)\n    {\n        if (typeInformation.Type == TypeCache<IDependencyResolver>.Type)\n            return resolutionContext.CurrentScopeParameter.AsServiceContext();\n\n        if (typeInformation.Type == TypeCache<IRequestContext>.Type)\n        {\n            resolutionContext.RequestConfiguration.RequiresRequestContext = true;\n            return resolutionContext.RequestContextParameter.AsServiceContext();\n        }\n\n        if (typeInformation is { HasDependencyNameAttribute: true, Parent.DependencyName: not null } &&\n            typeInformation.Parent.DependencyName.GetType() == typeInformation.Type)\n            return typeInformation.Parent.DependencyName.AsConstant().ConvertTo(typeInformation.Type)\n                .AsServiceContext();\n\n        if (typeInformation.IsDependency)\n        {\n            if (resolutionContext.ParameterExpressions.Length > 0)\n            {\n                var type = typeInformation.Type;\n                var length = resolutionContext.ParameterExpressions.Length;\n                for (var i = length; i-- > 0;)\n                {\n                    var parameters = resolutionContext.ParameterExpressions[i]\n                        .Where(p => p.I2.Type == type ||\n                                    p.I2.Type.Implements(type)).CastToArray();\n\n                    if (parameters.Length == 0) continue;\n\n#if NET5_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER\n                    var selected = Array.Find(parameters, parameter => !parameter.I1) ?? parameters[^1];\n#else\n                    var selected = Array.Find(parameters, parameter => !parameter.I1) ??\n                                   parameters[parameters.Length - 1];\n#endif\n\n                    selected.I1 = true;\n                    return selected.I2.AsServiceContext();\n                }\n            }\n\n            var decorators = resolutionContext.RemainingDecorators.GetOrDefaultByRef(typeInformation.Type);\n            if (decorators is { Length: > 0 })\n                return BuildExpressionForDecorator(decorators.Front(),\n                    resolutionContext.BeginDecoratingContext(typeInformation.Type, decorators), typeInformation,\n                    decorators).AsServiceContext();\n        }\n\n        var exprOverride = resolutionContext.ExpressionOverrides?.GetOrDefault(typeInformation.Type);\n        if (exprOverride != null)\n        {\n            var expression = typeInformation.DependencyName != null\n                ? exprOverride.LastOrDefault(e => typeInformation.DependencyName.Equals(e.DependencyName))\n                : exprOverride.LastOrDefault();\n\n            if (expression != null)\n                return expression.Instance.AsConstant().AsServiceContext();\n        }\n\n        var registration = resolutionContext.ResolutionBehavior.Has(ResolutionBehavior.Current)\n            ? resolutionContext.CurrentContainerContext.RegistrationRepository\n                .GetRegistrationOrDefault(typeInformation, resolutionContext)\n            : null;\n\n        var isResolutionCallRequired = registration?.Options.IsOn(RegistrationOption.IsResolutionCallRequired) ?? false;\n        if (isResolutionCallRequired && typeInformation.IsDependency && registration != null)\n            return resolutionContext.CurrentScopeParameter\n                .ConvertTo(TypeCache<IDependencyResolver>.Type)\n                .CallMethod(Constants.ResolveMethod,\n                    typeInformation.Type.AsConstant(), typeInformation.DependencyName.AsConstant(),\n                    resolutionContext.ExpressionOverrides?.Walk().SelectMany(c =>\n                        c.Select(ov => ov)).ToArray().AsConstant() ?? TypeCache.EmptyArray<object>().AsConstant(),\n                    resolutionContext.ResolutionBehavior.AsConstant())\n                .ConvertTo(typeInformation.Type)\n                .AsServiceContext(registration);\n\n        return registration != null\n            ? this.BuildExpressionForRegistration(registration, resolutionContext, typeInformation)\n            : this.BuildExpressionUsingWrappersOrResolvers(resolutionContext, typeInformation);\n    }\n\n    public IEnumerable<ServiceContext> BuildExpressionsForEnumerableRequest(ResolutionContext resolutionContext,\n        TypeInformation typeInformation)\n    {\n        var registrations = resolutionContext.ResolutionBehavior.Has(ResolutionBehavior.Current)\n            ? resolutionContext.CurrentContainerContext.RegistrationRepository\n                .GetRegistrationsOrDefault(typeInformation, resolutionContext)\n            : null;\n\n        if (registrations == null)\n            return this.BuildEnumerableExpressionUsingWrappersOrResolvers(resolutionContext, typeInformation);\n\n        var expressions = registrations.Select(registration =>\n        {\n            var decorators = resolutionContext.RemainingDecorators.GetOrDefaultByRef(typeInformation.Type);\n            if (decorators == null || decorators.Length == 0)\n                return this.BuildExpressionForRegistration(registration, resolutionContext, typeInformation);\n\n            decorators.ReplaceBack(registration);\n            return BuildExpressionForDecorator(decorators.Front(),\n                resolutionContext.BeginDecoratingContext(typeInformation.Type, decorators),\n                typeInformation, decorators).AsServiceContext(registration);\n        });\n\n        if (resolutionContext.ResolutionBehavior.Has(ResolutionBehavior.PreferEnumerableInCurrent) &&\n            !resolutionContext.IsInParentContext)\n            return expressions;\n\n        if (!this.parentContainerResolver.CanUseForResolution(typeInformation, resolutionContext)) return expressions;\n\n        var parentRegistrations =\n            this.parentContainerResolver.GetExpressionsForEnumerableRequest(this, typeInformation,\n                resolutionContext);\n        return parentRegistrations.Concat(expressions);\n    }\n\n    public ServiceContext BuildExpressionForRegistration(ServiceRegistration serviceRegistration,\n        ResolutionContext resolutionContext, TypeInformation typeInformation)\n    {\n        if (serviceRegistration is OpenGenericRegistration openGenericRegistration)\n        {\n            var genericType =\n                serviceRegistration.ImplementationType.MakeGenericType(typeInformation.Type.GetGenericArguments());\n            serviceRegistration = openGenericRegistration.ProduceClosedRegistration(genericType);\n        }\n\n        var decoratorContext = resolutionContext.RequestInitiatorResolutionBehavior.Has(ResolutionBehavior.Current)\n            ? resolutionContext.RequestInitiatorContainerContext\n            : resolutionContext.RequestInitiatorContainerContext.ParentContext;\n\n        var decorators = resolutionContext.RequestInitiatorResolutionBehavior.Has(ResolutionBehavior.Parent) ||\n                         resolutionContext.RequestInitiatorResolutionBehavior.Has(ResolutionBehavior.ParentDependency)\n            ? CollectDecorators(serviceRegistration.ImplementationType, typeInformation,\n                resolutionContext, decoratorContext)\n            : SearchAndFilterDecorators(serviceRegistration.ImplementationType, typeInformation, resolutionContext,\n                decoratorContext);\n\n        if (decorators == null)\n            return BuildExpressionAndApplyLifetime(serviceRegistration, resolutionContext, typeInformation)\n                .AsServiceContext(serviceRegistration);\n\n        var stack = decorators.AsStack();\n        stack.PushBack(serviceRegistration);\n        return BuildExpressionForDecorator(stack.Front(),\n                resolutionContext.BeginDecoratingContext(typeInformation.Type, stack), typeInformation, stack)\n            .AsServiceContext(serviceRegistration);\n    }\n\n    public bool IsTypeResolvable(ResolutionContext resolutionContext, TypeInformation typeInformation)\n    {\n        if (typeInformation.Type.IsGenericTypeDefinition)\n            return false;\n\n        if (typeInformation.Type == TypeCache<IDependencyResolver>.Type ||\n            typeInformation.Type == TypeCache<IServiceProvider>.Type ||\n            typeInformation.Type == TypeCache<IRequestContext>.Type)\n            return true;\n\n        if (resolutionContext.CurrentContainerContext.RegistrationRepository.ContainsRegistration(typeInformation.Type,\n                typeInformation.DependencyName) ||\n            this.IsWrappedTypeRegistered(typeInformation, resolutionContext))\n            return true;\n\n        var exprOverride = resolutionContext.ExpressionOverrides?.GetOrDefault(typeInformation.Type);\n        if (exprOverride == null) return this.CanLookupService(typeInformation, resolutionContext);\n        if (typeInformation.DependencyName != null)\n            return exprOverride.LastOrDefault(exp => exp.DependencyName == typeInformation.DependencyName) != null;\n\n        return true;\n    }\n\n    public void RegisterResolver(IResolver resolver) =>\n        Swap.SwapValue(ref this.resolverRepository, (t1, _, _, _, repo) =>\n                repo.Insert(repo.Length - 4, t1), resolver, Constants.DelegatePlaceholder,\n            Constants.DelegatePlaceholder,\n            Constants.DelegatePlaceholder);\n\n    private ServiceContext BuildExpressionUsingWrappersOrResolvers(ResolutionContext resolutionContext,\n        TypeInformation typeInformation)\n    {\n        var length = this.resolverRepository.Length;\n        for (var i = 0; i < length; i++)\n        {\n            var wrapper = this.resolverRepository[i];\n\n            switch (wrapper)\n            {\n                case IEnumerableWrapper enumerableWrapper\n                    when enumerableWrapper.TryUnWrap(typeInformation.Type, out var unWrappedEnumerable):\n                {\n                    var unwrappedTypeInformation = typeInformation.Clone(unWrappedEnumerable);\n                    var expressions = this.BuildExpressionsForEnumerableRequest(resolutionContext,\n                        unwrappedTypeInformation);\n                    if (resolutionContext.CurrentContainerContext.ContainerConfiguration\n                            .ExceptionOverEmptyCollectionEnabled &&\n                        !typeInformation.Type.MapsToGenericTypeDefinition(TypeCache.EnumerableType) &&\n                        expressions == TypeCache.EmptyArray<ServiceContext>()) return ServiceContext.Empty;\n                    return enumerableWrapper\n                        .WrapExpression(typeInformation, unwrappedTypeInformation, expressions)\n                        .AsServiceContext();\n                }\n                case IServiceWrapper serviceWrapper\n                    when serviceWrapper.TryUnWrap(typeInformation.Type, out var unWrappedServiceType):\n                {\n                    var unwrappedTypeInformation = typeInformation.Clone(unWrappedServiceType);\n                    var serviceContext = this.BuildExpressionForType(resolutionContext, unwrappedTypeInformation);\n                    return serviceContext.IsEmpty()\n                        ? ServiceContext.Empty\n                        : serviceWrapper\n                            .WrapExpression(typeInformation, unwrappedTypeInformation, serviceContext)\n                            .AsServiceContext(serviceContext.ServiceRegistration);\n                }\n                case IParameterizedWrapper parameterizedWrapper when parameterizedWrapper.TryUnWrap(\n                    typeInformation.Type,\n                    out var unWrappedParameterizedType, out var parameters):\n                {\n                    var unwrappedTypeInformation = typeInformation.Clone(unWrappedParameterizedType);\n                    var parameterExpressions = parameters.Select(p => p.AsParameter()).CastToArray();\n                    var serviceContext = this.BuildExpressionForType(\n                        resolutionContext.BeginContextWithFunctionParameters(parameterExpressions),\n                        unwrappedTypeInformation);\n                    return serviceContext.IsEmpty()\n                        ? ServiceContext.Empty\n                        : parameterizedWrapper\n                            .WrapExpression(typeInformation, unwrappedTypeInformation, serviceContext,\n                                parameterExpressions)\n                            .AsServiceContext(serviceContext.ServiceRegistration);\n                }\n                case IMetadataWrapper metadataWrapper when metadataWrapper.TryUnWrap(typeInformation.Type,\n                    out var unWrappedType, out var unwrappedMetadataType):\n                {\n                    var unwrappedTypeInformation =\n                        typeInformation.Clone(unWrappedType, metadataType: unwrappedMetadataType);\n                    var serviceContext = this.BuildExpressionForType(resolutionContext, unwrappedTypeInformation);\n                    return serviceContext.IsEmpty()\n                        ? ServiceContext.Empty\n                        : metadataWrapper\n                            .WrapExpression(typeInformation, unwrappedTypeInformation, serviceContext)\n                            .AsServiceContext(serviceContext.ServiceRegistration);\n                }\n            }\n        }\n\n        return this.BuildExpressionUsingResolvers(resolutionContext, typeInformation);\n    }\n\n    private IEnumerable<ServiceContext> BuildEnumerableExpressionUsingWrappersOrResolvers(\n        ResolutionContext resolutionContext, TypeInformation typeInformation)\n    {\n        var length = this.resolverRepository.Length;\n        for (var i = 0; i < length; i++)\n        {\n            var wrapper = this.resolverRepository[i];\n\n            switch (wrapper)\n            {\n                case IServiceWrapper serviceWrapper\n                    when serviceWrapper.TryUnWrap(typeInformation.Type, out var unWrappedServiceType):\n                {\n                    var unwrappedTypeInformation = typeInformation.Clone(unWrappedServiceType);\n                    var serviceContexts = this.BuildExpressionsForEnumerableRequest(resolutionContext,\n                        unwrappedTypeInformation);\n                    return serviceContexts.Select(serviceContext => serviceWrapper\n                        .WrapExpression(typeInformation, unwrappedTypeInformation, serviceContext)\n                        .AsServiceContext(serviceContext.ServiceRegistration));\n                }\n                case IParameterizedWrapper parameterizedWrapper\n                    when parameterizedWrapper.TryUnWrap(typeInformation.Type, out var unWrappedParameterizedType,\n                        out var parameters):\n                {\n                    var unwrappedTypeInformation = typeInformation.Clone(unWrappedParameterizedType);\n                    var parameterExpressions = parameters.Select(p => p.AsParameter()).CastToArray();\n                    var serviceContexts = this.BuildExpressionsForEnumerableRequest(\n                        resolutionContext.BeginContextWithFunctionParameters(parameterExpressions),\n                        unwrappedTypeInformation);\n                    return serviceContexts.Select(serviceContext => parameterizedWrapper\n                        .WrapExpression(typeInformation, unwrappedTypeInformation, serviceContext, parameterExpressions)\n                        .AsServiceContext(serviceContext.ServiceRegistration));\n                }\n                case IMetadataWrapper metadataWrapper when metadataWrapper.TryUnWrap(typeInformation.Type,\n                    out var unWrappedType, out var unwrappedMetadataType):\n                {\n                    var unwrappedTypeInformation =\n                        typeInformation.Clone(unWrappedType, metadataType: unwrappedMetadataType);\n                    var serviceContexts = this.BuildExpressionsForEnumerableRequest(resolutionContext,\n                        unwrappedTypeInformation);\n                    return serviceContexts.Select(serviceContext => metadataWrapper\n                        .WrapExpression(typeInformation, unwrappedTypeInformation, serviceContext)\n                        .AsServiceContext(serviceContext.ServiceRegistration));\n                }\n            }\n        }\n\n        return this.BuildEnumerableExpressionsUsingResolvers(resolutionContext, typeInformation);\n    }\n\n    private ServiceContext BuildExpressionUsingResolvers(ResolutionContext resolutionContext,\n        TypeInformation typeInformation)\n    {\n        var length = this.resolverRepository.Length;\n        for (var i = 0; i < length; i++)\n        {\n            var item = this.resolverRepository[i];\n            if (item is IServiceResolver resolver && resolver.CanUseForResolution(typeInformation, resolutionContext))\n                return resolver.GetExpression(this, typeInformation, resolutionContext);\n        }\n\n        return ServiceContext.Empty;\n    }\n\n    private IEnumerable<ServiceContext> BuildEnumerableExpressionsUsingResolvers(ResolutionContext resolutionContext,\n        TypeInformation typeInformation)\n    {\n        var length = this.resolverRepository.Length;\n        for (var i = 0; i < length; i++)\n        {\n            var item = this.resolverRepository[i];\n            if (item is IEnumerableSupportedResolver resolver &&\n                resolver.CanUseForResolution(typeInformation, resolutionContext))\n                return resolver.GetExpressionsForEnumerableRequest(this, typeInformation,\n                    resolutionContext);\n        }\n\n        return TypeCache.EmptyArray<ServiceContext>();\n    }\n\n    private bool IsWrappedTypeRegistered(TypeInformation typeInformation, ResolutionContext resolutionContext)\n    {\n        var length = this.resolverRepository.Length;\n        for (var i = 0; i < length; i++)\n        {\n            var middleware = this.resolverRepository[i];\n            switch (middleware)\n            {\n                case IEnumerableWrapper enumerableWrapper\n                    when enumerableWrapper.TryUnWrap(typeInformation.Type, out var unWrappedEnumerableType) &&\n                    !resolutionContext.CurrentContainerContext.ContainerConfiguration\n                        .ExceptionOverEmptyCollectionEnabled || typeInformation.Type.MapsToGenericTypeDefinition(\n                                                                 TypeCache.EnumerableType)\n                                                             || resolutionContext.CurrentContainerContext\n                                                                 .RegistrationRepository\n                                                                 .ContainsRegistration(unWrappedEnumerableType,\n                                                                     typeInformation.DependencyName):\n                case IServiceWrapper serviceWrapper\n                    when serviceWrapper.TryUnWrap(typeInformation.Type, out var unWrappedServiceType) &&\n                         resolutionContext.CurrentContainerContext.RegistrationRepository.ContainsRegistration(\n                             unWrappedServiceType, typeInformation.DependencyName):\n                case IParameterizedWrapper parameterizedWrapper\n                    when parameterizedWrapper.TryUnWrap(typeInformation.Type, out var unWrappedParameterizedType,\n                             out var _) &&\n                         resolutionContext.CurrentContainerContext.RegistrationRepository.ContainsRegistration(\n                             unWrappedParameterizedType, typeInformation.DependencyName):\n                case IMetadataWrapper metadataWrapper\n                    when metadataWrapper.TryUnWrap(typeInformation.Type, out var unWrappedType, out var _) &&\n                         resolutionContext.CurrentContainerContext.RegistrationRepository.ContainsRegistration(\n                             unWrappedType, typeInformation.DependencyName):\n                    return true;\n            }\n        }\n\n        return false;\n    }\n\n    private bool CanLookupService(TypeInformation typeInfo, ResolutionContext resolutionContext)\n    {\n        var length = this.resolverRepository.Length;\n        for (var i = 0; i < length; i++)\n        {\n            var item = this.resolverRepository[i];\n            if (item is ILookup lookup && lookup.CanLookupService(typeInfo, resolutionContext))\n                return true;\n        }\n\n        return false;\n    }\n\n    private IEnumerable<ServiceRegistration>? CollectDecorators(Type implementationType,\n        TypeInformation typeInformation, ResolutionContext resolutionContext, IContainerContext? decoratorContext)\n    {\n        if (decoratorContext == null) return null;\n        var parentDecorators = CollectDecorators(implementationType,\n            typeInformation, resolutionContext, decoratorContext.ParentContext);\n\n        if (parentDecorators == null)\n            return SearchAndFilterDecorators(implementationType,\n                typeInformation, resolutionContext, decoratorContext);\n\n        var currentDecorators = SearchAndFilterDecorators(implementationType,\n            typeInformation, resolutionContext, decoratorContext);\n\n        return currentDecorators == null ? parentDecorators : parentDecorators.Concat(currentDecorators);\n    }\n\n    private IEnumerable<ServiceRegistration>? SearchAndFilterDecorators(Type implementationType,\n        TypeInformation typeInformation, ResolutionContext resolutionContext, IContainerContext? decoratorContext)\n    {\n        var decorators = decoratorContext?.DecoratorRepository.GetDecoratorsOrDefault(implementationType,\n            typeInformation, resolutionContext);\n\n        if (decorators == null) return null;\n\n        var filtered = decorators.Where(d =>\n        {\n            var types = d.ImplementationType.GetPossibleDependencyTypes().ToArray();\n            return types.Any(implementationType.Implements) ||\n                   types.Any(t => TryUnwrapTypeFrom(t, out var unwrapped) && implementationType.Implements(unwrapped));\n        }).ToArray();\n\n        return filtered.Length == 0 ? null : filtered;\n    }\n\n    private bool TryUnwrapTypeFrom(Type wrapped, out Type unwrapped)\n    {\n        var length = this.resolverRepository.Length;\n        for (var i = 0; i < length; i++)\n        {\n            var resolver = this.resolverRepository[i];\n            switch (resolver)\n            {\n                case IEnumerableWrapper enumerableWrapper when enumerableWrapper.TryUnWrap(wrapped, out unwrapped):\n                case IServiceWrapper serviceWrapper when serviceWrapper.TryUnWrap(wrapped, out unwrapped):\n                case IParameterizedWrapper parameterizedWrapper\n                    when parameterizedWrapper.TryUnWrap(wrapped, out unwrapped, out _):\n                case IMetadataWrapper metadataWrapper when metadataWrapper.TryUnWrap(wrapped, out unwrapped, out _):\n                    return true;\n            }\n        }\n\n        unwrapped = TypeCache.EmptyType;\n        return false;\n    }\n\n    private static Expression? BuildExpressionForDecorator(ServiceRegistration serviceRegistration,\n        ResolutionContext resolutionContext, TypeInformation typeInformation,\n        Utils.Data.Stack<ServiceRegistration> decorators)\n    {\n        if (serviceRegistration is OpenGenericRegistration openGenericRegistration)\n        {\n            var genericType =\n                serviceRegistration.ImplementationType.MakeGenericType(typeInformation.Type.GetGenericArguments());\n            serviceRegistration = openGenericRegistration.ProduceClosedRegistration(genericType);\n        }\n\n        return BuildExpressionAndApplyLifetime(serviceRegistration, resolutionContext,\n            typeInformation, decorators.PeekBack()?.Lifetime);\n    }\n\n    private static Expression? BuildExpressionAndApplyLifetime(ServiceRegistration serviceRegistration,\n        ResolutionContext resolutionContext, TypeInformation typeInformation,\n        LifetimeDescriptor? secondaryLifetimeDescriptor = null)\n    {\n        var lifetimeDescriptor = secondaryLifetimeDescriptor != null && serviceRegistration.Lifetime is EmptyLifetime\n            ? secondaryLifetimeDescriptor\n            : serviceRegistration.Lifetime;\n\n        var expression = !IsOutputLifetimeManageable(serviceRegistration) || lifetimeDescriptor is EmptyLifetime\n            ? ExpressionBuilder.BuildExpressionForRegistration(serviceRegistration, resolutionContext, typeInformation)\n            : lifetimeDescriptor.ApplyLifetime(serviceRegistration, resolutionContext, typeInformation);\n\n        return typeInformation.Type != expression?.Type\n            ? expression?.ConvertTo(typeInformation.Type)\n            : expression;\n    }\n\n    private static bool IsOutputLifetimeManageable(ServiceRegistration serviceRegistration) =>\n        serviceRegistration is not OpenGenericRegistration &&\n        !serviceRegistration.IsInstance();\n}"
  },
  {
    "path": "src/Resolution/Resolvers/DefaultValueResolver.cs",
    "content": "﻿using Stashbox.Utils;\nusing System.Linq.Expressions;\n\nnamespace Stashbox.Resolution.Resolvers;\n\ninternal class DefaultValueResolver : IServiceResolver\n{\n    public ServiceContext GetExpression(\n        IResolutionStrategy resolutionStrategy,\n        TypeInformation typeInfo,\n        ResolutionContext resolutionContext) =>\n        typeInfo.Type.AsDefault().AsServiceContext();\n\n    public bool CanUseForResolution(TypeInformation typeInfo, ResolutionContext resolutionContext) =>\n        resolutionContext.CurrentContainerContext.ContainerConfiguration.DefaultValueInjectionEnabled &&\n        (typeInfo.Type.IsValueType\n         || typeInfo.Type == TypeCache<string>.Type);\n}"
  },
  {
    "path": "src/Resolution/Resolvers/OptionalValueResolver.cs",
    "content": "﻿using System.Linq.Expressions;\n\nnamespace Stashbox.Resolution.Resolvers;\n\ninternal class OptionalValueResolver : IServiceResolver\n{\n    public ServiceContext GetExpression(\n        IResolutionStrategy resolutionStrategy,\n        TypeInformation typeInfo,\n        ResolutionContext resolutionContext) =>\n        (typeInfo.DefaultValue?.Value ?? null).AsConstant(typeInfo.Type).AsServiceContext();\n\n    public bool CanUseForResolution(TypeInformation typeInfo, ResolutionContext resolutionContext) =>\n        typeInfo.DefaultValue != null;\n}"
  },
  {
    "path": "src/Resolution/Resolvers/ParentContainerResolver.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\n\nnamespace Stashbox.Resolution.Resolvers;\n\ninternal class ParentContainerResolver : IEnumerableSupportedResolver, ILookup\n{\n    public bool CanUseForResolution(TypeInformation typeInfo, ResolutionContext resolutionContext) =>\n        resolutionContext.CurrentContainerContext.ParentContext != null && \n        (resolutionContext.ResolutionBehavior.Has(ResolutionBehavior.Parent) || \n         typeInfo.IsDependency && resolutionContext.ResolutionBehavior.Has(ResolutionBehavior.ParentDependency));\n\n    public ServiceContext GetExpression(\n        IResolutionStrategy resolutionStrategy,\n        TypeInformation typeInfo,\n        ResolutionContext resolutionContext) =>\n        resolutionStrategy.BuildExpressionForType(resolutionContext.BeginParentContainerContext(resolutionContext\n            .CurrentContainerContext.ParentContext!), typeInfo);\n\n    public IEnumerable<ServiceContext> GetExpressionsForEnumerableRequest(\n        IResolutionStrategy resolutionStrategy,\n        TypeInformation typeInfo,\n        ResolutionContext resolutionContext) =>\n        resolutionStrategy.BuildExpressionsForEnumerableRequest(resolutionContext.BeginParentContainerContext(resolutionContext\n            .CurrentContainerContext.ParentContext!), typeInfo);\n\n    public bool CanLookupService(TypeInformation typeInfo, ResolutionContext resolutionContext)\n    {\n        if (resolutionContext.CurrentContainerContext.ParentContext == null || !this.CanUseForResolution(typeInfo, resolutionContext))\n            return false;\n\n        return resolutionContext.CurrentContainerContext.ResolutionStrategy.IsTypeResolvable(resolutionContext.BeginParentContainerContext(resolutionContext\n            .CurrentContainerContext.ParentContext), typeInfo);\n    }\n}"
  },
  {
    "path": "src/Resolution/Resolvers/ServiceProviderResolver.cs",
    "content": "﻿using System;\nusing System.Linq.Expressions;\nusing Stashbox.Utils;\n\nnamespace Stashbox.Resolution.Resolvers;\n\ninternal class ServiceProviderResolver : IServiceResolver\n{\n    public ServiceContext GetExpression(\n        IResolutionStrategy resolutionStrategy,\n        TypeInformation typeInfo,\n        ResolutionContext resolutionContext) =>\n        resolutionContext.CurrentScopeParameter.AsServiceContext();\n\n    public bool CanUseForResolution(TypeInformation typeInfo, ResolutionContext resolutionContext) =>\n        typeInfo.Type == TypeCache<IServiceProvider>.Type;\n}"
  },
  {
    "path": "src/Resolution/Resolvers/UnknownTypeResolver.cs",
    "content": "﻿using Stashbox.Registration;\nusing Stashbox.Registration.Fluent;\nusing System;\n\nnamespace Stashbox.Resolution.Resolvers;\n\ninternal class UnknownTypeResolver : IServiceResolver, ILookup\n{\n    public bool CanLookupService(TypeInformation typeInfo, ResolutionContext resolutionContext) =>\n        this.CanUseForResolution(typeInfo, resolutionContext);\n\n    public bool CanUseForResolution(TypeInformation typeInfo, ResolutionContext resolutionContext) =>\n        resolutionContext.RequestInitiatorContainerContext.ContainerConfiguration.UnknownTypeResolutionEnabled &&\n        !resolutionContext.UnknownTypeCheckDisabled &&\n        typeInfo.Type.IsResolvableType() ||\n        resolutionContext.RequestInitiatorContainerContext.ContainerConfiguration.UnknownTypeConfigurator != null;\n\n    public ServiceContext GetExpression(\n        IResolutionStrategy resolutionStrategy,\n        TypeInformation typeInfo,\n        ResolutionContext resolutionContext)\n    {\n        var name = typeInfo.DependencyName;\n        var configurator = resolutionContext.RequestInitiatorContainerContext.ContainerConfiguration.UnknownTypeConfigurator;\n\n        var unknownRegistrationConfigurator = new UnknownRegistrationConfigurator(typeInfo.Type, typeInfo.Type, name, resolutionContext.RequestInitiatorContainerContext.ContainerConfiguration.DefaultLifetime);\n        configurator?.Invoke(unknownRegistrationConfigurator);\n\n        if (unknownRegistrationConfigurator.RegistrationShouldBeSkipped)\n            return ServiceContext.Empty;\n\n        if (!unknownRegistrationConfigurator.IsFactory() && (!unknownRegistrationConfigurator.ImplementationType.IsResolvableType() ||\n            !unknownRegistrationConfigurator.ImplementationType.Implements(unknownRegistrationConfigurator.ServiceType)))\n            return ServiceContext.Empty;\n        \n        ServiceRegistrator.Register(resolutionContext.RequestInitiatorContainerContext, unknownRegistrationConfigurator, typeInfo.Type);\n\n        return resolutionStrategy.BuildExpressionForRegistration(unknownRegistrationConfigurator, \n            resolutionContext.FallBackToRequestInitiatorIfNeeded(),\n            typeInfo);\n    }\n}"
  },
  {
    "path": "src/Resolution/ServiceContext.cs",
    "content": "﻿using Stashbox.Registration;\nusing System.Linq.Expressions;\n\nnamespace Stashbox.Resolution;\n\n/// <summary>\n/// Represents the context of a service.\n/// </summary>\npublic readonly struct ServiceContext\n{\n    /// <summary>\n    /// The expression that describes the instantiation of the service.\n    /// </summary>\n    public readonly Expression ServiceExpression;\n\n    /// <summary>\n    /// The registration of the service.\n    /// </summary>\n    public readonly ServiceRegistration? ServiceRegistration;\n\n    /// <summary>\n    /// Constructs a <see cref=\"ServiceContext\"/>.\n    /// </summary>\n    /// <param name=\"serviceExpression\">The expression that describes the instantiation of the service.</param>\n    /// <param name=\"serviceRegistration\">The registration of the service.</param>\n    public ServiceContext(Expression serviceExpression, ServiceRegistration? serviceRegistration)\n    {\n        this.ServiceExpression = serviceExpression;\n        this.ServiceRegistration = serviceRegistration;\n    }\n\n    internal bool IsEmpty() => this.Equals(Empty);\n\n    private bool Equals(ServiceContext other) =>\n        ReferenceEquals(ServiceExpression, other.ServiceExpression) && ReferenceEquals(ServiceRegistration, other.ServiceRegistration);\n\n    internal static readonly ServiceContext Empty = default;\n}"
  },
  {
    "path": "src/Resolution/TypeInformation.cs",
    "content": "﻿using Stashbox.Utils;\nusing System;\nusing System.Collections.Generic;\n\nnamespace Stashbox.Resolution;\n\n/// <summary>\n/// Represents type information about a dependency.\n/// </summary>\npublic class TypeInformation\n{\n    /// <summary>\n    /// Represents a method or ctor parameter's default value.\n    /// </summary>\n    /// <param name=\"value\"></param>\n    public class DefaultValueHolder(object? value)\n    {\n        /// <summary>\n        /// The default value.\n        /// </summary>\n        public object? Value { get; } = value;\n    }\n    \n    /// <summary>\n    /// The reflected type of the dependency.\n    /// </summary>\n    public readonly Type Type;\n\n    /// <summary>\n    /// The name of the dependency.\n    /// </summary>\n    public readonly object? DependencyName;\n\n    /// <summary>\n    /// The type of the metadata.\n    /// </summary>\n    public readonly Type? MetadataType;\n\n    /// <summary>\n    /// The reflected type of the parent of the dependency.\n    /// </summary>\n    public readonly Type? ParentType;\n\n    /// <summary>\n    /// Custom attributes of the dependency.\n    /// </summary>\n    public readonly IEnumerable<Attribute>? CustomAttributes;\n\n    /// <summary>\n    /// If the dependency is a method or a constructor parameter, this property holds the parameter name, if it's a class member then the member name.\n    /// </summary>\n    public readonly string? ParameterOrMemberName;\n\n    /// <summary>\n    /// The default value of the dependency.\n    /// </summary>\n    public readonly DefaultValueHolder? DefaultValue;\n\n    /// <summary>\n    /// Indicates whether the dependency has a <see cref=\"DependencyName\"/> or similar attribute.\n    /// </summary>\n    public bool HasDependencyNameAttribute { get; set; }\n    \n    /// <summary>\n    /// The parent type's metadata.\n    /// </summary>\n    public readonly TypeInformation? Parent;\n\n    internal readonly bool IsDependency;\n\n    internal TypeInformation(Type type, object? dependencyName)\n    {\n        this.Type = type;\n        this.DependencyName = dependencyName;\n        this.ParentType = null;\n        this.MetadataType = null;\n        this.CustomAttributes = null;\n        this.ParameterOrMemberName = null;\n        this.DefaultValue = null;\n        this.Parent = null;\n        this.IsDependency = false;\n        this.HasDependencyNameAttribute = false;\n    }\n\n    internal TypeInformation(Type type, Type? parentType, TypeInformation? parent, object? dependencyName,\n        IEnumerable<Attribute>? customAttributes, string? parameterOrMemberName,\n        DefaultValueHolder? defaultValue, bool hasDependencyNameAttribute, Type? metaDataType)\n    {\n        this.Type = type;\n        this.ParentType = parentType;\n        this.DependencyName = dependencyName;\n        this.CustomAttributes = customAttributes;\n        this.ParameterOrMemberName = parameterOrMemberName;\n        this.DefaultValue = defaultValue;\n        this.MetadataType = metaDataType;\n        this.Parent = parent;\n        this.IsDependency = parentType != null; \n        this.HasDependencyNameAttribute = hasDependencyNameAttribute;\n    }\n\n    /// <summary>\n    /// Clones the type information with different type.\n    /// </summary>\n    /// <param name=\"type\">The type.</param>\n    /// <param name=\"dependencyName\">The dependency name.</param>\n    /// <param name=\"metadataType\">The metadata type.</param>\n    /// <returns>The cloned type information.</returns>\n    public TypeInformation Clone(Type type, object? dependencyName = null, Type? metadataType = null) =>\n        new(type,\n            this.ParentType,\n            this.Parent,\n            dependencyName ?? this.DependencyName,\n            this.CustomAttributes,\n            this.ParameterOrMemberName,\n            this.DefaultValue,\n            this.HasDependencyNameAttribute,\n            metadataType ?? this.MetadataType);\n\n    internal static readonly TypeInformation Empty = new(TypeCache<object>.Type, null);\n}"
  },
  {
    "path": "src/Resolution/Wrappers/EnumerableWrapper.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Linq.Expressions;\nusing Stashbox.Utils;\n\nnamespace Stashbox.Resolution.Wrappers;\n\ninternal class EnumerableWrapper : IEnumerableWrapper\n{\n    public Expression WrapExpression(TypeInformation originalTypeInformation,\n        TypeInformation wrappedTypeInformation,\n        IEnumerable<ServiceContext> serviceContexts) =>\n        wrappedTypeInformation.Type.InitNewArray(serviceContexts.Select(e => e.ServiceExpression));\n\n    public bool TryUnWrap(Type type, out Type unWrappedType)\n    {\n        var enumerableType = type.GetEnumerableType();\n        if (enumerableType == null)\n        {\n            unWrappedType = TypeCache.EmptyType;\n            return false;\n        }\n\n        unWrappedType = enumerableType;\n        return true;\n    }\n}"
  },
  {
    "path": "src/Resolution/Wrappers/FuncWrapper.cs",
    "content": "﻿using Stashbox.Utils;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Linq.Expressions;\n\nnamespace Stashbox.Resolution.Wrappers;\n\ninternal class FuncWrapper : IParameterizedWrapper\n{\n    public Expression WrapExpression(TypeInformation originalTypeInformation, TypeInformation wrappedTypeInformation,\n        ServiceContext serviceContext, IEnumerable<ParameterExpression> parameterExpressions) =>\n        serviceContext.ServiceExpression.AsLambda(originalTypeInformation.Type, parameterExpressions);\n\n    public bool TryUnWrap(Type type, out Type unWrappedType, out IEnumerable<Type> parameterTypes)\n    {\n        if (!type.IsSubclassOf(TypeCache<Delegate>.Type))\n        {\n            unWrappedType = TypeCache.EmptyType;\n            parameterTypes = TypeCache.EmptyTypes;\n            return false;\n        }\n\n        var method = type.GetMethod(\"Invoke\");\n        if (method == null || method.ReturnType == TypeCache.VoidType)\n        {\n            unWrappedType = TypeCache.EmptyType;\n            parameterTypes = TypeCache.EmptyTypes;\n            return false;\n        }\n\n        unWrappedType = method.ReturnType;\n        parameterTypes = method.GetParameters().Select(p => p.ParameterType);\n        return true;\n    }\n}"
  },
  {
    "path": "src/Resolution/Wrappers/KeyValueWrapper.cs",
    "content": "﻿using Stashbox.Utils;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq.Expressions;\n\nnamespace Stashbox.Resolution.Wrappers;\n\ninternal class KeyValueWrapper : IServiceWrapper\n{\n    private static readonly HashSet<Type> SupportedTypes =\n    [\n        typeof(KeyValuePair<,>),\n        typeof(ReadOnlyKeyValue<,>)\n    ];\n\n    private static bool IsKeyValueType(Type type) => type.IsClosedGenericType() && SupportedTypes.Contains(type.GetGenericTypeDefinition());\n\n    public Expression WrapExpression(TypeInformation originalTypeInformation, TypeInformation wrappedTypeInformation, \n        ServiceContext serviceContext)\n    {\n        var arguments = originalTypeInformation.Type.GetGenericArguments();\n        var constructor = originalTypeInformation.Type.GetConstructor(arguments)!;\n        var name = serviceContext.ServiceRegistration?.Name;\n        return constructor.MakeNew(name.AsConstant(), serviceContext.ServiceExpression);\n    }\n\n    public bool TryUnWrap(Type type, out Type unWrappedType)\n    {\n        if (!IsKeyValueType(type))\n        {\n            unWrappedType = TypeCache.EmptyType;\n            return false;\n        }\n\n        var arguments = type.GetGenericArguments();\n        var nameType = arguments[0];\n\n        if (nameType != TypeCache<object>.Type)\n        {\n            unWrappedType = TypeCache.EmptyType;\n            return false;\n        }\n\n        unWrappedType = arguments[1];\n        return true;\n    }\n}"
  },
  {
    "path": "src/Resolution/Wrappers/LazyWrapper.cs",
    "content": "﻿using Stashbox.Utils;\nusing System;\nusing System.Linq.Expressions;\n\nnamespace Stashbox.Resolution.Wrappers;\n\ninternal class LazyWrapper : IServiceWrapper\n{\n    private static bool IsLazy(Type type) => type.IsClosedGenericType() && type.GetGenericTypeDefinition() == typeof(Lazy<>);\n\n    public Expression WrapExpression(TypeInformation originalTypeInformation, TypeInformation wrappedTypeInformation,\n        ServiceContext serviceContext)\n    {\n        var ctorParamType = TypeCache.FuncType.MakeGenericType(wrappedTypeInformation.Type);\n        var lazyConstructor = originalTypeInformation.Type.GetConstructor(ctorParamType)!;\n        return lazyConstructor.MakeNew(serviceContext.ServiceExpression.AsLambda());\n    }\n\n    public bool TryUnWrap(Type type, out Type unWrappedType)\n    {\n        if (!IsLazy(type))\n        {\n            unWrappedType = TypeCache.EmptyType;\n            return false;\n        }\n\n        unWrappedType = type.GetGenericArguments()[0];\n        return true;\n    }\n}"
  },
  {
    "path": "src/Resolution/Wrappers/MetadataWrapper.cs",
    "content": "﻿using Stashbox.Registration;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq.Expressions;\nusing Stashbox.Utils;\n\nnamespace Stashbox.Resolution.Wrappers;\n\ninternal class MetadataWrapper : IMetadataWrapper\n{\n    private static readonly HashSet<Type> SupportedTypes =\n    [\n        typeof(ValueTuple<,>),\n        typeof(Tuple<,>),\n        typeof(Metadata<,>)\n    ];\n\n    private static bool IsMetadataType(Type type) => type.IsClosedGenericType() && SupportedTypes.Contains(type.GetGenericTypeDefinition());\n\n    public Expression WrapExpression(TypeInformation originalTypeInformation, TypeInformation wrappedTypeInformation, \n        ServiceContext serviceContext)\n    {\n        var arguments = originalTypeInformation.Type.GetGenericArguments();\n        var constructor = originalTypeInformation.Type.GetConstructor(arguments)!;\n        var metadata = serviceContext.ServiceRegistration?.Options.GetOrDefault(RegistrationOption.Metadata);\n        return constructor.MakeNew(serviceContext.ServiceExpression, metadata.AsConstant());\n    }\n\n    public bool TryUnWrap(Type type, out Type unWrappedType, out Type metadataType)\n    {\n        if (!IsMetadataType(type))\n        {\n            unWrappedType = TypeCache.EmptyType;\n            metadataType = TypeCache.EmptyType;\n            return false;\n        }\n\n        var arguments = type.GetGenericArguments();\n        var serviceType = arguments[0];\n        metadataType = arguments[1];\n        unWrappedType = serviceType;\n        return true;\n    }\n}"
  },
  {
    "path": "src/ResolutionScope.AsyncInitializer.cs",
    "content": "﻿using Stashbox.Utils;\nusing Stashbox.Utils.Data.Immutable;\nusing System;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace Stashbox;\n\ninternal sealed partial class ResolutionScope\n{\n    private sealed class AsyncInitializable\n    {\n        private readonly object item;\n        private readonly Func<object, IDependencyResolver, CancellationToken, Task> initializer;\n        private int initialized;\n\n        public AsyncInitializable(object item, Func<object, IDependencyResolver, CancellationToken, Task> initializer)\n        {\n            this.item = item;\n            this.initializer = initializer;\n            this.initialized = 0;\n        }\n\n        public ValueTask InvokeAsync(IDependencyResolver resolver, CancellationToken token) =>\n            Interlocked.CompareExchange(ref initialized, 1, 0) != 0\n                ? default\n                : new ValueTask(initializer(item, resolver, token));\n    }\n\n    private ImmutableLinkedList<AsyncInitializable> initializables = ImmutableLinkedList<AsyncInitializable>.Empty;\n\n    public object AddWithAsyncInitializer(object initializable, Func<object, IDependencyResolver, CancellationToken, Task> initializer)\n    {\n        this.ThrowIfDisposed();\n\n        Swap.SwapValue(ref this.initializables, (t1, t2, _, _, root) =>\n                root.Add(new AsyncInitializable(t1, t2)), initializable, initializer,\n            Constants.DelegatePlaceholder, Constants.DelegatePlaceholder);\n\n        return initializable;\n    }\n\n    /// <inheritdoc />\n    public async ValueTask InvokeAsyncInitializers(CancellationToken token = default)\n    {\n        this.ThrowIfDisposed();\n\n        if (this.ParentScope != null)\n            await this.ParentScope.InvokeAsyncInitializers(token).ConfigureAwait(false);\n\n        var initializable = this.initializables;\n        while (!ReferenceEquals(initializable, ImmutableLinkedList<AsyncInitializable>.Empty))\n        {\n            await initializable.Value.InvokeAsync(this, token).ConfigureAwait(false);\n            initializable = initializable.Next;\n        }\n    }\n}"
  },
  {
    "path": "src/ResolutionScope.Disposable.cs",
    "content": "﻿using Stashbox.Resolution;\nusing Stashbox.Utils;\nusing Stashbox.Utils.Data.Immutable;\nusing System;\nusing System.Runtime.CompilerServices;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace Stashbox;\n\ninternal partial class ResolutionScope\n{\n    private readonly struct Finalizable\n    {\n        public readonly object Item;\n        public readonly Action<object> Finalizer;\n\n        public Finalizable(object item, Action<object> finalizer)\n        {\n            this.Item = item;\n            this.Finalizer = finalizer;\n        }\n    }\n\n    private ImmutableLinkedList<object> disposables = ImmutableLinkedList<object>.Empty;\n    private ImmutableLinkedList<Finalizable> finalizables = ImmutableLinkedList<Finalizable>.Empty;\n\n    public object AddDisposableTracking(object disposable)\n    {\n        this.ThrowIfDisposed();\n\n        Swap.SwapValue(ref this.disposables, (t1, _, _, _, root) =>\n                root.Add(t1), disposable, Constants.DelegatePlaceholder,\n            Constants.DelegatePlaceholder, Constants.DelegatePlaceholder);\n\n        return disposable;\n    }\n\n    public object AddRequestContextAwareDisposableTracking(object disposable, IRequestContext requestContext)\n    {\n        this.ThrowIfDisposed();\n\n        var internalContext = (IInternalRequestContext)requestContext;\n        return internalContext.IsInstanceExcludedFromTracking(disposable) ? disposable : this.AddDisposableTracking(disposable);\n    }\n\n    public object AddWithFinalizer(object finalizable, Action<object> finalizer)\n    {\n        this.ThrowIfDisposed();\n\n        Swap.SwapValue(ref this.finalizables, (t1, t2, _, _, root) =>\n                root.Add(new Finalizable(t1, t2)), finalizable, finalizer,\n            Constants.DelegatePlaceholder, Constants.DelegatePlaceholder);\n\n        return finalizable;\n    }\n\n    public void Dispose()\n    {\n        if (Interlocked.CompareExchange(ref this.disposed, 1, 0) != 0)\n            return;\n\n        this.RemoveSelfFromParent();\n        this.DisposeChildScopes();\n        \n        this.CallFinalizers();\n        this.CallDisposes();\n    }\n\n#if HAS_ASYNC_DISPOSABLE\n        /// <inheritdoc />\n        public async ValueTask DisposeAsync()\n        {\n            if (Interlocked.CompareExchange(ref this.disposed, 1, 0) != 0)\n                return;\n\n            this.RemoveSelfFromParent();\n            await this.DisposeChildScopesAsync().ConfigureAwait(false);\n            \n            this.CallFinalizers();\n            await CallAsyncDisposes().ConfigureAwait(false);\n\n            async ValueTask CallAsyncDisposes()\n            {\n                var root = this.disposables;\n                while (!ReferenceEquals(root, ImmutableLinkedList<object>.Empty))\n                {\n                    switch (root.Value)\n                    {\n                        case IAsyncDisposable asyncDisposable:\n                            await asyncDisposable.DisposeAsync().ConfigureAwait(false);\n                            break;\n                        case IDisposable disposable:\n                            disposable.Dispose();\n                            break;\n                        default:\n                            throw new InvalidOperationException($\"Could not dispose {root.Value.GetType()} as it doesn't implement either IDisposable or IAsyncDisposable.\");\n                    }\n\n                    root = root.Next;\n                }\n            }\n        }\n        \n        private async ValueTask DisposeChildScopesAsync()\n        {\n            if (this.childScopes.IsEmpty) return;\n            \n            foreach (var childScope in this.childScopes.Walk())\n                await childScope.DisposeAsync().ConfigureAwait(false);\n        }\n#endif\n\n    private void DisposeChildScopes()\n    {\n        if (this.childScopes.IsEmpty) return;\n            \n        foreach (var childScope in this.childScopes.Walk())\n            childScope.Dispose();\n    }\n    \n    private void RemoveSelfFromParent()\n    {\n        if (this.parentScope is null || !this.attachedToParent) return;\n        \n        Swap.SwapValue(ref this.parentScope.childScopes, (t1, _, _, _, childRepo) =>\n                childRepo.Remove(t1),\n            this, Constants.DelegatePlaceholder, Constants.DelegatePlaceholder,\n            Constants.DelegatePlaceholder);\n    }\n    \n    private void CallFinalizers()\n    {\n        var rootFinalizable = this.finalizables;\n        while (!ReferenceEquals(rootFinalizable, ImmutableLinkedList<Finalizable>.Empty))\n        {\n            rootFinalizable.Value.Finalizer(rootFinalizable.Value.Item);\n            rootFinalizable = rootFinalizable.Next;\n        }\n    }\n\n    private void CallDisposes()\n    {\n        var root = this.disposables;\n        while (!ReferenceEquals(root, ImmutableLinkedList<object>.Empty) && root.Value is IDisposable disposable)\n        {\n            disposable.Dispose();\n            root = root.Next;\n        }\n    }\n\n    private void ThrowIfDisposed([CallerMemberName] string caller = \"<unknown>\")\n    {\n        if (this.disposed == 1)\n            Shield.ThrowDisposedException(this.GetType().FullName, caller);\n    }\n}"
  },
  {
    "path": "src/ResolutionScope.Resolver.cs",
    "content": "﻿using Stashbox.Exceptions;\nusing Stashbox.Expressions;\nusing Stashbox.Resolution;\nusing Stashbox.Utils;\nusing Stashbox.Utils.Data.Immutable;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Linq.Expressions;\nusing Stashbox.Utils.Data;\n\nnamespace Stashbox;\n\ninternal partial class ResolutionScope\n{\n    /// <inheritdoc />\n    public object Resolve(Type typeFrom)\n    {\n        this.ThrowIfDisposed();\n\n        var cachedFactory = this.delegateCache.ServiceDelegates.GetOrDefaultByRef(typeFrom)?\n            .GetOrDefault(Constants.DefaultResolutionBehaviorInt)?.ServiceFactory;\n        if (cachedFactory != null)\n            return cachedFactory(this, RequestContext.Empty);\n\n        return this.delegateCache.RequestContextAwareDelegates.GetOrDefaultByRef(typeFrom)?\n                   .GetOrDefault(Constants.DefaultResolutionBehaviorInt)?.ServiceFactory?.Invoke(this, RequestContext.Begin()) ??\n               this.BuildAndResolveService(typeFrom, name: null, dependencyOverrides: null, Constants.DefaultResolutionBehavior);\n    }\n    \n    /// <inheritdoc />\n    public object Resolve(Type typeFrom, object? name, object[]? dependencyOverrides, ResolutionBehavior resolutionBehavior = ResolutionBehavior.Default)\n    {\n        this.ThrowIfDisposed();\n\n        if (dependencyOverrides != null) \n            return this.BuildAndResolveService(typeFrom, name, dependencyOverrides, resolutionBehavior);\n        \n        if (name != null)\n        {\n            var resultFromCachedFactory = this.GetObjectFromCachedFactoryOrDefault<object>(typeFrom, name, resolutionBehavior);\n            return resultFromCachedFactory ?? this.BuildAndResolveService(typeFrom, name, dependencyOverrides: null, resolutionBehavior);\n        }\n\n        var cachedFactory = this.delegateCache.ServiceDelegates.GetOrDefaultByRef(typeFrom)?\n            .GetOrDefault((int)resolutionBehavior)?.ServiceFactory;\n        if (cachedFactory != null)\n            return cachedFactory(this, RequestContext.Empty);\n\n        return this.delegateCache.RequestContextAwareDelegates.GetOrDefaultByRef(typeFrom)?\n                   .GetOrDefault((int)resolutionBehavior)?.ServiceFactory?.Invoke(this, RequestContext.Begin()) ??\n               this.BuildAndResolveService(typeFrom, name: null, dependencyOverrides: null, resolutionBehavior);\n    }\n\n    /// <inheritdoc />\n    public object? ResolveOrDefault(Type typeFrom)\n    {\n        this.ThrowIfDisposed();\n\n        var cachedFactory = this.delegateCache.ServiceDelegates.GetOrDefaultByRef(typeFrom)?\n            .GetOrDefault(Constants.DefaultResolutionBehaviorInt)?.ServiceFactory;\n        if (cachedFactory != null)\n            return cachedFactory(this, RequestContext.Empty);\n\n        return this.delegateCache.RequestContextAwareDelegates.GetOrDefaultByRef(typeFrom)?\n                   .GetOrDefault(Constants.DefaultResolutionBehaviorInt)?.ServiceFactory?.Invoke(this, RequestContext.Begin()) ??\n               this.BuildAndResolveServiceOrDefault(typeFrom, name: null, dependencyOverrides: null, Constants.DefaultResolutionBehavior);\n    }\n\n    /// <inheritdoc />\n    public object? ResolveOrDefault(Type typeFrom, object? name, object[]? dependencyOverrides, ResolutionBehavior resolutionBehavior = ResolutionBehavior.Default)\n    {\n        this.ThrowIfDisposed();\n\n        if (dependencyOverrides != null)\n            return this.BuildAndResolveServiceOrDefault(typeFrom, name, dependencyOverrides, resolutionBehavior);\n        \n        if (name != null)\n        {\n            var resultFromCachedFactory = this.GetObjectFromCachedFactoryOrDefault<object>(typeFrom, name, resolutionBehavior);\n            return resultFromCachedFactory ?? this.BuildAndResolveServiceOrDefault(typeFrom, name, dependencyOverrides: null, resolutionBehavior);\n        }\n        \n        var cachedFactory = this.delegateCache.ServiceDelegates.GetOrDefaultByRef(typeFrom)?\n            .GetOrDefault((int)resolutionBehavior)?.ServiceFactory;\n        if (cachedFactory != null)\n            return cachedFactory(this, RequestContext.Empty);\n\n        return this.delegateCache.RequestContextAwareDelegates.GetOrDefaultByRef(typeFrom)?\n                   .GetOrDefault((int)resolutionBehavior)?.ServiceFactory?.Invoke(this, RequestContext.Begin()) ??\n               this.BuildAndResolveServiceOrDefault(typeFrom, name: null, dependencyOverrides: null, resolutionBehavior);\n    }\n\n    /// <inheritdoc />\n    public object? GetService(Type serviceType) => this.ResolveOrDefault(serviceType);\n\n    /// <inheritdoc />\n    public Delegate ResolveFactory(Type typeFrom, object? name = null, ResolutionBehavior resolutionBehavior = ResolutionBehavior.Default, params Type[] parameterTypes)\n    {\n        this.ThrowIfDisposed();\n\n        var key = $\"{name ?? \"\"}{string.Join(\"\", parameterTypes.Append(typeFrom).Select(t => t.FullName))}\";\n        var cachedFactory = this.delegateCache.ServiceDelegates.GetOrDefaultByRef(typeFrom)?\n            .GetOrDefault((int)resolutionBehavior)?.NamedFactories?.GetOrDefaultByValue(key);\n        if (cachedFactory != null)\n            return (Delegate)cachedFactory(this, RequestContext.Empty);\n\n        return (Delegate?)this.delegateCache.RequestContextAwareDelegates.GetOrDefaultByRef(typeFrom)?\n                   .GetOrDefault((int)resolutionBehavior)?.NamedFactories?.GetOrDefaultByValue(key)?.Invoke(this, RequestContext.Begin()) ??\n               this.BuildAndResolveFactoryDelegate(typeFrom, parameterTypes, name, key, resolutionBehavior);\n    }\n\n    /// <inheritdoc />\n    public Delegate? ResolveFactoryOrDefault(Type typeFrom, object? name = null, ResolutionBehavior resolutionBehavior = ResolutionBehavior.Default, params Type[] parameterTypes)\n    {\n        this.ThrowIfDisposed();\n\n        var key = $\"{name ?? \"\"}{string.Join(\"\", parameterTypes.Append(typeFrom).Select(t => t.FullName))}\";\n        var cachedFactory = this.delegateCache.ServiceDelegates.GetOrDefaultByRef(typeFrom)?\n            .GetOrDefault((int)resolutionBehavior)?.NamedFactories?.GetOrDefaultByValue(key);\n        if (cachedFactory != null)\n            return (Delegate)cachedFactory(this, RequestContext.Empty);\n\n        return (Delegate?)this.delegateCache.RequestContextAwareDelegates.GetOrDefaultByRef(typeFrom)?\n                   .GetOrDefault((int)resolutionBehavior)?.NamedFactories?.GetOrDefaultByValue(key)?.Invoke(this, RequestContext.Begin()) ??\n               this.BuildAndResolveFactoryDelegateOrDefault(typeFrom, parameterTypes, name, key, resolutionBehavior);\n    }\n\n    /// <inheritdoc />\n    public TTo BuildUp<TTo>(TTo instance, ResolutionBehavior resolutionBehavior = ResolutionBehavior.Default)\n        where TTo : class\n    {\n        this.ThrowIfDisposed();\n\n        var resolutionContext = ResolutionContext.BeginTopLevelContext(this.GetActiveScopeNames(),\n            this.containerContext, resolutionBehavior, this.ParentScope == null, false);\n        var expression = ExpressionFactory.ConstructBuildUpExpression(resolutionContext, instance.AsConstant(), new TypeInformation(TypeCache<TTo>.Type, null));\n        return (TTo)expression.CompileDelegate(resolutionContext, this.containerContext.ContainerConfiguration)(this,\n            resolutionContext.RequestConfiguration.RequiresRequestContext\n                ? RequestContext.Begin()\n                : RequestContext.Empty);\n    }\n\n    /// <inheritdoc />\n    public object Activate(Type type, ResolutionBehavior resolutionBehavior, params object[] arguments)\n    {\n        this.ThrowIfDisposed();\n\n        if (!type.IsResolvableType())\n            throw new ArgumentException($\"The given type ({type.FullName}) could not be activated on the fly by the container.\");\n\n        var resolutionContext = ResolutionContext.BeginTopLevelContext(this.GetActiveScopeNames(), this.containerContext, resolutionBehavior, this.ParentScope == null,\n            false, arguments, this.lateKnownInstances);\n        var expression = ExpressionFactory.ConstructExpression(resolutionContext, new TypeInformation(type, null));\n        return expression?.CompileDelegate(resolutionContext, this.containerContext.ContainerConfiguration)(this,\n            resolutionContext.RequestConfiguration.RequiresRequestContext\n                ? RequestContext.Begin()\n                : RequestContext.Empty) ?? throw ResolutionFailedException.CreateWithDesiredExceptionType(type, externalExceptionType: resolutionContext.CurrentContainerContext.ContainerConfiguration.ExternalResolutionFailedExceptionType);\n    }\n\n    /// <inheritdoc />\n    public bool CanResolve(Type typeFrom, object? name = null, ResolutionBehavior resolutionBehavior = ResolutionBehavior.Default)\n    {\n        this.ThrowIfDisposed();\n        Shield.EnsureNotNull(typeFrom, nameof(typeFrom));\n\n        return this.containerContext.ResolutionStrategy\n            .IsTypeResolvable(ResolutionContext.BeginTopLevelContext(this.GetActiveScopeNames(), this.containerContext, resolutionBehavior, false, false),\n                new TypeInformation(typeFrom, name));\n    }\n\n    /// <inheritdoc />\n    public IDependencyResolver BeginScope(object? name = null, bool attachToParent = false)\n    {\n        this.ThrowIfDisposed();\n\n        var scope = new ResolutionScope(this, this.containerContext, this.delegateCacheProvider, name, attachToParent);\n\n        if (attachToParent)\n            Swap.SwapValue(ref this.childScopes, (t1, _, _, _, childStore) =>\n                    childStore.AddOrSkip(t1),\n                scope, Constants.DelegatePlaceholder, Constants.DelegatePlaceholder, Constants.DelegatePlaceholder);\n\n        return scope;\n    }\n\n    /// <inheritdoc />\n    public void PutInstanceInScope(Type typeFrom, object instance, bool withoutDisposalTracking = false, object? name = null)\n    {\n        this.ThrowIfDisposed();\n\n        Shield.EnsureNotNull(typeFrom, nameof(typeFrom));\n        Shield.EnsureNotNull(instance, nameof(instance));\n        \n        var @override = Override.Of(typeFrom, instance, name);\n\n        Swap.SwapValue(ref this.lateKnownInstances, (t1, t2, t3, _, instances) =>\n            instances.AddOrUpdate(t1, t2, false, (o, _) => \n                o.Add(t3)), typeFrom, new ImmutableBucket<Override>([@override]), \n            @override, Constants.DelegatePlaceholder);\n\n        if (!withoutDisposalTracking && instance is IDisposable disposable)\n            this.AddDisposableTracking(disposable);\n\n        this.delegateCache = new DelegateCache();\n    }\n\n    /// <inheritdoc />\n    public IEnumerable<DelegateCacheEntry> GetDelegateCacheEntries()\n    {\n        this.ThrowIfDisposed();\n\n        return this.delegateCache.ServiceDelegates.Walk().SelectMany(d => d.Value.Walk().Select(e =>\n            new DelegateCacheEntry(d.Key, e.Value.ServiceFactory, e.Value.NamedFactories?.Walk().Select(n =>\n                new NamedCacheEntry(n.Key, n.Value)), (ResolutionBehavior)e.Key)).OrderBy(c => c.ServiceType.FullName));\n    }\n\n    private object BuildAndResolveService(Type type, object? name, object[]? dependencyOverrides, ResolutionBehavior resolutionBehavior)\n    {\n        var resolutionContext = ResolutionContext.BeginTopLevelContext(this.GetActiveScopeNames(), this.containerContext,\n            resolutionBehavior, this.ParentScope == null, nullResultAllowed: false, dependencyOverrides, this.lateKnownInstances);\n\n        var serviceContext = this.containerContext.ResolutionStrategy\n            .BuildExpressionForType(resolutionContext, new TypeInformation(type, name));\n        if (serviceContext.IsEmpty())\n            throw ResolutionFailedException.CreateWithDesiredExceptionType(type, name, externalExceptionType: resolutionContext.CurrentContainerContext.ContainerConfiguration.ExternalResolutionFailedExceptionType);\n\n        var factory = serviceContext.ServiceExpression.CompileDelegate(resolutionContext, this.containerContext.ContainerConfiguration);\n        return name != null\n            ? StoreAndInvokeNamedServiceDelegate(type, name, factory, resolutionContext, resolutionBehavior)\n            : StoreAndInvokeServiceDelegate(type, factory, resolutionContext, resolutionBehavior);\n    }\n\n    private object? BuildAndResolveServiceOrDefault(Type type, object? name, object[]? dependencyOverrides, ResolutionBehavior resolutionBehavior)\n    {\n        var resolutionContext = ResolutionContext.BeginTopLevelContext(this.GetActiveScopeNames(), this.containerContext,\n            resolutionBehavior, this.ParentScope == null, nullResultAllowed: true, dependencyOverrides, this.lateKnownInstances);\n\n        var serviceContext = this.containerContext.ResolutionStrategy.BuildExpressionForType(resolutionContext, new TypeInformation(type, name));\n        if (serviceContext.IsEmpty())\n            return null;\n\n        var factory = serviceContext.ServiceExpression.CompileDelegate(resolutionContext, this.containerContext.ContainerConfiguration);\n        return name != null \n            ? StoreAndInvokeNamedServiceDelegate(type, name, factory, resolutionContext, resolutionBehavior)\n            : StoreAndInvokeServiceDelegate(type, factory, resolutionContext, resolutionBehavior);\n    }\n\n    private Delegate BuildAndResolveFactoryDelegate(Type type, Type[] parameterTypes, object? name, string key, ResolutionBehavior resolutionBehavior)\n    {\n        var resolutionContext = ResolutionContext.BeginTopLevelContext(this.GetActiveScopeNames(), this.containerContext,\n            resolutionBehavior, this.ParentScope == null, nullResultAllowed: false, initialParameters: parameterTypes.AsParameters());\n\n        var serviceContext = this.containerContext.ResolutionStrategy\n            .BuildExpressionForType(resolutionContext, new TypeInformation(type, name));\n        if (serviceContext.IsEmpty())\n            throw ResolutionFailedException.CreateWithDesiredExceptionType(type, name, externalExceptionType: resolutionContext.CurrentContainerContext.ContainerConfiguration.ExternalResolutionFailedExceptionType);\n\n        var expression = serviceContext.ServiceExpression.AsLambda(resolutionContext.ParameterExpressions\n            .SelectMany(x => x.Select(i => i.I2)));\n\n        var factory = expression.CompileDynamicDelegate(resolutionContext, this.containerContext.ContainerConfiguration);\n        return (Delegate)StoreAndInvokeNamedServiceDelegate(type, key, factory, resolutionContext, resolutionBehavior);\n    }\n\n    private Delegate? BuildAndResolveFactoryDelegateOrDefault(Type type, Type[] parameterTypes, object? name, string key, ResolutionBehavior resolutionBehavior)\n    {\n        var resolutionContext = ResolutionContext.BeginTopLevelContext(this.GetActiveScopeNames(), this.containerContext,\n            resolutionBehavior, this.ParentScope == null, nullResultAllowed: true, initialParameters: parameterTypes.AsParameters());\n\n        var serviceContext = this.containerContext.ResolutionStrategy\n            .BuildExpressionForType(resolutionContext, new TypeInformation(type, name));\n        if (serviceContext.IsEmpty())\n            return null;\n\n        var expression = serviceContext.ServiceExpression.AsLambda(resolutionContext.ParameterExpressions\n            .SelectMany(x => x.Select(i => i.I2)));\n\n        var factory = expression.CompileDynamicDelegate(resolutionContext, this.containerContext.ContainerConfiguration);\n        return (Delegate)StoreAndInvokeNamedServiceDelegate(type, key, factory, resolutionContext, resolutionBehavior);\n    }\n\n    private object StoreAndInvokeServiceDelegate(Type serviceType,\n        Func<IResolutionScope, IRequestContext, object> factory,\n        ResolutionContext resolutionContext, ResolutionBehavior resolutionBehavior)\n    {\n        if (resolutionContext.RequestConfiguration.FactoryDelegateCacheEnabled)\n        {\n            \n            Swap.SwapValue(ref resolutionContext.RequestConfiguration.RequiresRequestContext\n                    ? ref this.delegateCache.RequestContextAwareDelegates\n                    : ref this.delegateCache.ServiceDelegates, (t1, t2, t3, _, c) =>\n                {\n                    var newEntry = new CacheEntry(t2, null);\n                    var tree = ImmutableTree<CacheEntry>.Empty.AddOrUpdate((int)t3, newEntry);\n                    return c.AddOrUpdate(t1, tree, true,\n                        (old, _) => old.AddOrUpdate((int)t3, newEntry, (oldEntry, _) => new CacheEntry(t2, oldEntry.NamedFactories)));\n                },\n            serviceType, factory, resolutionBehavior, Constants.DelegatePlaceholder);\n        }\n\n        return factory(this, resolutionContext.RequestConfiguration.RequiresRequestContext\n            ? resolutionContext.RequestContext\n            : RequestContext.Empty);\n    }\n\n    private object StoreAndInvokeNamedServiceDelegate(Type serviceType, object key, Func<IResolutionScope, IRequestContext, object> factory,\n        ResolutionContext resolutionContext, ResolutionBehavior resolutionBehavior)\n    {\n        if (resolutionContext.RequestConfiguration.FactoryDelegateCacheEnabled)\n            Swap.SwapValue(ref resolutionContext.RequestConfiguration.RequiresRequestContext\n                ? ref this.delegateCache.RequestContextAwareDelegates\n                : ref this.delegateCache.ServiceDelegates, (t1, t2, t3, t4, c) =>\n            {\n                var newEntry = new CacheEntry(null, ImmutableTree<object, Func<IResolutionScope, IRequestContext, object>>.Empty.AddOrUpdate(t2, t3, false));\n                var tree = ImmutableTree<CacheEntry>.Empty.AddOrUpdate((int)t4, newEntry);\n                return c.AddOrUpdate(t1, tree, true, (old, _) => old.AddOrUpdate((int)t4, newEntry, (oldEntry, _) => oldEntry.NamedFactories != null\n                    ? new CacheEntry(oldEntry.ServiceFactory, oldEntry.NamedFactories.AddOrUpdate(t2, t3, false))\n                    : new CacheEntry(oldEntry.ServiceFactory,\n                        ImmutableTree<object, Func<IResolutionScope, IRequestContext, object>>.Empty.AddOrUpdate(t2,\n                            t3, false))));\n            }, serviceType, key, factory, resolutionBehavior);\n\n        return factory(this, resolutionContext.RequestConfiguration.RequiresRequestContext\n            ? resolutionContext.RequestContext\n            : RequestContext.Empty);\n    }\n\n    private T? GetObjectFromCachedFactoryOrDefault<T>(Type type, object? name, ResolutionBehavior resolutionBehavior)\n    {\n        var cachedFactory = name == null\n            ? this.delegateCache.ServiceDelegates.GetOrDefaultByRef(type)?.GetOrDefault((int)resolutionBehavior)?.ServiceFactory\n            : this.delegateCache.ServiceDelegates.GetOrDefaultByRef(type)?.GetOrDefault((int)resolutionBehavior)?.NamedFactories?.GetOrDefaultByValue(name);\n\n        if (cachedFactory != null)\n            return (T?)cachedFactory(this, RequestContext.Empty);\n\n        var requestContextAwareFactory = name == null\n            ? this.delegateCache.RequestContextAwareDelegates.GetOrDefaultByRef(type)?.GetOrDefault((int)resolutionBehavior)?.ServiceFactory\n            : this.delegateCache.RequestContextAwareDelegates.GetOrDefaultByRef(type)?.GetOrDefault((int)resolutionBehavior)?.NamedFactories?.GetOrDefaultByValue(name);\n\n        return (T?)requestContextAwareFactory?.Invoke(this, RequestContext.Begin());\n    }\n}"
  },
  {
    "path": "src/ResolutionScope.cs",
    "content": "﻿using Stashbox.Exceptions;\nusing Stashbox.Resolution;\nusing Stashbox.Utils;\nusing Stashbox.Utils.Data.Immutable;\nusing System;\nusing System.Collections.Generic;\nusing System.Runtime.CompilerServices;\nusing System.Runtime.ExceptionServices;\nusing System.Threading;\n\nnamespace Stashbox;\n\ninternal sealed partial class ResolutionScope : IResolutionScope\n{\n    private sealed class ScopedEvaluator\n    {\n        private const int MaxWaitTimeInMs = 3000;\n        private static readonly object Default = new();\n        private int constructingThreadId = -1;\n        private object evaluatedObject = Default;\n\n        public object Evaluate(IResolutionScope scope, IRequestContext requestContext, Func<IResolutionScope, IRequestContext, object> factory, Type serviceType)\n        {\n            var evaluated = Volatile.Read(ref this.evaluatedObject);\n            if (!ReferenceEquals(evaluated, Default))\n                return GetEvaluatedObjectOrThrow(evaluated);\n\n            return Interlocked.CompareExchange(ref this.constructingThreadId, Environment.CurrentManagedThreadId, -1) != -1 \n                ? this.WaitForEvaluation(serviceType) \n                : this.EvaluateFactory(scope, requestContext, factory);\n        }\n\n        private object WaitForEvaluation(Type serviceType)\n        {\n            if (Volatile.Read(ref this.constructingThreadId) == Environment.CurrentManagedThreadId)\n                throw new ResolutionFailedException(serviceType,  \n                    message: $\"Circular dependency was detected while resolving '{serviceType}'. \" +\n                             $\"The same scoped/singleton service was requested again before its construction completed. \" +\n                             $\"This service is configured to allow only one instance per scope.\");\n            \n            SpinWait spin = default;\n            var startTime = (uint)Environment.TickCount;\n            object evaluated;\n            while (ReferenceEquals(evaluated = Volatile.Read(ref this.evaluatedObject), Default))\n            {\n                if (spin.NextSpinWillYield)\n                {\n                    var currentTime = (uint)Environment.TickCount;\n                    if (MaxWaitTimeInMs <= currentTime - startTime)\n                        throw new ResolutionFailedException(serviceType,\n                            message: $\"The construction of '{serviceType}' did not complete within the expected time. \" +\n                                     $\"It's possible that the factory is blocked, deadlocked, or waiting on another resolution.\");\n                }\n\n                spin.SpinOnce();\n            }\n\n            return GetEvaluatedObjectOrThrow(evaluated);\n        }\n        \n        private static object GetEvaluatedObjectOrThrow(object evaluated)\n        {\n            if (evaluated is FailedEvaluation failedEvaluation)\n                failedEvaluation.ExceptionDispatchInfo.Throw();\n\n            return evaluated;\n        }\n        \n        [MethodImpl(MethodImplOptions.NoInlining)]\n        private object EvaluateFactory(IResolutionScope scope, IRequestContext requestContext, Func<IResolutionScope, IRequestContext, object> factory)\n        {\n            try\n            {\n                var evaluated = factory(scope, requestContext);\n                Volatile.Write(ref this.evaluatedObject, evaluated);\n                return evaluated;\n            }\n            catch (Exception ex)\n            {\n                Volatile.Write(ref this.evaluatedObject, new FailedEvaluation(ex));\n                throw;\n            }\n        }\n        \n        private sealed class FailedEvaluation(Exception exception)\n        {\n            internal readonly ExceptionDispatchInfo ExceptionDispatchInfo = ExceptionDispatchInfo.Capture(exception);\n        }\n    }\n    \n    private int disposed;\n    private readonly bool attachedToParent;\n    private readonly IContainerContext containerContext;\n    private readonly DelegateCacheProvider delegateCacheProvider;\n    private readonly ResolutionScope? parentScope;\n    private ImmutableTree<ScopedEvaluator> scopedInstances = ImmutableTree<ScopedEvaluator>.Empty;\n    private ImmutableTree<Type, ImmutableBucket<Override>> lateKnownInstances = ImmutableTree<Type, ImmutableBucket<Override>>.Empty;\n    private ImmutableRefTree<IResolutionScope> childScopes = ImmutableRefTree<IResolutionScope>.Empty;\n\n\n    private DelegateCache delegateCache;\n\n    public object? Name { get; }\n\n    public IResolutionScope? ParentScope => this.parentScope;\n\n    public ResolutionScope(IContainerContext containerContext)\n    {\n        this.containerContext = containerContext;\n        this.delegateCacheProvider = new DelegateCacheProvider();\n        this.delegateCache = new DelegateCache();\n    }\n\n    private ResolutionScope(ResolutionScope parent, IContainerContext containerContext, DelegateCacheProvider delegateCacheProvider, object? name, bool attachedToParent)\n    {\n        this.containerContext = containerContext;\n        this.delegateCacheProvider = delegateCacheProvider;\n        this.parentScope = parent;\n        this.Name = name;\n        this.attachedToParent = attachedToParent;\n        this.delegateCache = name == null\n            ? delegateCacheProvider.DefaultCache\n            : delegateCacheProvider.GetNamedCache(name);\n    }\n\n    public object GetOrAddScopedObject(int key, Func<IResolutionScope, IRequestContext, object> factory,\n        IRequestContext requestContext, Type serviceType)\n    {\n        var item = this.scopedInstances.GetOrDefault(key);\n        if (item != null) return item.Evaluate(this, requestContext, factory, serviceType);\n\n        var evaluator = new ScopedEvaluator();\n        return Swap.SwapValue(ref this.scopedInstances, (t1, t2, _, _, items) =>\n            items.AddOrUpdate(t1, t2), key, evaluator, Constants.DelegatePlaceholder, Constants.DelegatePlaceholder)\n            ? evaluator.Evaluate(this, requestContext, factory, serviceType)\n            : this.scopedInstances.GetOrDefault(key)!.Evaluate(this, requestContext, factory, serviceType);\n    }\n\n    public void InvalidateDelegateCache()\n    {\n        this.ThrowIfDisposed();\n\n        this.delegateCacheProvider.DefaultCache.ServiceDelegates = this.delegateCache.ServiceDelegates =\n            ImmutableTree<Type, ImmutableTree<CacheEntry>>.Empty;\n        this.delegateCacheProvider.DefaultCache.RequestContextAwareDelegates = this.delegateCache.RequestContextAwareDelegates =\n            ImmutableTree<Type, ImmutableTree<CacheEntry>>.Empty;\n        this.delegateCacheProvider.NamedCache = ImmutableTree<object, DelegateCache>.Empty;\n    }\n\n    public IEnumerable<object> GetActiveScopeNames()\n    {\n        this.ThrowIfDisposed();\n\n        IResolutionScope? current = this;\n        while (current != null)\n        {\n            if (current.Name != null)\n                yield return current.Name;\n\n            current = current.ParentScope;\n        }\n    }\n}"
  },
  {
    "path": "src/StashboxContainer.CollectionRegistrator.cs",
    "content": "﻿using Stashbox.Registration.Fluent;\nusing Stashbox.Utils;\nusing System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Linq;\n\nnamespace Stashbox;\n\npublic partial class StashboxContainer\n{\n    /// <inheritdoc />\n    public IStashboxContainer RegisterTypesAs(Type typeFrom,\n        IEnumerable<Type> types,\n        Func<Type, bool>? selector = null,\n        Action<RegistrationConfigurator>? configurator = null)\n    {\n        Shield.EnsureNotNull(typeFrom, nameof(typeFrom));\n        Shield.EnsureNotNull(types, nameof(types));\n\n        types = selector != null ? types.Where(selector).Where(t => t.IsResolvableType()) : types.Where(t => t.IsResolvableType());\n\n        foreach (var type in types)\n        {\n            if (type.ImplementsWithoutGenericCheck(typeFrom))\n            {\n                this.RegisterTypeAs(typeFrom, type, configurator);\n                continue;\n            }\n\n            if (!typeFrom.IsGenericTypeDefinition) continue;\n\n            var serviceTypes = type.GetRegisterableBaseTypes().Concat(type.GetRegisterableInterfaceTypes())\n                .Where(t => t.IsGenericType && t.GetGenericTypeDefinition() == typeFrom);\n\n            foreach (var service in serviceTypes)\n                this.RegisterTypeAs(type.IsGenericTypeDefinition ? typeFrom : service, type, configurator);\n        }\n\n        return this;\n    }\n\n    /// <inheritdoc />\n    public IStashboxContainer RegisterTypes(IEnumerable<Type> types,\n        Func<Type, bool>? selector = null,\n        Func<Type, Type, bool>? serviceTypeSelector = null,\n        bool registerSelf = true,\n        Action<RegistrationConfigurator>? configurator = null)\n    {\n        Shield.EnsureNotNull(types, nameof(types));\n\n        types = selector != null\n            ? types.Where(t => t.IsResolvableType()).Where(selector)\n            : types.Where(t => t.IsResolvableType());\n\n        foreach (var type in types)\n        {\n            var serviceTypes = type.GetRegisterableBaseTypes().Concat(type.GetRegisterableInterfaceTypes());\n\n            if (serviceTypeSelector != null)\n                serviceTypes = serviceTypes.Where(t => serviceTypeSelector(type, t));\n\n            if (type.IsGenericTypeDefinition)\n                serviceTypes = serviceTypes.Where(t =>\n                {\n                    if (!t.IsGenericType) return false;\n                    return type.GetGenericArguments().Length == t.GetGenericArguments().Length;\n                }).Select(t => t.GetGenericTypeDefinition());\n\n            var finalServiceTypes = serviceTypes.ToArray();\n\n            var serviceType = finalServiceTypes.Length > 0 ? finalServiceTypes[0] : type;\n            if (finalServiceTypes.Length == 0 && !registerSelf)\n                continue;\n\n            var configuration = new RegistrationConfigurator(serviceType, type,\n                this.containerConfigurator.ContainerConfiguration.DefaultLifetime);\n\n            for (var i = 1; i < finalServiceTypes.Length; i++)\n            {\n                configuration.AsServiceAlso(finalServiceTypes[i]);\n            }\n\n            if (registerSelf)\n                configuration.AsServiceAlso(type);\n            \n            configurator?.Invoke(configuration);\n\n            this.RegisterInternal(configuration.ServiceType, configuration);\n        }\n\n        return this;\n    }\n\n    /// <inheritdoc />\n    public IStashboxContainer ComposeBy(Type compositionRootType, params object[] compositionRootArguments)\n    {\n        this.ThrowIfDisposed();\n        Shield.EnsureNotNull(compositionRootType, nameof(compositionRootType));\n        Shield.EnsureTrue(compositionRootType.IsCompositionRoot(), $\"The given type {compositionRootType} doesn't implement ICompositionRoot.\");\n\n        var compositionRoot = (ICompositionRoot)this.Activate(compositionRootType, compositionRootArguments);\n        compositionRoot.Compose(this);\n\n        return this;\n    }\n\n    /// <inheritdoc />\n    public IStashboxContainer ComposeBy(ICompositionRoot compositionRoot)\n    {\n        this.ThrowIfDisposed();\n        Shield.EnsureNotNull(compositionRoot, nameof(compositionRoot));\n\n        compositionRoot.Compose(this);\n        return this;\n    }\n\n    private void RegisterTypeAs(Type typeFrom, Type type, Action<RegistrationConfigurator>? configurator)\n    {\n        _ = configurator switch\n        {\n            null => this.Register(typeFrom, type),\n            _ => this.Register(typeFrom, type, configurator)\n        };\n    }\n}"
  },
  {
    "path": "src/StashboxContainer.FuncRegistrator.cs",
    "content": "﻿using Stashbox.Registration;\nusing System;\nusing System.Collections.Generic;\nusing Stashbox.Utils;\n\nnamespace Stashbox;\n\npublic partial class StashboxContainer\n{\n    /// <inheritdoc />\n    public IStashboxContainer RegisterFunc<TService>(Func<IDependencyResolver, TService> factory, object? name = null) =>\n        this.RegisterFuncInternal(factory, TypeCache<Func<TService>>.Type, name);\n\n    /// <inheritdoc />\n    public IStashboxContainer RegisterFunc<T1, TService>(Func<T1, IDependencyResolver, TService> factory, object? name = null) =>\n        this.RegisterFuncInternal(factory, TypeCache<Func<T1, TService>>.Type, name);\n\n    /// <inheritdoc />\n    public IStashboxContainer RegisterFunc<T1, T2, TService>(Func<T1, T2, IDependencyResolver, TService> factory, object? name = null) =>\n        this.RegisterFuncInternal(factory, TypeCache<Func<T1, T2, TService>>.Type, name);\n\n    /// <inheritdoc />\n    public IStashboxContainer RegisterFunc<T1, T2, T3, TService>(Func<T1, T2, T3, IDependencyResolver, TService> factory, object? name = null) =>\n        this.RegisterFuncInternal(factory, TypeCache<Func<T1, T2, T3, TService>>.Type, name);\n\n    /// <inheritdoc />\n    public IStashboxContainer RegisterFunc<T1, T2, T3, T4, TService>(Func<T1, T2, T3, T4, IDependencyResolver, TService> factory, object? name = null) =>\n        this.RegisterFuncInternal(factory, TypeCache<Func<T1, T2, T3, T4, TService>>.Type, name);\n\n    private IStashboxContainer RegisterFuncInternal(Delegate factory, Type factoryType, object? name)\n    {\n        this.ThrowIfDisposed();\n\n        var registration = new ServiceRegistration(factoryType, name, this.ContainerContext.ContainerConfiguration.DefaultLifetime, false, new Dictionary<RegistrationOption, object?>\n        {\n            { RegistrationOption.RegistrationTypeOptions, factory }\n        });\n        this.ContainerContext.RegistrationRepository.AddOrUpdateRegistration(registration, factoryType);\n        return this;\n    }\n}"
  },
  {
    "path": "src/StashboxContainer.ReMapper.cs",
    "content": "﻿using Stashbox.Registration;\nusing Stashbox.Registration.Fluent;\nusing System;\nusing Stashbox.Utils;\n\nnamespace Stashbox;\n\npublic partial class StashboxContainer\n{\n    /// <inheritdoc />\n    public IStashboxContainer ReMap<TFrom, TTo>(Action<RegistrationConfigurator<TFrom, TTo>>? configurator = null)\n        where TFrom : class\n        where TTo : class, TFrom\n    {\n        this.ThrowIfDisposed();\n        var typeFrom = TypeCache<TFrom>.Type;\n        var registrationConfigurator = new RegistrationConfigurator<TFrom, TTo>(typeFrom, TypeCache<TTo>.Type, this.containerConfigurator.ContainerConfiguration.DefaultLifetime);\n        configurator?.Invoke(registrationConfigurator);\n        return this.ReMapInternal(typeFrom, registrationConfigurator);\n    }\n\n    /// <inheritdoc />\n    public IStashboxContainer ReMap<TFrom>(Type typeTo, Action<RegistrationConfigurator<TFrom, TFrom>>? configurator = null)\n        where TFrom : class\n    {\n        this.ThrowIfDisposed();\n\n        var typeFrom = TypeCache<TFrom>.Type;\n        var registrationConfigurator = new RegistrationConfigurator<TFrom, TFrom>(TypeCache<TFrom>.Type, typeTo, this.containerConfigurator.ContainerConfiguration.DefaultLifetime);\n        configurator?.Invoke(registrationConfigurator);\n\n        registrationConfigurator.ValidateTypeMap();\n\n        return this.ReMapInternal(typeFrom, registrationConfigurator);\n    }\n\n    /// <inheritdoc />\n    public IStashboxContainer ReMap(Type typeFrom, Type typeTo, Action<RegistrationConfigurator>? configurator = null)\n    {\n        this.ThrowIfDisposed();\n\n        var registrationConfigurator = new RegistrationConfigurator(typeFrom, typeTo, this.containerConfigurator.ContainerConfiguration.DefaultLifetime);\n        configurator?.Invoke(registrationConfigurator);\n\n        registrationConfigurator.ValidateTypeMap();\n\n        return this.ReMapInternal(typeFrom, registrationConfigurator);\n    }\n\n    /// <inheritdoc />\n    public IStashboxContainer ReMap<TTo>(Action<RegistrationConfigurator<TTo, TTo>>? configurator = null)\n        where TTo : class\n    {\n        this.ThrowIfDisposed();\n        var type = TypeCache<TTo>.Type;\n        var registrationConfigurator = new RegistrationConfigurator<TTo, TTo>(type, type, this.containerConfigurator.ContainerConfiguration.DefaultLifetime);\n        configurator?.Invoke(registrationConfigurator);\n\n        registrationConfigurator.ValidateImplementationIsResolvable();\n\n        return this.ReMapInternal(type, registrationConfigurator);\n    }\n\n    /// <inheritdoc />\n    public IStashboxContainer ReMapDecorator(Type typeFrom, Type typeTo, Action<DecoratorConfigurator>? configurator = null)\n    {\n        this.ThrowIfDisposed();\n\n        var decoratorConfigurator = new DecoratorConfigurator(typeFrom, typeTo);\n        configurator?.Invoke(decoratorConfigurator);\n\n        decoratorConfigurator.ValidateTypeMap();\n\n        return this.ReMapInternal(typeFrom, decoratorConfigurator);\n    }\n\n    /// <inheritdoc />\n    public IStashboxContainer ReMapDecorator<TFrom, TTo>(Action<DecoratorConfigurator<TFrom, TTo>>? configurator = null)\n        where TFrom : class\n        where TTo : class, TFrom\n    {\n        this.ThrowIfDisposed();\n        var typeFrom = TypeCache<TFrom>.Type;\n        var decoratorConfigurator = new DecoratorConfigurator<TFrom, TTo>(typeFrom, TypeCache<TTo>.Type);\n        configurator?.Invoke(decoratorConfigurator);\n        return this.ReMapInternal(typeFrom, decoratorConfigurator);\n    }\n\n    /// <inheritdoc />\n    public IStashboxContainer ReMapDecorator<TFrom>(Type typeTo, Action<DecoratorConfigurator<TFrom, TFrom>>? configurator = null)\n        where TFrom : class\n    {\n        this.ThrowIfDisposed();\n\n        var typeFrom = TypeCache<TFrom>.Type;\n        var decoratorConfigurator = new DecoratorConfigurator<TFrom, TFrom>(typeFrom, typeTo);\n        configurator?.Invoke(decoratorConfigurator);\n\n        decoratorConfigurator.ValidateTypeMap();\n\n        return this.ReMapInternal(typeFrom, decoratorConfigurator);\n    }\n\n    private IStashboxContainer ReMapInternal(Type serviceType, ServiceRegistration serviceRegistration)\n    {\n        ServiceRegistrator.ReMap(\n            this.ContainerContext,\n            serviceRegistration,\n            serviceType);\n\n        return this;\n    }\n}"
  },
  {
    "path": "src/StashboxContainer.Registrator.cs",
    "content": "﻿using Stashbox.Lifetime;\nusing Stashbox.Registration;\nusing Stashbox.Registration.Fluent;\nusing Stashbox.Utils;\nusing System;\nusing System.Collections.Generic;\n\nnamespace Stashbox;\n\npublic partial class StashboxContainer\n{\n    /// <inheritdoc />\n    public IStashboxContainer Register<TFrom, TTo>(Action<RegistrationConfigurator<TFrom, TTo>> configurator)\n        where TFrom : class\n        where TTo : class, TFrom\n    {\n        this.ThrowIfDisposed();\n\n        var typeFrom = TypeCache<TFrom>.Type;\n        var typeTo = TypeCache<TTo>.Type;\n        var registrationConfigurator = new RegistrationConfigurator<TFrom, TTo>(typeFrom, typeTo, this.containerConfigurator.ContainerConfiguration.DefaultLifetime);\n        configurator(registrationConfigurator);\n        return this.RegisterInternal(typeFrom, registrationConfigurator);\n    }\n\n    /// <inheritdoc />\n    public IStashboxContainer Register<TFrom, TTo>(object? name = null)\n        where TFrom : class\n        where TTo : class, TFrom\n    {\n        this.ThrowIfDisposed();\n\n        return this.RegisterInternal(TypeCache<TFrom>.Type, TypeCache<TTo>.Type, name);\n    }\n\n    /// <inheritdoc />\n    public IStashboxContainer Register<TFrom>(Type typeTo, Action<RegistrationConfigurator<TFrom, TFrom>>? configurator = null)\n        where TFrom : class\n    {\n        this.ThrowIfDisposed();\n        Shield.EnsureNotNull(typeTo, nameof(typeTo));\n\n        var typeFrom = TypeCache<TFrom>.Type;\n\n        if (configurator == null)\n        {\n            Shield.EnsureTypeMapIsValid(typeFrom, typeTo);\n            return this.RegisterInternal(typeFrom, typeTo);\n        }\n\n        var registrationConfigurator = new RegistrationConfigurator<TFrom, TFrom>(typeFrom, typeTo, this.containerConfigurator.ContainerConfiguration.DefaultLifetime);\n        configurator(registrationConfigurator);\n\n        registrationConfigurator.ValidateTypeMap();\n        return this.RegisterInternal(typeFrom, registrationConfigurator);\n    }\n\n    /// <inheritdoc />\n    public IStashboxContainer Register(Type typeFrom, Type typeTo, Action<RegistrationConfigurator>? configurator = null)\n    {\n        this.ThrowIfDisposed();\n        Shield.EnsureNotNull(typeFrom, nameof(typeFrom));\n        Shield.EnsureNotNull(typeTo, nameof(typeTo));\n\n        if (configurator == null)\n        {\n            Shield.EnsureTypeMapIsValid(typeFrom, typeTo);\n            return this.RegisterInternal(typeFrom, typeTo);\n        }\n\n        var registrationConfigurator = new RegistrationConfigurator(typeFrom, typeTo, this.containerConfigurator.ContainerConfiguration.DefaultLifetime);\n        configurator(registrationConfigurator);\n\n        registrationConfigurator.ValidateTypeMap();\n        return this.RegisterInternal(typeFrom, registrationConfigurator);\n    }\n\n    /// <inheritdoc />\n    public IStashboxContainer Register<TTo>(Action<RegistrationConfigurator<TTo, TTo>> configurator)\n        where TTo : class\n    {\n        this.ThrowIfDisposed();\n        var type = TypeCache<TTo>.Type;\n\n        var registrationConfigurator = new RegistrationConfigurator<TTo, TTo>(type, type, this.containerConfigurator.ContainerConfiguration.DefaultLifetime);\n        configurator(registrationConfigurator);\n\n        registrationConfigurator.ValidateImplementationIsResolvable();\n        return this.RegisterInternal(type, registrationConfigurator);\n    }\n\n    /// <inheritdoc />\n    public IStashboxContainer Register<TTo>(object? name = null)\n        where TTo : class\n    {\n        this.ThrowIfDisposed();\n\n        var type = TypeCache<TTo>.Type;\n        Shield.EnsureIsResolvable(type);\n\n        return this.RegisterInternal(type, type, name);\n    }\n\n    /// <inheritdoc />\n    public IStashboxContainer Register(Type typeTo, Action<RegistrationConfigurator>? configurator = null)\n    {\n        this.ThrowIfDisposed();\n        Shield.EnsureNotNull(typeTo, nameof(typeTo));\n\n        if (configurator == null)\n        {\n            Shield.EnsureIsResolvable(typeTo);\n            return this.RegisterInternal(typeTo, typeTo);\n        }\n\n        var registrationConfigurator = new RegistrationConfigurator(typeTo, typeTo, this.containerConfigurator.ContainerConfiguration.DefaultLifetime);\n        configurator(registrationConfigurator);\n\n        registrationConfigurator.ValidateImplementationIsResolvable();\n\n        return this.RegisterInternal(typeTo, registrationConfigurator);\n    }\n\n    /// <inheritdoc />\n    public IStashboxContainer RegisterSingleton<TFrom, TTo>(object? name = null)\n        where TFrom : class\n        where TTo : class, TFrom\n    {\n        this.ThrowIfDisposed();\n\n        return this.RegisterInternal(TypeCache<TFrom>.Type, TypeCache<TTo>.Type, name, lifetime: Lifetimes.Singleton);\n    }\n\n    /// <inheritdoc />\n    public IStashboxContainer RegisterSingleton<TTo>(object? name = null)\n        where TTo : class\n    {\n        this.ThrowIfDisposed();\n\n        var type = TypeCache<TTo>.Type;\n        Shield.EnsureIsResolvable(type);\n\n        return this.RegisterInternal(type, type, name, lifetime: Lifetimes.Singleton);\n    }\n\n    /// <inheritdoc />\n    public IStashboxContainer RegisterSingleton(Type typeFrom, Type typeTo, object? name = null)\n    {\n        this.ThrowIfDisposed();\n        Shield.EnsureNotNull(typeFrom, nameof(typeFrom));\n        Shield.EnsureNotNull(typeTo, nameof(typeTo));\n        Shield.EnsureTypeMapIsValid(typeFrom, typeTo);\n\n        return this.RegisterInternal(typeFrom, typeTo, name, lifetime: Lifetimes.Singleton);\n    }\n\n    /// <inheritdoc />\n    public IStashboxContainer RegisterScoped<TFrom, TTo>(object? name = null)\n        where TFrom : class\n        where TTo : class, TFrom\n    {\n        this.ThrowIfDisposed();\n\n        return this.RegisterInternal(TypeCache<TFrom>.Type, TypeCache<TTo>.Type, name, lifetime: Lifetimes.Scoped);\n    }\n\n    /// <inheritdoc />\n    public IStashboxContainer RegisterScoped(Type typeFrom, Type typeTo, object? name = null)\n    {\n        this.ThrowIfDisposed();\n        Shield.EnsureNotNull(typeFrom, nameof(typeFrom));\n        Shield.EnsureNotNull(typeTo, nameof(typeTo));\n        Shield.EnsureTypeMapIsValid(typeFrom, typeTo);\n\n        return this.RegisterInternal(typeFrom, typeTo, name, lifetime: Lifetimes.Scoped);\n    }\n\n    /// <inheritdoc />\n    public IStashboxContainer RegisterScoped<TTo>(object? name = null)\n        where TTo : class\n    {\n        this.ThrowIfDisposed();\n\n        var type = TypeCache<TTo>.Type;\n        Shield.EnsureIsResolvable(type);\n\n        return this.RegisterInternal(type, type, name, lifetime: Lifetimes.Scoped);\n    }\n\n    /// <inheritdoc />\n    public IStashboxContainer RegisterInstance<TInstance>(TInstance instance, object? name = null, bool withoutDisposalTracking = false,\n        Action<TInstance>? finalizerDelegate = null) where TInstance : class\n    {\n        this.ThrowIfDisposed();\n        Shield.EnsureNotNull(instance, nameof(instance));\n\n        return this.RegisterInstanceInternal(TypeCache<TInstance>.Type, instance.GetType(), instance, false, withoutDisposalTracking, name, finalizerDelegate != null\n            ? o => finalizerDelegate((TInstance)o)\n            : null);\n    }\n\n    /// <inheritdoc />\n    public IStashboxContainer RegisterInstance(object instance, Type serviceType, object? name = null, bool withoutDisposalTracking = false)\n    {\n        this.ThrowIfDisposed();\n        Shield.EnsureNotNull(instance, nameof(instance));\n        Shield.EnsureNotNull(serviceType, nameof(serviceType));\n\n        return this.RegisterInstanceInternal(serviceType, instance.GetType(), instance, false, withoutDisposalTracking, name);\n    }\n\n    /// <inheritdoc />\n    public IStashboxContainer WireUp<TInstance>(TInstance instance, object? name = null, bool withoutDisposalTracking = false,\n        Action<TInstance>? finalizerDelegate = null) where TInstance : class\n    {\n        this.ThrowIfDisposed();\n        Shield.EnsureNotNull(instance, nameof(instance));\n\n        return this.RegisterInstanceInternal(TypeCache<TInstance>.Type, instance.GetType(), instance, true, withoutDisposalTracking, name, finalizerDelegate != null\n            ? o => finalizerDelegate((TInstance)o)\n            : null);\n    }\n\n    /// <inheritdoc />\n    public IStashboxContainer WireUp(object instance, Type serviceType, object? name = null, bool withoutDisposalTracking = false)\n    {\n        this.ThrowIfDisposed();\n        Shield.EnsureNotNull(instance, nameof(instance));\n        Shield.EnsureNotNull(serviceType, nameof(serviceType));\n\n        return this.RegisterInstanceInternal(serviceType, instance.GetType(), instance, true, withoutDisposalTracking, name);\n    }\n\n    /// <inheritdoc />\n    public IStashboxContainer RegisterDecorator(Type typeFrom, Type typeTo, Action<DecoratorConfigurator>? configurator = null)\n    {\n        this.ThrowIfDisposed();\n        Shield.EnsureNotNull(typeFrom, nameof(typeFrom));\n        Shield.EnsureNotNull(typeTo, nameof(typeTo));\n\n        if (configurator == null)\n        {\n            Shield.EnsureTypeMapIsValid(typeFrom, typeTo);\n            return this.RegisterInternal(typeFrom, typeTo, lifetime: Lifetimes.Empty, isDecorator: true);\n        }\n\n        var decoratorConfigurator = new DecoratorConfigurator(typeFrom, typeTo);\n        configurator(decoratorConfigurator);\n\n        decoratorConfigurator.ValidateTypeMap();\n\n        return this.RegisterInternal(typeFrom, decoratorConfigurator);\n    }\n\n    /// <inheritdoc />\n    public IStashboxContainer RegisterDecorator<TFrom, TTo>(Action<DecoratorConfigurator<TFrom, TTo>>? configurator = null)\n        where TFrom : class\n        where TTo : class, TFrom\n    {\n        this.ThrowIfDisposed();\n\n        if (configurator == null) return this.RegisterInternal(TypeCache<TFrom>.Type, TypeCache<TTo>.Type, lifetime: Lifetimes.Empty, isDecorator: true);\n\n        var typeFrom = TypeCache<TFrom>.Type;\n        var typeTo = TypeCache<TTo>.Type;\n        var decoratorConfigurator = new DecoratorConfigurator<TFrom, TTo>(typeFrom, typeTo);\n        configurator(decoratorConfigurator);\n        return this.RegisterInternal(typeFrom, decoratorConfigurator);\n    }\n\n    /// <inheritdoc />\n    public IStashboxContainer RegisterDecorator(Type typeTo, Action<DecoratorConfigurator>? configurator = null)\n    {\n        this.ThrowIfDisposed();\n        Shield.EnsureNotNull(typeTo, nameof(typeTo));\n\n        var decoratorConfigurator = new DecoratorConfigurator(typeTo, typeTo);\n        configurator?.Invoke(decoratorConfigurator);\n        decoratorConfigurator\n            .AsImplementedTypes()\n            .ValidateTypeMap();\n\n        return this.RegisterInternal(typeTo, decoratorConfigurator);\n    }\n\n    /// <inheritdoc />\n    public IStashboxContainer RegisterDecorator<TTo>(Action<DecoratorConfigurator<TTo, TTo>>? configurator = null)\n        where TTo : class\n    {\n        this.ThrowIfDisposed();\n        var type = TypeCache<TTo>.Type;\n\n        var decoratorConfigurator = new DecoratorConfigurator<TTo, TTo>(type, type);\n        configurator?.Invoke(decoratorConfigurator);\n        decoratorConfigurator\n            .AsImplementedTypes()\n            .ValidateImplementationIsResolvable();\n\n        return this.RegisterInternal(type, decoratorConfigurator);\n    }\n\n    /// <inheritdoc />\n    public IStashboxContainer RegisterDecorator<TFrom>(Type typeTo, Action<DecoratorConfigurator<TFrom, TFrom>>? configurator = null)\n        where TFrom : class\n    {\n        this.ThrowIfDisposed();\n        Shield.EnsureNotNull(typeTo, nameof(typeTo));\n\n        var typeFrom = TypeCache<TFrom>.Type;\n\n        if (configurator == null)\n        {\n            Shield.EnsureTypeMapIsValid(typeFrom, typeTo);\n            return this.RegisterInternal(typeFrom, typeTo, lifetime: Lifetimes.Empty, isDecorator: true);\n        }\n\n        var decoratorConfigurator = new DecoratorConfigurator<TFrom, TFrom>(typeFrom, typeTo);\n        configurator(decoratorConfigurator);\n\n        decoratorConfigurator.ValidateTypeMap();\n\n        return this.RegisterInternal(typeFrom, decoratorConfigurator);\n    }\n\n    private IStashboxContainer RegisterInternal(Type serviceType, Type implementationType, object? name = null,\n        LifetimeDescriptor? lifetime = null, bool isDecorator = false)\n    {\n        ServiceRegistrator.Register(\n            this.ContainerContext,\n            new ServiceRegistration(implementationType, name, lifetime ?? this.ContainerContext.ContainerConfiguration.DefaultLifetime, isDecorator),\n            serviceType);\n\n        return this;\n    }\n\n    private IStashboxContainer RegisterInternal(Type serviceType, ServiceRegistration serviceRegistration)\n    {\n        ServiceRegistrator.Register(\n            this.ContainerContext,\n            serviceRegistration,\n            serviceType);\n\n        return this;\n    }\n\n    private IStashboxContainer RegisterInstanceInternal(Type serviceType, Type implementationType, object instance, bool isWireUp,\n        bool withoutDisposalTracking, object? name, Action<object>? finalizer = null)\n    {\n        ServiceRegistrator.Register(\n            this.ContainerContext,\n            new ServiceRegistration(implementationType, name, Lifetimes.Empty, false, new Dictionary<RegistrationOption, object?>\n            {\n                { RegistrationOption.Finalizer, finalizer },\n                { RegistrationOption.IsLifetimeExternallyOwned, withoutDisposalTracking },\n                { RegistrationOption.RegistrationTypeOptions, new InstanceOptions(instance, isWireUp) }\n            }),\n            serviceType);\n\n        return this;\n    }\n}"
  },
  {
    "path": "src/StashboxContainer.Resolver.cs",
    "content": "﻿using Stashbox.Resolution;\nusing System;\nusing System.Collections.Generic;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace Stashbox;\n\npublic partial class StashboxContainer\n{\n    /// <inheritdoc />\n    public object Resolve(Type typeFrom) => this.rootScope.Resolve(typeFrom);\n\n    /// <inheritdoc />\n    public object Resolve(Type typeFrom, object? name, object[]? dependencyOverrides,\n        ResolutionBehavior resolutionBehavior = ResolutionBehavior.Default) =>\n        this.rootScope.Resolve(typeFrom, name, dependencyOverrides, resolutionBehavior);\n    \n    /// <inheritdoc />\n    public object? ResolveOrDefault(Type typeFrom) =>\n        this.rootScope.ResolveOrDefault(typeFrom);\n\n    /// <inheritdoc />\n    public object? ResolveOrDefault(Type typeFrom, object? name, object[]? dependencyOverrides,\n        ResolutionBehavior resolutionBehavior = ResolutionBehavior.Default) =>\n        this.rootScope.ResolveOrDefault(typeFrom, name, dependencyOverrides, resolutionBehavior);\n    \n    /// <inheritdoc />\n    public object? GetService(Type serviceType) => this.rootScope.ResolveOrDefault(serviceType);\n\n    /// <inheritdoc />\n    public Delegate ResolveFactory(Type typeFrom, object? name = null,\n        ResolutionBehavior resolutionBehavior = ResolutionBehavior.Default, params Type[] parameterTypes) =>\n        this.rootScope.ResolveFactory(typeFrom, name, resolutionBehavior, parameterTypes);\n    \n    /// <inheritdoc />\n    public Delegate? ResolveFactoryOrDefault(Type typeFrom, object? name = null,\n        ResolutionBehavior resolutionBehavior = ResolutionBehavior.Default, params Type[] parameterTypes) =>\n        this.rootScope.ResolveFactoryOrDefault(typeFrom, name, resolutionBehavior, parameterTypes);\n\n    /// <inheritdoc />\n    public TTo BuildUp<TTo>(TTo instance, ResolutionBehavior resolutionBehavior = ResolutionBehavior.Default)\n        where TTo : class => this.rootScope.BuildUp(instance, resolutionBehavior);\n\n    /// <inheritdoc />\n    public object Activate(Type type, ResolutionBehavior resolutionBehavior, params object[] arguments) =>\n        this.rootScope.Activate(type, resolutionBehavior, arguments);\n\n    /// <inheritdoc />\n    public bool CanResolve(Type typeFrom, object? name = null,\n        ResolutionBehavior resolutionBehavior = ResolutionBehavior.Default) =>\n        this.rootScope.CanResolve(typeFrom, name, resolutionBehavior);\n\n    /// <inheritdoc />\n    public ValueTask InvokeAsyncInitializers(CancellationToken token = default) =>\n        this.rootScope.InvokeAsyncInitializers(token);\n\n    /// <inheritdoc />\n    public IDependencyResolver BeginScope(object? name = null, bool attachToParent = false)\n        => this.rootScope.BeginScope(name, attachToParent);\n\n    /// <inheritdoc />\n    public void PutInstanceInScope(Type typeFrom, object instance, bool withoutDisposalTracking = false, object? name = null) =>\n        this.rootScope.PutInstanceInScope(typeFrom, instance, withoutDisposalTracking, name);\n\n    /// <inheritdoc />\n    public IEnumerable<DelegateCacheEntry> GetDelegateCacheEntries() =>\n        this.rootScope.GetDelegateCacheEntries();\n}"
  },
  {
    "path": "src/StashboxContainer.cs",
    "content": "﻿using Stashbox.Configuration;\nusing Stashbox.Registration;\nusing Stashbox.Resolution;\nusing Stashbox.Utils;\nusing Stashbox.Utils.Data;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Runtime.CompilerServices;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Stashbox.Utils.Data.Immutable;\n\nnamespace Stashbox;\n\n/// <summary>\n/// Represents the Stashbox dependency injection container.\n/// </summary>\npublic sealed partial class StashboxContainer : IStashboxContainer\n{\n    private sealed class ChildContainerStore\n    {\n        public ImmutableTree<object, IStashboxContainer> ChildContainers =\n            ImmutableTree<object, IStashboxContainer>.Empty;\n    }\n\n    private static int globalContainerId = int.MinValue;\n\n    private int disposed;\n    private readonly ChildContainerStore childContainerStore;\n    private readonly ChildContainerStore? directParentChildContainerStore;\n    private readonly ContainerConfigurator containerConfigurator;\n    private readonly ResolutionScope rootScope;\n    private readonly object containerId;\n    private readonly bool shouldDisposeWithParent;\n\n    /// <summary>\n    /// Constructs a <see cref=\"StashboxContainer\"/>.\n    /// </summary>\n    public StashboxContainer(Action<ContainerConfigurator>? config = null)\n        : this(null, new ResolutionStrategy(), new ContainerConfigurator(), ReserveContainerId(), false, config)\n    {\n    }\n\n    private StashboxContainer(StashboxContainer? parentContainer, IResolutionStrategy resolutionStrategy,\n        ContainerConfigurator containerConfigurator, object containerId, bool shouldDisposeWithParent,\n        Action<ContainerConfigurator>? config = null)\n    {\n        this.childContainerStore = new ChildContainerStore();\n        this.directParentChildContainerStore = parentContainer?.childContainerStore;\n        this.ContainerContext = new ContainerContext(parentContainer?.ContainerContext, resolutionStrategy,\n            containerConfigurator.ContainerConfiguration);\n        this.rootScope = (ResolutionScope)this.ContainerContext.RootScope;\n        this.containerConfigurator = containerConfigurator;\n        this.containerId = containerId;\n        this.shouldDisposeWithParent = shouldDisposeWithParent;\n        config?.Invoke(this.containerConfigurator);\n    }\n\n    /// <inheritdoc />\n    public IContainerContext ContainerContext { get; }\n\n    /// <inheritdoc />\n    public IEnumerable<ReadOnlyKeyValue<object, IStashboxContainer>> ChildContainers =>\n        this.childContainerStore.ChildContainers.Walk();\n\n    /// <inheritdoc />\n    public IStashboxContainer RegisterResolver(IResolver resolver)\n    {\n        this.ThrowIfDisposed();\n        Shield.EnsureNotNull(resolver, nameof(resolver));\n\n        this.ContainerContext.ResolutionStrategy.RegisterResolver(resolver);\n        return this;\n    }\n\n    /// <inheritdoc />\n    public bool IsRegistered<TFrom>(object? name = null) =>\n        this.IsRegistered(TypeCache<TFrom>.Type, name);\n\n    /// <inheritdoc />\n    public bool IsRegistered(Type typeFrom, object? name = null)\n    {\n        this.ThrowIfDisposed();\n        Shield.EnsureNotNull(typeFrom, nameof(typeFrom));\n\n        return this.ContainerContext.RegistrationRepository.ContainsRegistration(typeFrom, name, false);\n    }\n\n    /// <inheritdoc />\n    public void Validate()\n    {\n        this.ThrowIfDisposed();\n\n        var exceptions = new ExpandableArray<Exception>();\n\n        foreach (var serviceRegistration in this.ContainerContext.RegistrationRepository\n                     .GetRegistrationMappings()\n                     .Where(reg => !reg.Key.IsOpenGenericType()))\n        {\n            try\n            {\n                this.ContainerContext.ResolutionStrategy.BuildExpressionForRegistration(serviceRegistration.Value,\n                    ResolutionContext.BeginValidationContext(this.ContainerContext, ResolutionBehavior.Default),\n                    new TypeInformation(serviceRegistration.Key, serviceRegistration.Value.Name));\n            }\n            catch (Exception ex)\n            {\n                exceptions.Add(ex);\n            }\n        }\n\n        foreach (var child in this.childContainerStore.ChildContainers.Walk())\n        {\n            try\n            {\n                child.Value.Validate();\n            }\n            catch (AggregateException ex)\n            {\n                exceptions.Add(new AggregateException(\n                    $\"Child container validation failed for '{child.Key}'. See the inner exceptions for details.\",\n                    ex.InnerExceptions));\n            }\n        }\n\n        if (exceptions.Length > 0)\n            throw new AggregateException(\"Container validation failed. See the inner exceptions for details.\",\n                exceptions);\n    }\n\n    /// <inheritdoc />\n    public IStashboxContainer CreateChildContainer(Action<ContainerConfigurator>? config = null,\n        bool attachToParent = true) =>\n        this.CreateChildContainer(ReserveContainerId(), config == null ? null : cont => cont.Configure(config),\n            attachToParent);\n\n    /// <inheritdoc />\n    public IStashboxContainer CreateChildContainer(object identifier, Action<IStashboxContainer>? config = null,\n        bool attachToParent = true)\n    {\n        this.ThrowIfDisposed();\n\n        var child = new StashboxContainer(this, this.ContainerContext.ResolutionStrategy,\n            new ContainerConfigurator(this.ContainerContext.ContainerConfiguration.Clone()), identifier,\n            attachToParent);\n\n        config?.Invoke(child);\n\n        Swap.SwapValue(ref this.childContainerStore.ChildContainers, (t1, t2, _, _, childStore) =>\n                childStore.AddOrUpdate(t1, t2, false, false),\n            identifier, child, Constants.DelegatePlaceholder, Constants.DelegatePlaceholder);\n\n        return child;\n    }\n\n    /// <inheritdoc />\n    public IStashboxContainer? GetChildContainer(object identifier) =>\n        this.childContainerStore.ChildContainers.GetOrDefaultByValue(identifier);\n\n    /// <inheritdoc />\n    public IStashboxContainer Configure(Action<ContainerConfigurator> config)\n    {\n        this.ThrowIfDisposed();\n        Shield.EnsureNotNull(config, \"The config parameter cannot be null!\");\n\n        config.Invoke(this.containerConfigurator);\n        this.containerConfigurator.ContainerConfiguration.ConfigurationChangedEvent?\n            .Invoke(this.containerConfigurator.ContainerConfiguration);\n\n        this.ContainerContext.RootScope.InvalidateDelegateCache();\n        return this;\n    }\n\n    /// <inheritdoc />\n    public IEnumerable<KeyValuePair<Type, ServiceRegistration>> GetRegistrationMappings()\n    {\n        this.ThrowIfDisposed();\n\n        return this.ContainerContext.RegistrationRepository.GetRegistrationMappings();\n    }\n\n    /// <inheritdoc />\n    public IEnumerable<RegistrationDiagnosticsInfo> GetRegistrationDiagnostics()\n    {\n        this.ThrowIfDisposed();\n\n        foreach (var reg in this.ContainerContext.RegistrationRepository.GetRegistrationMappings())\n            yield return new RegistrationDiagnosticsInfo(reg.Key, reg.Value.ImplementationType, reg.Value.Name);\n    }\n\n    private void ThrowIfDisposed([CallerMemberName] string caller = \"<unknown>\")\n    {\n        if (this.disposed == 1)\n            Shield.ThrowDisposedException(this.GetType().FullName, caller);\n    }\n\n    /// <inheritdoc />\n    public void Dispose()\n    {\n        if (Interlocked.CompareExchange(ref this.disposed, 1, 0) != 0)\n            return;\n\n        this.RemoveSelfFromParentChildContainers();\n        this.DisposeChildContainers();\n        this.rootScope.Dispose();\n    }\n\n#if HAS_ASYNC_DISPOSABLE\n    /// <inheritdoc />\n    public async ValueTask DisposeAsync()\n    {\n        if (Interlocked.CompareExchange(ref this.disposed, 1, 0) != 0)\n            return;\n        \n        this.RemoveSelfFromParentChildContainers();\n        await this.DisposeChildContainersAsync().ConfigureAwait(false);\n        await this.rootScope.DisposeAsync().ConfigureAwait(false);\n    }\n    \n    private async ValueTask DisposeChildContainersAsync()\n    {\n        foreach (var childContainer in this.childContainerStore.ChildContainers.Walk())\n        {\n            if (childContainer.Value is StashboxContainer { shouldDisposeWithParent: true } container)\n                await container.DisposeAsync().ConfigureAwait(false);\n        }\n    }\n#endif\n\n    private void DisposeChildContainers()\n    {\n        foreach (var childContainer in this.childContainerStore.ChildContainers.Walk())\n        {\n            if (childContainer.Value is StashboxContainer { shouldDisposeWithParent: true } container)\n                container.Dispose();\n        }\n    }\n    \n    private void RemoveSelfFromParentChildContainers()\n    {\n        if (this.directParentChildContainerStore != null)\n            Swap.SwapValue(ref this.directParentChildContainerStore.ChildContainers, (t1, _, _, _, childRepo) =>\n                    childRepo.Remove(t1, false),\n                this.containerId, Constants.DelegatePlaceholder, Constants.DelegatePlaceholder,\n                Constants.DelegatePlaceholder);\n    }\n\n    private static int ReserveContainerId() =>\n        Interlocked.Increment(ref globalContainerId);\n}"
  },
  {
    "path": "src/Utils/Constants.cs",
    "content": "﻿using Stashbox.Resolution;\nusing System;\nusing System.Linq.Expressions;\nusing System.Reflection;\nusing System.Reflection.Emit;\nusing System.Runtime.CompilerServices;\n\nnamespace Stashbox.Utils;\n\ninternal static class Constants\n{\n    public static readonly ParameterExpression ResolutionScopeParameter = TypeCache<IResolutionScope>.Type.AsParameter(\"scope\");\n\n    public static readonly ParameterExpression RequestContextParameter = TypeCache<IRequestContext>.Type.AsParameter(\"request\");\n\n    public static readonly MethodInfo AddDisposalMethod = TypeCache<IResolutionScope>.Type.GetMethod(nameof(IResolutionScope.AddDisposableTracking))!;\n\n    public static readonly MethodInfo AddRequestContextAwareDisposalMethod = TypeCache<IResolutionScope>.Type.GetMethod(nameof(IResolutionScope.AddRequestContextAwareDisposableTracking))!;\n\n    public static readonly MethodInfo GetOrAddScopedObjectMethod = TypeCache<IResolutionScope>.Type.GetMethod(nameof(IResolutionScope.GetOrAddScopedObject))!;\n\n    public static readonly MethodInfo AddWithFinalizerMethod = TypeCache<IResolutionScope>.Type.GetMethod(nameof(IResolutionScope.AddWithFinalizer))!;\n\n    public static readonly MethodInfo AddWithAsyncInitializerMethod = TypeCache<IResolutionScope>.Type.GetMethod(nameof(IResolutionScope.AddWithAsyncInitializer))!;\n\n    public static readonly MethodInfo GetOrAddInstanceMethod = TypeCache<IInternalRequestContext>.Type.GetMethod(nameof(IInternalRequestContext.GetOrAddInstance))!;\n        \n    public static readonly MethodInfo ResolveMethod =\n        TypeCache<IDependencyResolver>.Type.GetMethod(nameof(IDependencyResolver.Resolve), [\n            TypeCache<Type>.Type,\n            TypeCache<object>.Type, TypeCache<object[]>.Type, TypeCache<ResolutionBehavior>.Type\n        ])!;\n\n    public static readonly MethodInfo BeginScopeMethod = TypeCache<IDependencyResolver>.Type.GetMethod(nameof(IDependencyResolver.BeginScope))!;\n\n    public const MethodImplOptions Inline = (MethodImplOptions)256;\n\n    public const byte DelegatePlaceholder = 0;\n\n    public const ResolutionBehavior DefaultResolutionBehavior = ResolutionBehavior.Default;\n    \n    public const int DefaultResolutionBehaviorInt = (int)DefaultResolutionBehavior;\n}"
  },
  {
    "path": "src/Utils/Data/ExpandableArray.cs",
    "content": "﻿using System;\nusing System.Collections;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Runtime.CompilerServices;\n\nnamespace Stashbox.Utils.Data;\n\ninternal class ExpandableArray<TItem> : IEnumerable<TItem>\n{\n    private const int InitialSize = 8;\n\n    public int Length;\n\n    protected TItem[]? Repository;\n\n    public ExpandableArray()\n    { }\n\n    public ExpandableArray(ExpandableArray<TItem> initial)\n    {\n        this.Repository = initial.AsArray();\n        this.Length = this.Repository.Length;\n    }\n\n    public ExpandableArray(IEnumerable<TItem> initial)\n        : this(initial.CastToArray())\n    { }\n\n    public ExpandableArray(TItem[] initial)\n    {\n        this.Repository = initial;\n        this.Length = this.Repository.Length;\n    }\n\n    public void Add(TItem item)\n    {\n        var index = this.EnsureSize();\n        this.Repository![index] = item;\n    }\n\n    public void AddOrKeep(TItem item)\n    {\n        if (this.ContainsReference(item))\n            return;\n\n        var index = this.EnsureSize();\n        this.Repository![index] = item;\n    }\n\n    public void AddRange(IEnumerable<TItem> items) => this.AddRange(items.CastToArray());\n\n    public void AddRange(TItem[] items)\n    {\n        var index = this.EnsureSize(items.Length);\n        Array.Copy(items, 0, this.Repository!, index, items.Length);\n    }\n\n    public TItem this[int i] => this.Repository![i];\n\n    public TItem[] AsArray()\n    {\n        if (this.Length == 0)\n            return TypeCache.EmptyArray<TItem>();\n\n        Array.Resize(ref this.Repository, this.Length);\n        return this.Repository;\n    }\n\n    public int IndexOf(TItem element)\n    {\n        var length = this.Length;\n        if (length == 1) return ReferenceEquals(this.Repository![0], element) ? 0 : -1;\n\n        for (var i = 0; i < length; i++)\n            if (ReferenceEquals(this.Repository![i], element))\n                return i;\n\n        return -1;\n    }\n\n    public bool ContainsReference(TItem element)\n    {\n        var length = this.Length;\n        if (length == 1) return ReferenceEquals(this.Repository![0], element);\n\n        for (var i = 0; i < length; i++)\n            if (ReferenceEquals(this.Repository![i], element))\n                return true;\n\n        return false;\n    }\n\n    public bool Contains(TItem element)\n    {\n        var length = this.Length;\n        if (length == 1) return Equals(this.Repository![0], element);\n\n        for (var i = 0; i < length; i++)\n            if (Equals(this.Repository![i], element))\n                return true;\n\n        return false;\n    }\n\n    protected int EnsureSize(int increaseAmount = 1)\n    {\n        if (this.Length == 0)\n            this.Repository = new TItem[increaseAmount > InitialSize ? increaseAmount : InitialSize];\n\n        this.Length += increaseAmount;\n        if (this.Repository!.Length >= this.Length) return this.Length - increaseAmount;\n\n        var newSize = this.Repository.Length * 2;\n        var desiredSize = this.Length > newSize ? this.Length : newSize;\n        Array.Resize(ref this.Repository, desiredSize);\n\n        return this.Length - increaseAmount;\n    }\n\n    public TItem First() => this.Repository![0];\n\n    public IEnumerator<TItem> GetEnumerator()\n    {\n        var length = this.Length;\n        for (var i = 0; i < length; i++)\n            yield return this.Repository![i];\n    }\n\n    IEnumerator IEnumerable.GetEnumerator() => this.GetEnumerator();\n}\n\ninternal class ExpandableArray<TKey, TItem> : ExpandableArray<ReadOnlyKeyValue<TKey, TItem>>\n{\n    public ExpandableArray()\n    { }\n\n    public ExpandableArray(ExpandableArray<TKey, TItem> initial)\n        : base(initial)\n    { }\n\n    [MethodImpl(Constants.Inline)]\n    public TItem? GetOrDefaultByValue(TKey key)\n    {\n        var length = this.Length;\n        for (var i = 0; i < length; i++)\n        {\n            ref readonly var item = ref this.Repository![i];\n            if (Equals(item.Key, key))\n                return item.Value;\n        }\n\n        return default;\n    }\n\n    [MethodImpl(Constants.Inline)]\n    public TItem? GetOrDefaultByRef(TKey key)\n    {\n        var length = this.Length;\n        for (var i = 0; i < length; i++)\n        {\n            ref readonly var item = ref this.Repository![i];\n            if (ReferenceEquals(item.Key, key))\n                return item.Value;\n        }\n\n        return default;\n    }\n\n    public void AddOrKeep(TKey item, TItem value)\n    {\n        if (this.ContainsReference(item))\n            return;\n\n        var index = this.EnsureSize();\n        this.Repository![index] = new ReadOnlyKeyValue<TKey, TItem>(item, value);\n    }\n\n    public void AddOrUpdate(TKey key, TItem value)\n    {\n        var index = this.IndexOf(key);\n        if (index >= 0)\n        {\n            this.Repository![index] = new ReadOnlyKeyValue<TKey, TItem>(key, value);\n            return;\n        }\n\n        index = this.EnsureSize();\n        this.Repository![index] = new ReadOnlyKeyValue<TKey, TItem>(key, value);\n    }\n\n    public int IndexAndValueOf(TKey key, out TItem? value)\n    {\n        value = default;\n        var length = this.Length;\n        for (var i = 0; i < length; i++)\n        {\n            ref readonly var item = ref Repository![i];\n            if (!ReferenceEquals(item.Key, key)) continue;\n            value = item.Value;\n            return i;\n        }\n\n        return -1;\n    }\n\n    public int IndexOf(TKey key)\n    {\n        var length = this.Length;\n        if (length == 1) return ReferenceEquals(this.Repository![0].Key, key) ? 0 : -1;\n\n        for (var i = 0; i < length; i++)\n        {\n            ref readonly var item = ref Repository![i];\n            if (ReferenceEquals(item.Key, key))\n                return i;\n        }\n\n        return -1;\n    }\n\n    public bool ContainsReference(TKey key)\n    {\n        var length = this.Length;\n        if (length == 1) return ReferenceEquals(this.Repository![0].Key, key);\n\n        for (var i = 0; i < length; i++)\n        {\n            ref readonly var item = ref Repository![i];\n            if (ReferenceEquals(item.Key, key))\n                return true;\n\n        }\n\n        return false;\n    }\n}"
  },
  {
    "path": "src/Utils/Data/HashTree.cs",
    "content": "﻿using System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Linq;\nusing System.Runtime.CompilerServices;\n\nnamespace Stashbox.Utils.Data;\n\n[DebuggerTypeProxy(typeof(HashTreeDebugView<,>))]\ninternal sealed class HashTree<TKey, TValue>\n    where TKey : class\n{\n    private class Node\n    {\n        public readonly int StoredHash;\n        public readonly TKey StoredKey;\n        public TValue StoredValue;\n        public Node? Left;\n        public Node? Right;\n        public int Height;\n        public ExpandableArray<TKey, TValue>? Collisions;\n\n        public Node(TKey key, TValue value, int hash)\n        {\n            this.StoredValue = value;\n            this.StoredKey = key;\n            this.StoredHash = hash;\n            this.Height = 1;\n        }\n    }\n\n    private Node? root;\n\n    public void Add(TKey key, TValue value)\n    {\n        this.root = Add(this.root, key, key.GetHashCode(), value);\n    }\n\n    [MethodImpl(Constants.Inline)]\n    public TValue? GetOrDefault(TKey key)\n    {\n        if (this.root == null)\n            return default;\n\n        var node = root;\n        var hash = key.GetHashCode();\n        while (node != null && node.StoredHash != hash)\n            node = hash < node.StoredHash ? node.Left : node.Right;\n        return node != null && Equals(key, node.StoredKey)\n            ? node.StoredValue\n            : node?.Collisions == null\n                ? default\n                : node.Collisions.GetOrDefaultByValue(key);\n    }\n\n    private static int CalculateHeight(Node node)\n    {\n        if (node is { Left: not null, Right: not null })\n            return 1 + (node.Left.Height > node.Right.Height ? node.Left.Height : node.Right.Height);\n\n        if (node.Left == null && node.Right == null)\n            return 1;\n\n        return 1 + (node.Left?.Height ?? node.Right!.Height);\n    }\n\n    private static int GetBalance(Node node)\n    {\n        if (node is { Left: not null, Right: not null })\n            return node.Left.Height - node.Right.Height;\n\n        if (node.Left == null && node.Right == null)\n            return 0;\n\n        return node.Left?.Height ?? node.Right!.Height * -1;\n    }\n\n    private static Node RotateLeft(Node node)\n    {\n        var current = node.Right;\n        var left = current!.Left;\n\n        current.Left = node;\n        node.Right = left;\n\n        current.Height = CalculateHeight(current);\n        node.Height = CalculateHeight(node);\n\n        return current;\n    }\n\n    private static Node RotateRight(Node node)\n    {\n        var current = node.Left;\n        var right = current!.Right;\n        current.Right = node;\n        node.Left = right;\n        current.Height = CalculateHeight(current);\n        node.Height = CalculateHeight(node);\n\n        return current;\n    }\n\n    private static Node Add(Node? node, TKey key, int hash, TValue value)\n    {\n        if (node == null)\n            return new Node(key, value, hash);\n\n        if (node.StoredHash == hash)\n        {\n            CheckCollisions(node, key, value);\n            return node;\n        }\n\n        if (node.StoredHash > hash)\n            node.Left = Add(node.Left, key, hash, value);\n        else\n            node.Right = Add(node.Right, key, hash, value);\n\n        node.Height = CalculateHeight(node);\n        var balance = GetBalance(node);\n\n        switch (balance)\n        {\n            case >= 2 when GetBalance(node.Left!) == -1:\n                node.Left = RotateLeft(node.Left!);\n                node = RotateRight(node);\n                break;\n            case >= 2:\n                node = RotateRight(node);\n                break;\n            case <= -2 when GetBalance(node.Right!) == 1:\n                node.Right = RotateRight(node.Right!);\n                node = RotateLeft(node);\n                break;\n            case <= -2:\n                node = RotateLeft(node);\n                break;\n        }\n\n        return node;\n    }\n\n    private static void CheckCollisions(Node node, TKey key, TValue value)\n    {\n        if (Equals(key, node.StoredKey))\n            node.StoredValue = value;\n        else\n        {\n            node.Collisions ??= [];\n            node.Collisions.Add(new ReadOnlyKeyValue<TKey, TValue>(key, value));\n        }\n    }\n\n    public IEnumerable<TValue> Walk()\n    {\n        if (this.root == null)\n            yield break;\n\n        switch (this.root.Height)\n        {\n            case 1:\n                yield return this.root.StoredValue;\n                break;\n            case 2:\n                if (this.root.Left != null)\n                    yield return this.root.Left.StoredValue;\n                yield return this.root.StoredValue;\n                if (this.root.Right != null)\n                    yield return this.root.Right.StoredValue;\n                break;\n            default:\n            {\n                var nodes = new Node[this.root.Height - 2];\n                var currentNode = this.root;\n                var index = -1;\n\n                while (true)\n                {\n                    if (currentNode != null)\n                    {\n                        if (currentNode.Height == 2)\n                        {\n                            if (currentNode.Left != null)\n                                yield return currentNode.Left.StoredValue;\n                            yield return currentNode.StoredValue;\n                            if (currentNode.Right != null)\n                                yield return currentNode.Right.StoredValue;\n\n                            if (index == -1)\n                                break;\n                            currentNode = nodes[index--];\n                            yield return currentNode.StoredValue;\n\n                            currentNode = currentNode.Right;\n                        }\n                        else if (currentNode.Height == 1)\n                        {\n                            yield return currentNode.StoredValue;\n\n                            if (index == -1)\n                                break;\n                            currentNode = nodes[index--];\n                            yield return currentNode.StoredValue;\n\n                            currentNode = currentNode.Right;\n                        }\n                        else\n                        {\n                            nodes[++index] = currentNode;\n                            currentNode = currentNode.Left;\n                        }\n                    }\n                    else\n                    {\n                        if (index == -1)\n                            break;\n                        currentNode = nodes[index--];\n                        yield return currentNode.StoredValue;\n\n                        currentNode = currentNode.Right;\n                    }\n\n                }\n\n                break;\n            }\n        }\n    }\n}\n\ninternal class HashTreeDebugView<TKey, TValue> where TKey : class\n{\n    private readonly HashTree<TKey, TValue> tree;\n\n    public HashTreeDebugView(HashTree<TKey, TValue> tree) { this.tree = tree; }\n\n    [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]\n    public TValue[] Items => tree.Walk().ToArray();\n}"
  },
  {
    "path": "src/Utils/Data/Immutable/ImmutableBucket.cs",
    "content": "﻿using System;\nusing System.Collections;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Runtime.CompilerServices;\n\nnamespace Stashbox.Utils.Data.Immutable;\n\n[DebuggerTypeProxy(typeof(ImmutableBucketDebugView<>))]\ninternal class ImmutableBucket<TValue>\n{\n    public static readonly ImmutableBucket<TValue> Empty = new(TypeCache.EmptyArray<TValue>());\n\n    public readonly int Length;\n\n    public readonly TValue[] Repository;\n\n    public TValue this[int i] => this.Repository[i];\n\n    public ImmutableBucket(TValue value)\n        : this([value])\n    { }\n\n    public ImmutableBucket(TValue[] repository)\n    {\n        this.Repository = repository;\n        this.Length = repository.Length;\n    }\n\n    internal ImmutableBucket<TValue> Add(TValue value)\n    {\n        if (this.Length == 0)\n            return new ImmutableBucket<TValue>([value]);\n\n        var newRepository = new TValue[this.Length + 1];\n        Array.Copy(this.Repository, newRepository, this.Length);\n        newRepository[this.Length] = value;\n\n        return new ImmutableBucket<TValue>(newRepository);\n    }\n\n    internal ImmutableBucket<TValue> Insert(int index, TValue value)\n    {\n        if (index > this.Length - 1)\n            throw new IndexOutOfRangeException();\n\n        if (this.Length == 0)\n            return new ImmutableBucket<TValue>([value]);\n\n        var newRepository = new TValue[this.Length + 1];\n        Array.Copy(this.Repository, newRepository, index);\n        newRepository[index] = value;\n        Array.Copy(this.Repository, index, newRepository, index + 1, this.Length - index);\n\n        return new ImmutableBucket<TValue>(newRepository);\n    }\n\n    internal ImmutableBucket<TValue> ReplaceAt(int index, TValue value)\n    {\n        if (index > this.Length - 1)\n            throw new IndexOutOfRangeException();\n\n        if (this.Length == 0)\n            return new ImmutableBucket<TValue>([value]);\n\n        var newRepository = new TValue[this.Length];\n        Array.Copy(this.Repository, newRepository, this.Length);\n        newRepository[index] = value;\n\n        return new ImmutableBucket<TValue>(newRepository);\n    }\n    \n    public ImmutableBucket<TValue> AddIfNotExist(TValue value)\n    {\n        if (this.Length == 0)\n            return this;\n\n        var count = this.Length - 1;\n        while (count >= 0)\n        {\n            ref readonly var item = ref this.Repository[count];\n            if (ReferenceEquals(item, value))\n                break;\n\n            count--;\n        }\n\n        return count != -1 ? this : this.Add(value);\n    }\n    \n    public ImmutableBucket<TValue> Remove(TValue value)\n    {\n        if (this.Length == 0)\n            return this;\n\n        var count = this.Length - 1;\n        while (count >= 0)\n        {\n            ref readonly var item = ref this.Repository[count];\n            if (ReferenceEquals(item, value))\n                break;\n\n            count--;\n        }\n\n        if (count == -1)\n            return this;\n        \n        var newRepository = new TValue[this.Length - 1];\n        Array.Copy(this.Repository, newRepository, count);\n        Array.Copy(this.Repository, count + 1, newRepository, count, this.Length - 1 - count);\n        return new ImmutableBucket<TValue>(newRepository);\n    }\n}\n\ninternal class ImmutableBucketDebugView<TValue>\n{\n    private readonly ImmutableBucket<TValue> bucket;\n\n    public ImmutableBucketDebugView(ImmutableBucket<TValue> bucket) { this.bucket = bucket; }\n\n    [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]\n    public TValue[] Items => bucket.Repository;\n}\n\ninternal class ImmutableBucket<TKey, TValue> : IEnumerable<TValue>\n{\n    public static readonly ImmutableBucket<TKey, TValue> Empty = new(TypeCache.EmptyArray<ReadOnlyKeyValue<TKey, TValue>>());\n\n    public readonly int Length;\n\n    public readonly ReadOnlyKeyValue<TKey, TValue>[] Repository;\n\n    private ImmutableBucket(ReadOnlyKeyValue<TKey, TValue>[] repository)\n    {\n        this.Repository = repository;\n        this.Length = repository.Length;\n    }\n\n    public ImmutableBucket<TKey, TValue> Add(TKey key, TValue value)\n    {\n        if (this.Length == 0)\n            return new ImmutableBucket<TKey, TValue>([new ReadOnlyKeyValue<TKey, TValue>(key, value)]);\n\n        var newRepository = new ReadOnlyKeyValue<TKey, TValue>[this.Length + 1];\n        Array.Copy(this.Repository, newRepository, this.Length);\n        newRepository[this.Length] = new ReadOnlyKeyValue<TKey, TValue>(key, value);\n\n        return new ImmutableBucket<TKey, TValue>(newRepository);\n    }\n\n    public ImmutableBucket<TKey, TValue> AddOrUpdate(TKey key, TValue value, bool byRef)\n    {\n        if (this.Length == 0)\n            return new ImmutableBucket<TKey, TValue>([new ReadOnlyKeyValue<TKey, TValue>(key, value)]);\n\n        var count = this.Length - 1;\n        while (count >= 0)\n        {\n            ref readonly var item = ref this.Repository[count];\n            if (byRef && ReferenceEquals(item.Key, key) || !byRef && Equals(item.Key, key))\n                break;\n\n            count--;\n        }\n\n        if (count == -1)\n            return this.Add(key, value);\n\n        var newRepository = new ReadOnlyKeyValue<TKey, TValue>[this.Length];\n        Array.Copy(this.Repository, newRepository, this.Length);\n        newRepository[count] = new ReadOnlyKeyValue<TKey, TValue>(key, value);\n\n        return new ImmutableBucket<TKey, TValue>(newRepository);\n    }\n\n    public ImmutableBucket<TKey, TValue> ReplaceIfExists(TKey key, Func<TValue, TValue> updateDelegate, bool byRef)\n    {\n        if (this.Length == 0)\n            return this;\n\n        var count = this.Length - 1;\n        while (count >= 0)\n        {\n            ref readonly var item = ref this.Repository[count];\n            if (byRef && ReferenceEquals(item.Key, key) || !byRef && Equals(item.Key, key))\n                break;\n\n            count--;\n        }\n\n        if (count == -1)\n            return this;\n\n        var newRepository = new ReadOnlyKeyValue<TKey, TValue>[this.Length];\n        Array.Copy(this.Repository, newRepository, this.Length);\n\n        newRepository[count] = new ReadOnlyKeyValue<TKey, TValue>(key, updateDelegate(newRepository[count].Value));\n\n        return new ImmutableBucket<TKey, TValue>(newRepository);\n    }\n\n    public ImmutableBucket<TKey, TValue> ReplaceIfExists(TKey key, TValue value, bool byRef, Func<TValue, TValue, TValue>? update = null)\n    {\n        if (this.Length == 0)\n            return this;\n\n        var count = this.Length - 1;\n        while (count >= 0)\n        {\n            ref readonly var item = ref this.Repository[count];\n            if (byRef && ReferenceEquals(item.Key, key) || !byRef && Equals(item.Key, key))\n                break;\n\n            count--;\n        }\n\n        if (count == -1)\n            return this;\n\n        var old = this.Repository[count].Value;\n        var @new = update == null ? value : update(old, value);\n        if (ReferenceEquals(@new, old))\n            return this;\n\n        var newRepository = new ReadOnlyKeyValue<TKey, TValue>[this.Length];\n        Array.Copy(this.Repository, newRepository, this.Length);\n\n        newRepository[count] = new ReadOnlyKeyValue<TKey, TValue>(key, @new);\n\n        return new ImmutableBucket<TKey, TValue>(newRepository);\n    }\n    \n    [MethodImpl(Constants.Inline)]\n    public TValue? GetOrDefaultByValue(TKey key)\n    {\n        var length = this.Repository.Length;\n        for (var i = 0; i < length; i++)\n        {\n            ref readonly var item = ref this.Repository[i];\n            if (Equals(item.Key, key))\n                return item.Value;\n        }\n\n        return default;\n    }\n\n    [MethodImpl(Constants.Inline)]\n    public TValue? GetOrDefaultByRef(TKey key)\n    {\n        var length = this.Repository.Length;\n        for (var i = 0; i < length; i++)\n        {\n            ref readonly var item = ref this.Repository[i];\n            if (ReferenceEquals(item.Key, key))\n                return item.Value;\n        }\n\n        return default;\n    }\n\n    public ImmutableBucket<TKey, TValue> Remove(TKey key, bool byRef)\n    {\n        if (this.Length == 0)\n            return this;\n\n        var count = this.Length - 1;\n        while (count >= 0)\n        {\n            ref readonly var item = ref this.Repository[count];\n            if (byRef && ReferenceEquals(item.Key, key) || !byRef && Equals(item.Key, key))\n                break;\n\n            count--;\n        }\n\n        if (count == -1)\n            return this;\n        \n        var newRepository = new ReadOnlyKeyValue<TKey, TValue>[this.Length - 1];\n        Array.Copy(this.Repository, newRepository, count);\n        Array.Copy(this.Repository, count + 1, newRepository, count, this.Length - 1 - count);\n        return new ImmutableBucket<TKey, TValue>(newRepository);\n    }\n    \n    public ImmutableBucket<TKey, TValue> RemoveFirst()\n    {\n        switch (this.Length)\n        {\n            case 0:\n                return this;\n            case 1:\n                return new ImmutableBucket<TKey, TValue>([]);\n        }\n\n        var newRepository = new ReadOnlyKeyValue<TKey, TValue>[this.Length - 1];\n        Array.Copy(this.Repository, 1, newRepository, 0, this.Length - 1);\n\n        return new ImmutableBucket<TKey, TValue>(newRepository);\n    }\n    \n    public IEnumerator<TValue> GetEnumerator()\n    {\n        for (var i = 0; i < this.Length; i++)\n            yield return this.Repository[i].Value;\n    }\n\n    IEnumerator IEnumerable.GetEnumerator()\n    {\n        return this.Repository.GetEnumerator();\n    }\n}"
  },
  {
    "path": "src/Utils/Data/Immutable/ImmutableLinkedList.cs",
    "content": "﻿#nullable disable\n\nnamespace Stashbox.Utils.Data.Immutable;\n\ninternal class ImmutableLinkedList<TValue>\n{\n    public static readonly ImmutableLinkedList<TValue> Empty = new();\n\n    public readonly TValue Value;\n\n    public readonly ImmutableLinkedList<TValue> Next;\n\n    private ImmutableLinkedList(ImmutableLinkedList<TValue> next, TValue value)\n    {\n        this.Value = value;\n        this.Next = next;\n    }\n\n    private ImmutableLinkedList()\n    { }\n\n    public ImmutableLinkedList<TValue> Add(TValue value) =>\n        new(this, value);\n}"
  },
  {
    "path": "src/Utils/Data/Immutable/ImmutableTree.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Linq;\nusing System.Runtime.CompilerServices;\n\nnamespace Stashbox.Utils.Data.Immutable;\n\n[DebuggerTypeProxy(typeof(ImmutableTreeDebugView<>))]\ninternal sealed class ImmutableTree<TValue>\n{\n    public static readonly ImmutableTree<TValue> Empty = new();\n\n    private readonly int storedHash;\n    private readonly TValue? storedValue;\n\n    private readonly ImmutableTree<TValue>? leftNode;\n    private readonly ImmutableTree<TValue>? rightNode;\n\n    private readonly int height;\n    public readonly bool IsEmpty = true;\n\n    private ImmutableTree(int hash, TValue value, ImmutableTree<TValue> left, ImmutableTree<TValue> right)\n    {\n        this.storedHash = hash;\n        this.leftNode = left;\n        this.rightNode = right;\n        this.storedValue = value;\n        this.IsEmpty = false;\n        this.height = 1 + (left.height > right.height ? left.height : right.height);\n    }\n\n    private ImmutableTree(int hash, TValue value)\n    {\n        this.storedHash = hash;\n        this.leftNode = Empty;\n        this.rightNode = Empty;\n        this.storedValue = value;\n        this.IsEmpty = false;\n        this.height = 1;\n    }\n\n    private ImmutableTree()\n    { }\n\n    [MethodImpl(Constants.Inline)]\n    public TValue? GetOrDefault(int key)\n    {\n        if (this.IsEmpty)\n            return default;\n\n        var node = this;\n        while (!node!.IsEmpty && node.storedHash != key)\n            node = key < node.storedHash ? node.leftNode : node.rightNode;\n        return !node.IsEmpty ? node.storedValue : default;\n    }\n\n    public ImmutableTree<TValue> AddOrUpdate(int key, TValue value, Func<TValue, TValue, TValue>? updateDelegate = null)\n    {\n        if (this.IsEmpty)\n            return new ImmutableTree<TValue>(key, value);\n\n        if (key == this.storedHash)\n            return updateDelegate != null\n                ? new ImmutableTree<TValue>(key, updateDelegate(this.storedValue!, value), this.leftNode!, this.rightNode!)\n                : this;\n\n        return key < this.storedHash\n            ? this.height == 1\n                ? new ImmutableTree<TValue>(this.storedHash, this.storedValue!,\n                    new ImmutableTree<TValue>(key, value), this.rightNode!)\n                : Balance(this.storedHash, this.storedValue!, this.leftNode!.AddOrUpdate(key, value, updateDelegate), this.rightNode!)\n            : this.height == 1\n                ? new ImmutableTree<TValue>(this.storedHash, this.storedValue!, this.leftNode!,\n                    new ImmutableTree<TValue>(key, value))\n                : Balance(this.storedHash, this.storedValue!, this.leftNode!, this.rightNode!.AddOrUpdate(key, value, updateDelegate));\n    }\n    \n    public ImmutableTree<TValue> Remove(int key)\n    {\n        if (this.IsEmpty) return this;\n\n        if (key != this.storedHash)\n            return key < this.storedHash\n                ? Balance(this.storedHash, this.storedValue!, this.leftNode!.Remove(key), this.rightNode!)\n                : Balance(this.storedHash, this.storedValue!, this.leftNode!, this.rightNode!.Remove(key));\n        \n        if (this.height == 1) return Empty;\n        if (this.rightNode!.IsEmpty) return this.leftNode!;\n        if (this.leftNode!.IsEmpty) return this.rightNode!;\n\n        var next = this.rightNode;\n        while (!next.leftNode!.IsEmpty) next = next.leftNode;\n        return new ImmutableTree<TValue>(next.storedHash, next.storedValue!,\n            this.leftNode!, this.rightNode!.Remove(next.storedHash));\n    }\n\n    private static ImmutableTree<TValue> Balance(int hash, TValue value, ImmutableTree<TValue> left, ImmutableTree<TValue> right)\n    {\n        var balance = left.height - right.height;\n\n        return balance switch\n        {\n            >= 2 => left.leftNode!.height - left.rightNode!.height == -1\n                ? RotateLeftRight(hash, value, left, right)\n                : RotateRight(hash, value, left, right),\n            <= -2 => right.leftNode!.height - right.rightNode!.height == 1\n                ? RotateRightLeft(hash, value, left, right)\n                : RotateLeft(hash, value, left, right),\n            _ => new ImmutableTree<TValue>(hash, value, left, right)\n        };\n    }\n\n    private static ImmutableTree<TValue> RotateRight(int hash, TValue value, ImmutableTree<TValue> left, ImmutableTree<TValue> right)\n    {\n        var r = new ImmutableTree<TValue>(hash, value, left.rightNode!, right);\n        return new ImmutableTree<TValue>(left.storedHash, left.storedValue!, left.leftNode!, r);\n    }\n\n    private static ImmutableTree<TValue> RotateLeft(int hash, TValue value, ImmutableTree<TValue> left, ImmutableTree<TValue> right)\n    {\n        var l = new ImmutableTree<TValue>(hash, value, left, right.leftNode!);\n        return new ImmutableTree<TValue>(right.storedHash, right.storedValue!, l, right.rightNode!);\n    }\n\n    private static ImmutableTree<TValue> RotateRightLeft(int hash, TValue value, ImmutableTree<TValue> left, ImmutableTree<TValue> right)\n    {\n        var l = new ImmutableTree<TValue>(hash, value, left, right.leftNode!.leftNode!);\n        var r = new ImmutableTree<TValue>(right.storedHash, right.storedValue!, right.leftNode.rightNode!, right.rightNode!);\n        return new ImmutableTree<TValue>(right.leftNode.storedHash, right.leftNode.storedValue!, l, r);\n    }\n\n    private static ImmutableTree<TValue> RotateLeftRight(int hash, TValue value, ImmutableTree<TValue> left, ImmutableTree<TValue> right)\n    {\n        var l = new ImmutableTree<TValue>(left.storedHash, left.storedValue!, left.leftNode!, left.rightNode!.leftNode!);\n        var r = new ImmutableTree<TValue>(hash, value, left.rightNode.rightNode!, right);\n        return new ImmutableTree<TValue>(left.rightNode.storedHash, left.rightNode.storedValue!, l, r);\n    }\n\n    public override string ToString() => this.IsEmpty ? \"empty\" : $\"{this.storedHash} : {this.storedValue}\";\n\n\n    public IEnumerable<ReadOnlyKeyValue<int, TValue>> Walk()\n    {\n        if (this.IsEmpty)\n            yield break;\n\n        var nodes = new ImmutableTree<TValue>[this.height];\n        var currentNode = this;\n        var index = -1;\n\n        while (!currentNode!.IsEmpty || index != -1)\n        {\n            if (!currentNode.IsEmpty)\n            {\n                nodes[++index] = currentNode;\n                currentNode = currentNode.leftNode;\n            }\n            else\n            {\n                currentNode = nodes[index--];\n                yield return new ReadOnlyKeyValue<int, TValue>(currentNode.storedHash, currentNode.storedValue!);\n\n                currentNode = currentNode.rightNode;\n            }\n        }\n    }\n}\n\ninternal class ImmutableTreeDebugView<TValue>\n{\n    private readonly ImmutableTree<TValue> tree;\n\n    public ImmutableTreeDebugView(ImmutableTree<TValue> tree) { this.tree = tree; }\n\n    [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]\n    public ReadOnlyKeyValue<int, TValue>[] Items => tree.Walk().ToArray();\n}\n\n[DebuggerTypeProxy(typeof(ImmutableTreeDebugView<,>))]\ninternal sealed class ImmutableTree<TKey, TValue>\n    where TKey : class\n{\n    public static readonly ImmutableTree<TKey, TValue> Empty = new();\n\n    private readonly int height;\n    private readonly int storedHash;\n    private readonly TKey? storedKey;\n    private readonly TValue? storedValue;\n    private readonly ImmutableTree<TKey, TValue>? leftNode;\n    private readonly ImmutableTree<TKey, TValue>? rightNode;\n    private readonly ImmutableBucket<TKey, TValue>? collisions;\n\n    public readonly bool IsEmpty = true;\n\n    private ImmutableTree(int hash, TKey key, TValue value, ImmutableTree<TKey, TValue> left,\n        ImmutableTree<TKey, TValue> right, ImmutableBucket<TKey, TValue> collisions)\n    {\n        this.collisions = collisions;\n        this.storedKey = key;\n        this.storedHash = hash;\n        this.leftNode = left;\n        this.rightNode = right;\n        this.storedValue = value;\n        this.IsEmpty = false;\n        this.height = 1 + (left.height > right.height ? left.height : right.height);\n    }\n\n    private ImmutableTree()\n    { }\n\n    private ImmutableTree(int hash, TKey key, TValue value)\n    {\n        this.storedKey = key;\n        this.storedHash = hash;\n        this.leftNode = Empty;\n        this.rightNode = Empty;\n        this.storedValue = value;\n        this.IsEmpty = false;\n        this.height = 1;\n    }\n\n    public ImmutableTree<TKey, TValue> AddOrUpdate(TKey key, TValue value, bool byRef, Func<TValue, TValue, TValue>? updateDelegate = null) =>\n        this.AddOrUpdate(byRef ? RuntimeHelpers.GetHashCode(key) : key.GetHashCode(), key, value, byRef, updateDelegate, false);\n\n    public ImmutableTree<TKey, TValue> AddOrUpdate(TKey key, TValue value, bool byRef, bool forceUpdate) =>\n        this.AddOrUpdate(byRef ? RuntimeHelpers.GetHashCode(key) : key.GetHashCode(), key, value, byRef, null, forceUpdate);\n\n    public ImmutableTree<TKey, TValue> UpdateIfExists(TKey key, bool byRef, Func<TValue, TValue> updateDelegate) =>\n        this.UpdateIfExists(byRef ? RuntimeHelpers.GetHashCode(key) : key.GetHashCode(), key, byRef, updateDelegate);\n\n    public ImmutableTree<TKey, TValue> UpdateIfExists(TKey key, TValue value, bool byRef) =>\n        this.UpdateIfExists(byRef ? RuntimeHelpers.GetHashCode(key) : key.GetHashCode(), key, byRef, value);\n\n    [MethodImpl(Constants.Inline)]\n    public TValue? GetOrDefaultByValue(TKey key)\n    {\n        if (this.IsEmpty)\n            return default;\n\n        var hash = key.GetHashCode();\n        var node = this;\n        while (!node!.IsEmpty && node.storedHash != hash)\n            node = hash < node.storedHash ? node.leftNode : node.rightNode;\n        return !node.IsEmpty && Equals(key, node.storedKey)\n            ? node.storedValue\n            : node.collisions == null\n                ? default\n                : node.collisions.GetOrDefaultByValue(key);\n    }\n\n    [MethodImpl(Constants.Inline)]\n    public TValue? GetOrDefaultByRef(TKey key)\n    {\n        if (this.IsEmpty)\n            return default;\n\n        var hash = RuntimeHelpers.GetHashCode(key);\n        var node = this;\n        while (!node!.IsEmpty && node.storedHash != hash)\n            node = hash < node.storedHash ? node.leftNode : node.rightNode;\n        return !node.IsEmpty && ReferenceEquals(key, node.storedKey)\n            ? node.storedValue\n            : node.collisions == null\n                ? default\n                : node.collisions.GetOrDefaultByRef(key);\n    }\n    \n    public ImmutableTree<TKey, TValue> Remove(TKey key, bool byRef) => \n        this.Remove(byRef ? RuntimeHelpers.GetHashCode(key) : key.GetHashCode(), key, byRef);\n\n    private ImmutableTree<TKey, TValue> AddOrUpdate(int hash, TKey key, TValue value, bool byRef, Func<TValue, TValue, TValue>? updateDelegate, bool forceUpdate)\n    {\n        if (this.IsEmpty)\n            return new ImmutableTree<TKey, TValue>(hash, key, value);\n\n        if (hash == this.storedHash)\n            return this.CheckCollision(hash, key, value, byRef, updateDelegate, forceUpdate);\n\n        if (hash < this.storedHash)\n        {\n            if (this.height == 1)\n                return new ImmutableTree<TKey, TValue>(this.storedHash, this.storedKey!, this.storedValue!,\n                    new ImmutableTree<TKey, TValue>(hash, key, value), this.rightNode!, this.collisions!);\n\n            var left = this.leftNode!.AddOrUpdate(hash, key, value, byRef, updateDelegate, forceUpdate);\n            return ReferenceEquals(left, this.leftNode)\n                ? this\n                : Balance(this.storedHash, this.storedKey!, this.storedValue!, left, this.rightNode!, this.collisions!);\n        }\n\n\n        if (this.height == 1)\n            return new ImmutableTree<TKey, TValue>(this.storedHash, this.storedKey!, this.storedValue!, this.leftNode!,\n                new ImmutableTree<TKey, TValue>(hash, key, value), this.collisions!);\n\n        var right = this.rightNode!.AddOrUpdate(hash, key, value, byRef, updateDelegate, forceUpdate);\n        return ReferenceEquals(right, this.rightNode)\n            ? this\n            : Balance(this.storedHash, this.storedKey!, this.storedValue!, this.leftNode!, right, this.collisions!);\n    }\n\n    private ImmutableTree<TKey, TValue> UpdateIfExists(int hash, TKey key, bool byRef, Func<TValue, TValue> updateDelegate)\n    {\n        if (this.IsEmpty) return this;\n\n        if (hash == this.storedHash)\n            return this.ReplaceInCollisionsIfExist(hash, key, byRef, updateDelegate);\n\n        if (hash < this.storedHash)\n        {\n            var left = this.leftNode!.UpdateIfExists(hash, key, byRef, updateDelegate);\n            if (ReferenceEquals(left, this.leftNode))\n                return this;\n\n            return new ImmutableTree<TKey, TValue>(this.storedHash, this.storedKey!,\n                this.storedValue!, left, this.rightNode!, this.collisions!);\n        }\n\n        var right = this.rightNode!.UpdateIfExists(hash, key, byRef, updateDelegate);\n        if (ReferenceEquals(right, this.rightNode))\n            return this;\n\n        return new ImmutableTree<TKey, TValue>(this.storedHash, this.storedKey!,\n            this.storedValue!, this.leftNode!, right, this.collisions!);\n    }\n\n    private ImmutableTree<TKey, TValue> UpdateIfExists(int hash, TKey key, bool byRef, TValue value)\n    {\n        if (this.IsEmpty)\n            return this;\n\n        if (hash == this.storedHash)\n            return this.ReplaceInCollisionsIfExist(hash, key, value, byRef);\n\n        if (hash < this.storedHash)\n        {\n            var left = this.leftNode!.UpdateIfExists(hash, key, byRef, value);\n            if (ReferenceEquals(left, this.leftNode))\n                return this;\n\n            return new ImmutableTree<TKey, TValue>(this.storedHash, this.storedKey!,\n                this.storedValue!, left, this.rightNode!, this.collisions!);\n        }\n\n        var right = this.rightNode!.UpdateIfExists(hash, key, byRef, value);\n        if (ReferenceEquals(right, this.rightNode))\n            return this;\n\n        return new ImmutableTree<TKey, TValue>(this.storedHash, this.storedKey!,\n            this.storedValue!, this.leftNode!, right, this.collisions!);\n    }\n\n    private ImmutableTree<TKey, TValue> Remove(int hash, TKey key, bool byRef)\n    {\n        if (this.IsEmpty) return this;\n\n        if (hash != this.storedHash)\n            return hash < this.storedHash\n                ? Balance(this.storedHash, this.storedKey!, this.storedValue!, this.leftNode!.Remove(hash, key, byRef), this.rightNode!,\n                    this.collisions!)\n                : Balance(this.storedHash, this.storedKey!, this.storedValue!, this.leftNode!, this.rightNode!.Remove(hash, key, byRef),\n                    this.collisions!);\n        \n        if (byRef && ReferenceEquals(key, this.storedKey) || !byRef && Equals(key, this.storedKey))\n        {\n            if (this.collisions is { Length: > 0 })\n            {\n                var first = this.collisions.Repository[0];\n                return new ImmutableTree<TKey, TValue>(hash, first.Key, first.Value, this.leftNode!, this.rightNode!,\n                    this.collisions.RemoveFirst());\n            }\n            \n            if (this.height == 1) return Empty;\n            if (this.rightNode!.IsEmpty) return this.leftNode!;\n            if (this.leftNode!.IsEmpty) return this.rightNode!;\n\n            var next = this.rightNode;\n            while (!next.leftNode!.IsEmpty) next = next.leftNode;\n            return new ImmutableTree<TKey, TValue>(next.storedHash, next.storedKey!, next.storedValue!,\n                this.leftNode!, this.rightNode!.Remove(next.storedHash, next.storedKey!, byRef), next.collisions!);\n        }\n\n        if (this.collisions != null)\n            return new ImmutableTree<TKey, TValue>(this.storedHash, this.storedKey!, this.storedValue!,\n                this.leftNode!, this.rightNode!, this.collisions.Remove(key, byRef));\n            \n        return this;\n    }\n\n    private ImmutableTree<TKey, TValue> CheckCollision(int hash, TKey key, TValue value, bool byRef, Func<TValue, TValue, TValue>? updateDelegate, bool forceUpdate)\n    {\n        if (byRef && ReferenceEquals(key, this.storedKey) || !byRef && Equals(key, this.storedKey))\n        {\n            if (forceUpdate)\n                return new ImmutableTree<TKey, TValue>(hash, key, value, this.leftNode!, this.rightNode!, this.collisions!);\n\n            if (updateDelegate == null) return this;\n\n            var newValue = updateDelegate(this.storedValue!, value);\n            return ReferenceEquals(newValue, this.storedValue)\n                ? this\n                : new ImmutableTree<TKey, TValue>(hash, key, newValue, this.leftNode!, this.rightNode!, this.collisions!);\n        }\n\n        if (this.collisions == null)\n            return new ImmutableTree<TKey, TValue>(hash, this.storedKey!, this.storedValue!, this.leftNode!, this.rightNode!,\n                ImmutableBucket<TKey, TValue>.Empty.Add(key, value));\n\n        var collision = byRef ? this.collisions.GetOrDefaultByRef(key) : this.collisions.GetOrDefaultByValue(key);\n        var @new = collision == null || updateDelegate == null || forceUpdate\n            ? value\n            : updateDelegate(collision, value);\n\n        if (ReferenceEquals(@new, collision))\n            return this;\n\n        return new ImmutableTree<TKey, TValue>(hash, this.storedKey!, this.storedValue!, this.leftNode!, this.rightNode!,\n            this.collisions.AddOrUpdate(key, @new, byRef));\n    }\n\n    private ImmutableTree<TKey, TValue> ReplaceInCollisionsIfExist(int hash, TKey key, bool byRef, Func<TValue, TValue> updateDelegate)\n    {\n        if (ReferenceEquals(key, this.storedKey))\n            return new ImmutableTree<TKey, TValue>(hash, key, updateDelegate(this.storedValue!),\n                this.leftNode!, this.rightNode!, this.collisions!);\n\n        if (this.collisions == null) return this;\n\n        var currentCollisions = this.collisions.ReplaceIfExists(key, updateDelegate, byRef);\n        if (ReferenceEquals(currentCollisions, this.collisions))\n            return this;\n\n        return new ImmutableTree<TKey, TValue>(this.storedHash, this.storedKey!,\n            this.storedValue!, this.leftNode!, this.rightNode!, currentCollisions);\n    }\n\n    private ImmutableTree<TKey, TValue> ReplaceInCollisionsIfExist(int hash, TKey key, TValue value, bool byRef)\n    {\n        if (ReferenceEquals(key, this.storedKey))\n            return new ImmutableTree<TKey, TValue>(hash, key, value,\n                this.leftNode!, this.rightNode!, this.collisions!);\n\n        if (this.collisions == null) return this;\n\n        var currentCollisions = this.collisions.ReplaceIfExists(key, value, byRef);\n        if (ReferenceEquals(currentCollisions, this.collisions))\n            return this;\n\n        return new ImmutableTree<TKey, TValue>(this.storedHash, this.storedKey!,\n            this.storedValue!, this.leftNode!, this.rightNode!, currentCollisions);\n    }\n\n    private static ImmutableTree<TKey, TValue> Balance(int hash, TKey key, TValue value, ImmutableTree<TKey, TValue> left, ImmutableTree<TKey, TValue> right, ImmutableBucket<TKey, TValue> collisions)\n    {\n        var balance = left.height - right.height;\n\n        return balance switch\n        {\n            >= 2 => left.leftNode!.height - left.rightNode!.height == -1\n                ? RotateLeftRight(hash, key, value, left, right, collisions)\n                : RotateRight(hash, key, value, left, right, collisions),\n            <= -2 => right.leftNode!.height - right.rightNode!.height == 1\n                ? RotateRightLeft(hash, key, value, left, right, collisions)\n                : RotateLeft(hash, key, value, left, right, collisions),\n            _ => new ImmutableTree<TKey, TValue>(hash, key, value, left, right, collisions)\n        };\n    }\n\n    private static ImmutableTree<TKey, TValue> RotateRight(int hash, TKey key, TValue value, ImmutableTree<TKey, TValue> left, ImmutableTree<TKey, TValue> right, ImmutableBucket<TKey, TValue> collisions)\n    {\n        var r = new ImmutableTree<TKey, TValue>(hash, key, value, left.rightNode!, right, collisions);\n        return new ImmutableTree<TKey, TValue>(left.storedHash, left.storedKey!, left.storedValue!, left.leftNode!, r, left.collisions!);\n    }\n\n    private static ImmutableTree<TKey, TValue> RotateLeft(int hash, TKey key, TValue value, ImmutableTree<TKey, TValue> left, ImmutableTree<TKey, TValue> right, ImmutableBucket<TKey, TValue> collisions)\n    {\n        var l = new ImmutableTree<TKey, TValue>(hash, key, value, left, right.leftNode!, collisions);\n        return new ImmutableTree<TKey, TValue>(right.storedHash, right.storedKey!, right.storedValue!, l, right.rightNode!, right.collisions!);\n    }\n\n    private static ImmutableTree<TKey, TValue> RotateRightLeft(int hash, TKey key, TValue value, ImmutableTree<TKey, TValue> left, ImmutableTree<TKey, TValue> right, ImmutableBucket<TKey, TValue> collisions)\n    {\n        var l = new ImmutableTree<TKey, TValue>(hash, key, value, left, right.leftNode!.leftNode!, collisions);\n        var r = new ImmutableTree<TKey, TValue>(right.storedHash, right.storedKey!, right.storedValue!, right.leftNode.rightNode!, right.rightNode!, right.collisions!);\n        return new ImmutableTree<TKey, TValue>(right.leftNode.storedHash, right.leftNode.storedKey!, right.leftNode.storedValue!, l, r, right.leftNode.collisions!);\n    }\n\n    private static ImmutableTree<TKey, TValue> RotateLeftRight(int hash, TKey key, TValue value, ImmutableTree<TKey, TValue> left, ImmutableTree<TKey, TValue> right, ImmutableBucket<TKey, TValue> collisions)\n    {\n        var l = new ImmutableTree<TKey, TValue>(left.storedHash, left.storedKey!, left.storedValue!, left.leftNode!, left.rightNode!.leftNode!, left.collisions!);\n        var r = new ImmutableTree<TKey, TValue>(hash, key, value, left.rightNode.rightNode!, right, collisions);\n        return new ImmutableTree<TKey, TValue>(left.rightNode.storedHash, left.rightNode.storedKey!, left.rightNode.storedValue!, l, r, left.rightNode.collisions!);\n    }\n\n    public override string ToString() => this.IsEmpty ? \"empty\" : $\"{this.storedKey} : {this.storedValue}\";\n\n    public IEnumerable<ReadOnlyKeyValue<TKey, TValue>> Walk()\n    {\n        if (this.IsEmpty)\n            yield break;\n\n        var nodes = new ImmutableTree<TKey, TValue>[this.height];\n        var currentNode = this;\n        var index = -1;\n\n        while (!currentNode!.IsEmpty || index != -1)\n        {\n            if (!currentNode.IsEmpty)\n            {\n                nodes[++index] = currentNode;\n                currentNode = currentNode.leftNode;\n            }\n            else\n            {\n                currentNode = nodes[index--];\n                yield return new ReadOnlyKeyValue<TKey, TValue>(currentNode.storedKey!, currentNode.storedValue!);\n\n                if (currentNode.collisions != null)\n                    foreach (var keyValue in currentNode.collisions.Repository)\n                        yield return keyValue;\n\n                currentNode = currentNode.rightNode;\n            }\n        }\n    }\n}\n\ninternal class ImmutableTreeDebugView<TKey, TValue> where TKey : class\n{\n    private readonly ImmutableTree<TKey, TValue> tree;\n\n    public ImmutableTreeDebugView(ImmutableTree<TKey, TValue> tree) { this.tree = tree; }\n\n    [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]\n    public ReadOnlyKeyValue<TKey, TValue>[] Items => tree.Walk().ToArray();\n}\n\n[DebuggerTypeProxy(typeof(ImmutableRefTreeDebugView<>))]\ninternal sealed class ImmutableRefTree<TValue>\n    where TValue : class\n{\n    public static readonly ImmutableRefTree<TValue> Empty = new();\n\n    private readonly int height;\n    private readonly int storedHash;\n    private readonly TValue? storedValue;\n    private readonly ImmutableRefTree<TValue>? leftNode;\n    private readonly ImmutableRefTree<TValue>? rightNode;\n    private readonly ImmutableBucket<TValue>? collisions;\n\n    public readonly bool IsEmpty = true;\n\n    private ImmutableRefTree(int hash, TValue value, ImmutableRefTree<TValue> left,\n        ImmutableRefTree<TValue> right, ImmutableBucket<TValue> collisions)\n    {\n        this.collisions = collisions;\n        this.storedHash = hash;\n        this.leftNode = left;\n        this.rightNode = right;\n        this.storedValue = value;\n        this.IsEmpty = false;\n        this.height = 1 + (left.height > right.height ? left.height : right.height);\n    }\n\n    private ImmutableRefTree()\n    { }\n\n    private ImmutableRefTree(int hash, TValue value)\n    {\n        this.storedHash = hash;\n        this.leftNode = Empty;\n        this.rightNode = Empty;\n        this.storedValue = value;\n        this.IsEmpty = false;\n        this.height = 1;\n    }\n\n    public ImmutableRefTree<TValue> AddOrSkip(TValue value) =>\n        this.AddOrUpdate(RuntimeHelpers.GetHashCode(value), value);\n    \n    public ImmutableRefTree<TValue> Remove(TValue value) => \n        this.Remove(RuntimeHelpers.GetHashCode(value), value);\n\n    private ImmutableRefTree<TValue> AddOrUpdate(int hash, TValue value)\n    {\n        if (this.IsEmpty)\n            return new ImmutableRefTree<TValue>(hash, value);\n\n        if (hash == this.storedHash)\n            return this.CheckCollision(hash, value);\n\n        if (hash < this.storedHash)\n        {\n            if (this.height == 1)\n                return new ImmutableRefTree<TValue>(this.storedHash, this.storedValue!,\n                    new ImmutableRefTree<TValue>(hash, value), this.rightNode!, this.collisions!);\n\n            var left = this.leftNode!.AddOrUpdate(hash, value);\n            return ReferenceEquals(left, this.leftNode)\n                ? this\n                : Balance(this.storedHash, this.storedValue!, left, this.rightNode!, this.collisions!);\n        }\n\n\n        if (this.height == 1)\n            return new ImmutableRefTree<TValue>(this.storedHash, this.storedValue!, this.leftNode!,\n                new ImmutableRefTree<TValue>(hash, value), this.collisions!);\n\n        var right = this.rightNode!.AddOrUpdate(hash, value);\n        return ReferenceEquals(right, this.rightNode)\n            ? this\n            : Balance(this.storedHash, this.storedValue!, this.leftNode!, right, this.collisions!);\n    }\n\n    private ImmutableRefTree<TValue> Remove(int hash, TValue value)\n    {\n        if (this.IsEmpty) return this;\n\n        if (hash != this.storedHash)\n            return hash < this.storedHash\n                ? Balance(this.storedHash, this.storedValue!, this.leftNode!.Remove(hash, value), this.rightNode!,\n                    this.collisions!)\n                : Balance(this.storedHash, this.storedValue!, this.leftNode!, this.rightNode!.Remove(hash, value),\n                    this.collisions!);\n        \n        if (ReferenceEquals(value, this.storedValue))\n        {\n            if (this.height == 1) return Empty;\n            if (this.rightNode!.IsEmpty) return this.leftNode!;\n            if (this.leftNode!.IsEmpty) return this.rightNode!;\n\n            var next = this.rightNode;\n            while (!next.leftNode!.IsEmpty) next = next.leftNode;\n            return new ImmutableRefTree<TValue>(next.storedHash, next.storedValue!,\n                this.leftNode!, this.rightNode!.Remove(next.storedHash, next.storedValue!), next.collisions!);\n        }\n\n        if (this.collisions != null)\n            return new ImmutableRefTree<TValue>(this.storedHash, this.storedValue!,\n                this.leftNode!, this.rightNode!, this.collisions.Remove(value));\n            \n        return this;\n    }\n\n    private ImmutableRefTree<TValue> CheckCollision(int hash, TValue value)\n    {\n        if (ReferenceEquals(value, this.storedValue)) return this;\n\n        if (this.collisions == null)\n            return new ImmutableRefTree<TValue>(hash, value, this.leftNode!, this.rightNode!,\n                ImmutableBucket<TValue>.Empty.Add(value));\n\n        return new ImmutableRefTree<TValue>(hash, value, this.leftNode!, this.rightNode!,\n            this.collisions.AddIfNotExist(value));\n    }\n    \n    private static ImmutableRefTree<TValue> Balance(int hash, TValue value, ImmutableRefTree<TValue> left, ImmutableRefTree<TValue> right, ImmutableBucket<TValue> collisions)\n    {\n        var balance = left.height - right.height;\n\n        return balance switch\n        {\n            >= 2 => left.leftNode!.height - left.rightNode!.height == -1\n                ? RotateLeftRight(hash, value, left, right, collisions)\n                : RotateRight(hash, value, left, right, collisions),\n            <= -2 => right.leftNode!.height - right.rightNode!.height == 1\n                ? RotateRightLeft(hash, value, left, right, collisions)\n                : RotateLeft(hash, value, left, right, collisions),\n            _ => new ImmutableRefTree<TValue>(hash, value, left, right, collisions)\n        };\n    }\n\n    private static ImmutableRefTree<TValue> RotateRight(int hash, TValue value, ImmutableRefTree<TValue> left, ImmutableRefTree<TValue> right, ImmutableBucket<TValue> collisions)\n    {\n        var r = new ImmutableRefTree<TValue>(hash, value, left.rightNode!, right, collisions);\n        return new ImmutableRefTree<TValue>(left.storedHash, left.storedValue!, left.leftNode!, r, left.collisions!);\n    }\n\n    private static ImmutableRefTree<TValue> RotateLeft(int hash, TValue value, ImmutableRefTree<TValue> left, ImmutableRefTree<TValue> right, ImmutableBucket<TValue> collisions)\n    {\n        var l = new ImmutableRefTree<TValue>(hash, value, left, right.leftNode!, collisions);\n        return new ImmutableRefTree<TValue>(right.storedHash, right.storedValue!, l, right.rightNode!, right.collisions!);\n    }\n\n    private static ImmutableRefTree<TValue> RotateRightLeft(int hash, TValue value, ImmutableRefTree<TValue> left, ImmutableRefTree<TValue> right, ImmutableBucket<TValue> collisions)\n    {\n        var l = new ImmutableRefTree<TValue>(hash, value, left, right.leftNode!.leftNode!, collisions);\n        var r = new ImmutableRefTree<TValue>(right.storedHash, right.storedValue!, right.leftNode.rightNode!, right.rightNode!, right.collisions!);\n        return new ImmutableRefTree<TValue>(right.leftNode.storedHash, right.leftNode.storedValue!, l, r, right.leftNode.collisions!);\n    }\n\n    private static ImmutableRefTree<TValue> RotateLeftRight(int hash, TValue value, ImmutableRefTree<TValue> left, ImmutableRefTree<TValue> right, ImmutableBucket<TValue> collisions)\n    {\n        var l = new ImmutableRefTree<TValue>(left.storedHash, left.storedValue!, left.leftNode!, left.rightNode!.leftNode!, left.collisions!);\n        var r = new ImmutableRefTree<TValue>(hash, value, left.rightNode.rightNode!, right, collisions);\n        return new ImmutableRefTree<TValue>(left.rightNode.storedHash, left.rightNode.storedValue!, l, r, left.rightNode.collisions!);\n    }\n\n    public override string ToString() => this.IsEmpty ? \"empty\" : $\"{this.storedValue}\";\n\n    public IEnumerable<TValue> Walk()\n    {\n        if (this.IsEmpty)\n            yield break;\n\n        var nodes = new ImmutableRefTree<TValue>[this.height];\n        var currentNode = this;\n        var index = -1;\n\n        while (!currentNode!.IsEmpty || index != -1)\n        {\n            if (!currentNode.IsEmpty)\n            {\n                nodes[++index] = currentNode;\n                currentNode = currentNode.leftNode;\n            }\n            else\n            {\n                currentNode = nodes[index--];\n                yield return currentNode.storedValue!;\n\n                if (currentNode.collisions != null)\n                    foreach (var keyValue in currentNode.collisions.Repository)\n                        yield return keyValue;\n\n                currentNode = currentNode.rightNode;\n            }\n        }\n    }\n}\n\ninternal class ImmutableRefTreeDebugView<TValue> where TValue : class\n{\n    private readonly ImmutableRefTree<TValue> tree;\n\n    public ImmutableRefTreeDebugView(ImmutableRefTree<TValue> tree) { this.tree = tree; }\n\n    [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]\n    public TValue[] Items => tree.Walk().ToArray();\n}\n"
  },
  {
    "path": "src/Utils/Data/Pair.cs",
    "content": "﻿namespace Stashbox.Utils.Data;\n\ninternal class Pair<T1, T2>\n{\n    public T1 I1;\n\n    public T2 I2;\n\n    public Pair(T1 item1, T2 item2)\n    {\n        this.I1 = item1;\n        this.I2 = item2;\n    }\n}"
  },
  {
    "path": "src/Utils/Data/Stack.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\n#nullable disable\n\nnamespace Stashbox.Utils.Data;\n\ninternal class Stack<TValue> : ExpandableArray<TValue>\n{\n    public static Stack<TValue> FromEnumerable(IEnumerable<TValue> enumerable) =>\n        new(enumerable);\n\n    public Stack()\n    { }\n\n    public Stack(IEnumerable<TValue> initial)\n        : base(initial.CastToArray())\n    { }\n\n    public TValue Pop()\n    {\n        if (this.Length == 0)\n            return default;\n\n        var result = base.Repository[this.Length - 1];\n        base.Repository[--this.Length] = default;\n        return result;\n    }\n\n    public TValue Front() => this.Length == 0 ? default : base.Repository[this.Length - 1];\n\n    public void PushBack(TValue item)\n    {\n        if (this.Length == 0)\n        {\n            this.Length = 1;\n            this.Repository = [item];\n            return;\n        }\n\n        this.EnsureSize();\n        var newArray = new TValue[this.Length];\n        newArray[0] = item;\n        Array.Copy(this.Repository, 0, newArray, 1, this.Length - 1);\n        this.Repository = newArray;\n    }\n\n    public TValue PeekBack() => this.Length == 0 ? default : this.Repository[0];\n\n    public void ReplaceBack(TValue value) => this.Repository[0] = value;\n}"
  },
  {
    "path": "src/Utils/Data/Tree.cs",
    "content": "﻿using System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Linq;\nusing System.Runtime.CompilerServices;\n\nnamespace Stashbox.Utils.Data;\n\n[DebuggerTypeProxy(typeof(TreeDebugView<>))]\ninternal sealed class Tree<TValue>\n{\n    private class Node\n    {\n        public readonly int StoredKey;\n        public TValue StoredValue;\n        public Node? Left;\n        public Node? Right;\n        public int Height;\n\n        public Node(int key, TValue value)\n        {\n            this.StoredValue = value;\n            this.StoredKey = key;\n            this.Height = 1;\n        }\n    }\n\n    private Node? root;\n\n    public bool IsEmpty => this.root == null;\n\n    public void Add(int key, TValue value)\n    {\n        this.root = Add(this.root, key, value);\n    }\n\n    [MethodImpl(Constants.Inline)]\n    public TValue? GetOrDefault(int key)\n    {\n        if (this.root == null)\n            return default;\n\n        var node = root;\n        while (node != null && node.StoredKey != key)\n            node = key < node.StoredKey ? node.Left : node.Right;\n        return node == null ? default : node.StoredValue;\n    }\n\n    private static int CalculateHeight(Node node)\n    {\n        if (node is { Left: not null, Right: not null })\n            return 1 + (node.Left.Height > node.Right.Height ? node.Left.Height : node.Right.Height);\n\n        if (node.Left == null && node.Right == null)\n            return 1;\n\n        return 1 + (node.Left?.Height ?? node.Right!.Height);\n    }\n\n    private static int GetBalance(Node node)\n    {\n        if (node is { Left: not null, Right: not null })\n            return node.Left.Height - node.Right.Height;\n\n        if (node.Left == null && node.Right == null)\n            return 0;\n\n        return node.Left?.Height ?? node.Right!.Height * -1;\n    }\n\n    private static Node RotateLeft(Node node)\n    {\n        var current = node.Right;\n        var left = current!.Left;\n\n        current.Left = node;\n        node.Right = left;\n\n        node.Height = CalculateHeight(node);\n        current.Height = CalculateHeight(current);\n\n        return current;\n    }\n\n    private static Node RotateRight(Node node)\n    {\n        var current = node.Left;\n        var right = current!.Right;\n\n        current.Right = node;\n        node.Left = right;\n\n        node.Height = CalculateHeight(node);\n        current.Height = CalculateHeight(current);\n\n        return current;\n    }\n\n    private static Node Add(Node? node, int key, TValue value)\n    {\n        if (node == null)\n            return new Node(key, value);\n\n        if (node.StoredKey == key)\n        {\n            node.StoredValue = value;\n            return node;\n        }\n\n        if (node.StoredKey > key)\n            node.Left = Add(node.Left, key, value);\n        else\n            node.Right = Add(node.Right, key, value);\n\n        node.Height = CalculateHeight(node);\n        var balance = GetBalance(node);\n\n        switch (balance)\n        {\n            case >= 2 when GetBalance(node.Left!) == -1:\n                node.Left = RotateLeft(node.Left!);\n                node = RotateRight(node);\n                break;\n            case >= 2:\n                node = RotateRight(node);\n                break;\n            case <= -2 when GetBalance(node.Right!) == 1:\n                node.Right = RotateRight(node.Right!);\n                node = RotateLeft(node);\n                break;\n            case <= -2:\n                node = RotateLeft(node);\n                break;\n        }\n\n        return node;\n    }\n\n    public IEnumerable<TValue> Walk()\n    {\n        if (this.root == null)\n            yield break;\n\n        switch (this.root.Height)\n        {\n            case 1:\n                yield return this.root.StoredValue;\n                break;\n            case 2:\n                if (this.root.Left != null)\n                    yield return this.root.Left.StoredValue;\n                yield return this.root.StoredValue;\n                if (this.root.Right != null)\n                    yield return this.root.Right.StoredValue;\n                break;\n            default:\n            {\n                var nodes = new Node[this.root.Height - 2];\n                var currentNode = this.root;\n                var index = -1;\n\n                while (true)\n                {\n                    if (currentNode != null)\n                    {\n                        if (currentNode.Height == 2)\n                        {\n                            if (currentNode.Left != null)\n                                yield return currentNode.Left.StoredValue;\n                            yield return currentNode.StoredValue;\n                            if (currentNode.Right != null)\n                                yield return currentNode.Right.StoredValue;\n\n                            if (index == -1)\n                                break;\n                            currentNode = nodes[index--];\n                            yield return currentNode.StoredValue;\n\n                            currentNode = currentNode.Right;\n                        }\n                        else if (currentNode.Height == 1)\n                        {\n                            yield return currentNode.StoredValue;\n\n                            if (index == -1)\n                                break;\n                            currentNode = nodes[index--];\n                            yield return currentNode.StoredValue;\n\n                            currentNode = currentNode.Right;\n                        }\n                        else\n                        {\n                            nodes[++index] = currentNode;\n                            currentNode = currentNode.Left;\n                        }\n                    }\n                    else\n                    {\n                        if (index == -1)\n                            break;\n                        currentNode = nodes[index--];\n                        yield return currentNode.StoredValue;\n\n                        currentNode = currentNode.Right;\n                    }\n\n                }\n\n                break;\n            }\n        }\n    }\n}\n\ninternal class TreeDebugView<TValue>\n{\n    private readonly Tree<TValue> tree;\n\n    public TreeDebugView(Tree<TValue> tree) { this.tree = tree; }\n\n    [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]\n    public TValue[] Items => tree.Walk().ToArray();\n}"
  },
  {
    "path": "src/Utils/Shield.cs",
    "content": "﻿using Stashbox.Exceptions;\nusing System;\n\nnamespace Stashbox.Utils;\n\n/// <summary>\n/// Represents a utility class for input validation.\n/// </summary>\npublic static class Shield\n{\n    /// <summary>\n    /// Checks the value of the given object and throws an ArgumentNullException if it == null.\n    /// </summary>\n    /// <typeparam name=\"T\">Type of the object.</typeparam>\n    /// <param name=\"obj\">The object to be checked.</param>\n    /// <param name=\"parameterName\">The name of the parameter to be checked.</param>\n    public static void EnsureNotNull<T>(T obj, string parameterName)\n    {\n        if (obj == null)\n            throw new ArgumentNullException(parameterName);\n    }\n\n    /// <summary>\n    /// Checks the value of the given object and throws an ArgumentNullException with the given message if it == null.\n    /// </summary>\n    /// <typeparam name=\"T\">Type of the object.</typeparam>\n    /// <param name=\"obj\">The object to be checked.</param>\n    /// <param name=\"parameterName\">The name of the parameter to be checked.</param>\n    /// <param name=\"message\">The message to be shown in the exception.</param>\n    public static void EnsureNotNull<T>(T obj, string parameterName, string message)\n    {\n        if (obj == null || obj.Equals(default))\n            throw new ArgumentNullException(parameterName, message);\n    }\n\n    /// <summary>\n    /// Checks the value of the given string and throws an ArgumentException if it == null or empty.\n    /// </summary>\n    /// <param name=\"obj\">The string to be checked.</param>\n    /// <param name=\"parameterName\">The name of the parameter to be checked.</param>\n    public static void EnsureNotNullOrEmpty(string obj, string parameterName)\n    {\n        if (string.IsNullOrWhiteSpace(obj))\n            throw new ArgumentException(string.Empty, parameterName);\n    }\n\n    /// <summary>\n    /// Checks two integers and throws an ArgumentException if the actual is lesser than the reference.\n    /// </summary>\n    /// <param name=\"actual\">The actual value.</param>\n    /// <param name=\"reference\">The reference value.</param>\n    public static void EnsureGreaterThan(int actual, int reference)\n    {\n        if (reference >= actual)\n            throw new ArgumentException($\"The given number is less or equal than: {reference}\");\n    }\n\n    /// <summary>\n    /// Checks a bool condition and throws an ArgumentException if it is false.\n    /// </summary>\n    /// <param name=\"condition\">The condition.</param>\n    /// <param name=\"message\">Exception message.</param>\n    public static void EnsureTrue(bool condition, string message)\n    {\n        if (!condition)\n            throw new ArgumentException(message);\n    }\n\n    /// <summary>\n    /// Checks the type of the given object and throws an ArgumentException if it doesn't matches with the given type parameter.\n    /// </summary>\n    /// <typeparam name=\"TType\">The type parameter.</typeparam>\n    /// <param name=\"obj\">The object to be checked.</param>\n    public static void EnsureTypeOf<TType>(object obj)\n    {\n        if (obj is not TType)\n            throw new ArgumentException($\"{nameof(obj)} is not {TypeCache<TType>.Type}.\", nameof(obj));\n    }\n\n    internal static void EnsureTypeMapIsValid(Type serviceType, Type implementationType)\n    {\n        EnsureIsResolvable(implementationType);\n\n        if (!implementationType.Implements(serviceType))\n            throw new InvalidRegistrationException(implementationType, $\"The type {implementationType} does not implement the service type {serviceType}.\");\n    }\n\n    internal static void EnsureIsResolvable(Type implementationType)\n    {\n        if (!implementationType.IsResolvableType())\n            throw new InvalidRegistrationException(implementationType, $\"The type {implementationType} could not be resolved. It's probably an interface, abstract class or primitive type.\");\n    }\n\n    internal static void ThrowDisposedException(string? name, string caller) =>\n        throw new ObjectDisposedException(name, $\"The member '{caller}' was called on '{name}' but it has been disposed already.\");\n}"
  },
  {
    "path": "src/Utils/Swap.cs",
    "content": "﻿using System;\nusing System.Threading;\n\nnamespace Stashbox.Utils;\n\ninternal static class Swap\n{\n    private const int MinimumSwapThreshold = 50;\n\n    public static bool SwapValue<T1, T2, T3, T4, TValue>(ref TValue refValue, Func<T1, T2, T3, T4, TValue, TValue> valueFactory, T1 t1, T2 t2, T3 t3, T4 t4)\n        where TValue : class\n    {\n        var currentValue = Volatile.Read(ref refValue);\n        var newValue = valueFactory(t1, t2, t3, t4, currentValue);\n\n        var original = Interlocked.CompareExchange(ref refValue, newValue, currentValue);\n\n        if (ReferenceEquals(original, currentValue))\n            return !ReferenceEquals(newValue, currentValue);\n\n        return RepeatSwap(ref refValue, valueFactory, t1, t2, t3, t4);\n    }\n\n    private static bool RepeatSwap<T1, T2, T3, T4, TValue>(ref TValue refValue, Func<T1, T2, T3, T4, TValue, TValue> valueFactory, T1 t1, T2 t2, T3 t3, T4 t4)\n        where TValue : class\n    {\n        var wait = new SpinWait();\n        var desiredThreshold = Environment.ProcessorCount * 6;\n        var swapThreshold = desiredThreshold <= MinimumSwapThreshold ? MinimumSwapThreshold : desiredThreshold;\n\n        while (true)\n        {\n            var currentValue = Volatile.Read(ref refValue);\n            var newValue = valueFactory(t1, t2, t3, t4, currentValue);\n\n            var original = Interlocked.CompareExchange(ref refValue, newValue, currentValue);\n\n            if (ReferenceEquals(original, currentValue))\n                return !ReferenceEquals(newValue, currentValue);\n\n            if (wait.Count > swapThreshold)\n                throw new InvalidOperationException(\"Swap quota exceeded.\");\n\n            wait.SpinOnce();\n        }\n    }\n}"
  },
  {
    "path": "src/Utils/TypeCache.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing Stashbox.Expressions.Compile;\n\nnamespace Stashbox.Utils;\n\ninternal static class TypeCache<TType>\n{\n    public static readonly Type Type = typeof(TType);\n}\n\ninternal static class TypeCache\n{\n    public static readonly Type EmptyType = TypeCache<object>.Type;\n    \n    public static readonly Type FuncType = typeof(Func<>);\n\n    public static readonly Type[] EmptyTypes = EmptyArray<Type>();\n\n    public static readonly Type VoidType = typeof(void);\n\n    public static readonly Type EnumerableType = typeof(IEnumerable<>);\n\n    public static readonly Type NullableType = typeof(Nullable<>);\n\n    public static readonly Type ExpressionEmitterType = typeof(ExpressionEmitter);\n\n    public static T[] EmptyArray<T>() => InternalArrayHelper<T>.Empty;\n\n    private static class InternalArrayHelper<T>\n    {\n#if NET5_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER\n        public static readonly T[] Empty = Array.Empty<T>();\n#else\n        public static readonly T[] Empty = new T[0];\n#endif\n    }\n}"
  },
  {
    "path": "src/stashbox.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <TargetFrameworks>net461;netstandard2.0;netstandard2.1;net5.0;net6.0;net7.0;net8.0;net9.0;net10.0</TargetFrameworks>\n    <AssemblyName>Stashbox</AssemblyName>\n    <AssemblyTitle>Stashbox</AssemblyTitle>\n    <RootNamespace>Stashbox</RootNamespace>\n    <PackageId>Stashbox</PackageId>\n    <Authors>Peter Csajtai</Authors>\n    <Company>Peter Csajtai</Company>\n    <Product>Stashbox</Product>\n    <Copyright>Copyright © Peter Csajtai 2026</Copyright>\n    <PackageLicenseExpression>MIT</PackageLicenseExpression>\n    <PackageProjectUrl>https://z4kn4fein.github.io/stashbox</PackageProjectUrl>\n    <PackageIcon>icon.png</PackageIcon>\n    <RepositoryUrl>https://github.com/z4kn4fein/stashbox</RepositoryUrl>\n    <RepositoryType>git</RepositoryType>\n    <PackageReadmeFile>README.md</PackageReadmeFile>\n    <PackageTags>Stashbox di dependency-injection ioc dotnet netstandard</PackageTags>\n    <Description>Stashbox is a lightweight, fast, and portable dependency injection framework for .NET-based solutions.</Description>\n    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>\n    <GenerateDocumentationFile>true</GenerateDocumentationFile>\n    <SignAssembly>true</SignAssembly>\n    <AssemblyOriginatorKeyFile>../sn.snk</AssemblyOriginatorKeyFile>\n    <Version>1.0.0</Version>\n    <PackageVersion>1.0.0</PackageVersion>\n    <GeneratePackageOnBuild>false</GeneratePackageOnBuild>\n    <LangVersion>latest</LangVersion>\n    <PublishRepositoryUrl>true</PublishRepositoryUrl>\n    <EmbedUntrackedSources>true</EmbedUntrackedSources>\n    <IncludeSymbols>true</IncludeSymbols>\n    <SymbolPackageFormat>snupkg</SymbolPackageFormat>\n    <PackageReleaseNotes>https://github.com/z4kn4fein/stashbox/blob/master/CHANGELOG.md</PackageReleaseNotes>\n    <Configurations>Debug;Release;Benchmark</Configurations>\n    <Nullable>enable</Nullable>\n    <NoWarn>CA1032</NoWarn>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)' == 'Benchmark'\">\n    <AssemblyName>Stashbox.Benchmark</AssemblyName>\n    <AssemblyTitle>Stashbox.Benchmark</AssemblyTitle>\n    <RootNamespace>Stashbox.Benchmark</RootNamespace>\n    <Optimize>true</Optimize>\n  </PropertyGroup>\n\n  <PropertyGroup Condition=\"'$(TargetFramework)' == 'netstandard2.0'\">\n    <AssemblyTitle>Stashbox .NET Standard 2.0</AssemblyTitle>\n    <DefineConstants>HAS_ASYNC_DISPOSABLE</DefineConstants>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(TargetFramework)' == 'netstandard2.1'\">\n    <AssemblyTitle>Stashbox .NET Standard 2.1</AssemblyTitle>\n    <DefineConstants>HAS_ASYNC_DISPOSABLE</DefineConstants>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(TargetFramework)' == 'net461'\">\n    <AssemblyTitle>Stashbox .NET 4.6.1</AssemblyTitle>\n    <DefineConstants>HAS_ASYNC_DISPOSABLE</DefineConstants>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(TargetFramework)' == 'net5.0'\">\n    <AssemblyTitle>Stashbox .NET 5.0</AssemblyTitle>\n    <DefineConstants>HAS_ASYNC_DISPOSABLE</DefineConstants>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(TargetFramework)' == 'net6.0'\">\n    <AssemblyTitle>Stashbox .NET 6.0</AssemblyTitle>\n    <DefineConstants>HAS_ASYNC_DISPOSABLE</DefineConstants>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(TargetFramework)' == 'net7.0'\">\n    <AssemblyTitle>Stashbox .NET 7.0</AssemblyTitle>\n    <DefineConstants>HAS_ASYNC_DISPOSABLE;HAS_REQUIRED</DefineConstants>\n  </PropertyGroup>\n\n  <PropertyGroup Condition=\"'$(TargetFramework)' == 'net8.0'\">\n    <AssemblyTitle>Stashbox .NET 8.0</AssemblyTitle>\n    <DefineConstants>HAS_ASYNC_DISPOSABLE;HAS_REQUIRED</DefineConstants>\n  </PropertyGroup>\n\n  <PropertyGroup Condition=\"'$(TargetFramework)' == 'net9.0'\">\n    <AssemblyTitle>Stashbox .NET 9.0</AssemblyTitle>\n    <DefineConstants>HAS_ASYNC_DISPOSABLE;HAS_REQUIRED</DefineConstants>\n  </PropertyGroup>\n\n  <PropertyGroup Condition=\"'$(TargetFramework)' == 'net10.0'\">\n    <AssemblyTitle>Stashbox .NET 10.0</AssemblyTitle>\n    <DefineConstants>HAS_ASYNC_DISPOSABLE;HAS_REQUIRED</DefineConstants>\n  </PropertyGroup>\n\n  <ItemGroup Condition=\"'$(TargetFramework)' == 'netstandard2.0'\">\n    <PackageReference Include=\"System.Reflection.Emit.Lightweight\" Version=\"4.7.0\" />\n  </ItemGroup>\n  \n  <ItemGroup Condition=\"'$(TargetFramework)' == 'net461' Or '$(TargetFramework)' == 'netstandard2.0'\">\n    <PackageReference Include=\"Microsoft.Bcl.AsyncInterfaces\" Version=\"6.0.0\" />\n  </ItemGroup>\n\t\n  <ItemGroup Condition=\"'$(TargetFramework)' == 'net461'\">\n    <PackageReference Include=\"System.ValueTuple\" Version=\"4.5.0\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.SourceLink.GitHub\" Version=\"8.0.0\" PrivateAssets=\"All\" />\n    <PackageReference Include=\"SauceControl.InheritDoc\" Version=\"2.0.2\" PrivateAssets=\"all\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <InternalsVisibleTo Include=\"Stashbox.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f54f3fc3580d2301f3aa4c3c6d28c2e419687f23392a4c0f543c17232c8c1640a12a0ebeae2ed5c59cf7443100718480a19c7fd62ab8225b40741179c6ad8c17e6dbb8d6e4d98255c6364ca6ca541148b11d7c72f74919d283f2536f52750b7e0a69d9f416e4a4eed49a38547daee8d11ca1dca646f6eb519ba5c2faeff7d7b0\" />\n    <InternalsVisibleTo Include=\"Stashbox.Benchmarks, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f54f3fc3580d2301f3aa4c3c6d28c2e419687f23392a4c0f543c17232c8c1640a12a0ebeae2ed5c59cf7443100718480a19c7fd62ab8225b40741179c6ad8c17e6dbb8d6e4d98255c6364ca6ca541148b11d7c72f74919d283f2536f52750b7e0a69d9f416e4a4eed49a38547daee8d11ca1dca646f6eb519ba5c2faeff7d7b0\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <None Include=\"..\\LICENSE\" />\n    <None Include=\"..\\assets\\icon.png\" Pack=\"true\" PackagePath=\"\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <None Include=\"..\\.github\\workflows\\*.yml\" />\n    <None Include=\"..\\.version\" />\n    <None Include=\"..\\appveyor.yml\" />\n    <None Include=\"..\\appveyor-release.yml\" />\n    <None Include=\"..\\README.md\" Pack=\"true\" PackagePath=\"\" />\n    <None Include=\"..\\CHANGELOG.md\" />\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "stashbox.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 17\nVisualStudioVersion = 17.0.31903.59\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"stashbox\", \"src\\stashbox.csproj\", \"{21317234-0499-4178-BCA5-558FBA2CB9AC}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"stashbox.tests\", \"test\\stashbox.tests.csproj\", \"{C7625187-F112-4928-8B73-2EA175E32204}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"testassembly\", \"test\\testassembly\\testassembly.csproj\", \"{FE845F24-9A71-4FB4-88F7-EE36598C3D90}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tDebug|x64 = Debug|x64\n\t\tDebug|x86 = Debug|x86\n\t\tRelease|Any CPU = Release|Any CPU\n\t\tRelease|x64 = Release|x64\n\t\tRelease|x86 = Release|x86\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{21317234-0499-4178-BCA5-558FBA2CB9AC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{21317234-0499-4178-BCA5-558FBA2CB9AC}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{21317234-0499-4178-BCA5-558FBA2CB9AC}.Debug|x64.ActiveCfg = Debug|Any CPU\n\t\t{21317234-0499-4178-BCA5-558FBA2CB9AC}.Debug|x64.Build.0 = Debug|Any CPU\n\t\t{21317234-0499-4178-BCA5-558FBA2CB9AC}.Debug|x86.ActiveCfg = Debug|Any CPU\n\t\t{21317234-0499-4178-BCA5-558FBA2CB9AC}.Debug|x86.Build.0 = Debug|Any CPU\n\t\t{21317234-0499-4178-BCA5-558FBA2CB9AC}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{21317234-0499-4178-BCA5-558FBA2CB9AC}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{21317234-0499-4178-BCA5-558FBA2CB9AC}.Release|x64.ActiveCfg = Release|Any CPU\n\t\t{21317234-0499-4178-BCA5-558FBA2CB9AC}.Release|x64.Build.0 = Release|Any CPU\n\t\t{21317234-0499-4178-BCA5-558FBA2CB9AC}.Release|x86.ActiveCfg = Release|Any CPU\n\t\t{21317234-0499-4178-BCA5-558FBA2CB9AC}.Release|x86.Build.0 = Release|Any CPU\n\t\t{C7625187-F112-4928-8B73-2EA175E32204}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{C7625187-F112-4928-8B73-2EA175E32204}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{C7625187-F112-4928-8B73-2EA175E32204}.Debug|x64.ActiveCfg = Debug|Any CPU\n\t\t{C7625187-F112-4928-8B73-2EA175E32204}.Debug|x64.Build.0 = Debug|Any CPU\n\t\t{C7625187-F112-4928-8B73-2EA175E32204}.Debug|x86.ActiveCfg = Debug|Any CPU\n\t\t{C7625187-F112-4928-8B73-2EA175E32204}.Debug|x86.Build.0 = Debug|Any CPU\n\t\t{C7625187-F112-4928-8B73-2EA175E32204}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{C7625187-F112-4928-8B73-2EA175E32204}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{C7625187-F112-4928-8B73-2EA175E32204}.Release|x64.ActiveCfg = Release|Any CPU\n\t\t{C7625187-F112-4928-8B73-2EA175E32204}.Release|x64.Build.0 = Release|Any CPU\n\t\t{C7625187-F112-4928-8B73-2EA175E32204}.Release|x86.ActiveCfg = Release|Any CPU\n\t\t{C7625187-F112-4928-8B73-2EA175E32204}.Release|x86.Build.0 = Release|Any CPU\n\t\t{FE845F24-9A71-4FB4-88F7-EE36598C3D90}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{FE845F24-9A71-4FB4-88F7-EE36598C3D90}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{FE845F24-9A71-4FB4-88F7-EE36598C3D90}.Debug|x64.ActiveCfg = Debug|Any CPU\n\t\t{FE845F24-9A71-4FB4-88F7-EE36598C3D90}.Debug|x64.Build.0 = Debug|Any CPU\n\t\t{FE845F24-9A71-4FB4-88F7-EE36598C3D90}.Debug|x86.ActiveCfg = Debug|Any CPU\n\t\t{FE845F24-9A71-4FB4-88F7-EE36598C3D90}.Debug|x86.Build.0 = Debug|Any CPU\n\t\t{FE845F24-9A71-4FB4-88F7-EE36598C3D90}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{FE845F24-9A71-4FB4-88F7-EE36598C3D90}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{FE845F24-9A71-4FB4-88F7-EE36598C3D90}.Release|x64.ActiveCfg = Release|Any CPU\n\t\t{FE845F24-9A71-4FB4-88F7-EE36598C3D90}.Release|x64.Build.0 = Release|Any CPU\n\t\t{FE845F24-9A71-4FB4-88F7-EE36598C3D90}.Release|x86.ActiveCfg = Release|Any CPU\n\t\t{FE845F24-9A71-4FB4-88F7-EE36598C3D90}.Release|x86.Build.0 = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {A91FC5AF-2866-45D7-91FF-1C6ADE67E230}\n\tEndGlobalSection\n\tGlobalSection(Performance) = preSolution\n\t\tHasPerformanceSessions = true\n\tEndGlobalSection\n\tGlobalSection(Performance) = preSolution\n\t\tHasPerformanceSessions = true\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "test/ActivateTests.cs",
    "content": "﻿using Stashbox.Attributes;\nusing System;\nusing Xunit;\n\nnamespace Stashbox.Tests;\n\npublic class ActivateTests\n{\n    [Fact]\n    public void ActivateTests_Full()\n    {\n        var inst = new StashboxContainer().Register<Test>().Activate<Test1>();\n\n        Assert.NotNull(inst.Test);\n        Assert.NotNull(inst.Test2);\n\n        Assert.True(inst.InjectionMethodCalled);\n    }\n\n    [Fact]\n    public void ActivateTests_Full_DepOverride()\n    {\n        var test = new Test();\n        var inst = new StashboxContainer().Activate<Test1>(test);\n\n        Assert.Same(test, inst.Test);\n        Assert.Same(test, inst.Test2);\n\n        Assert.True(inst.InjectionMethodCalled);\n    }\n\n    [Fact]\n    public void ActivateTests_Fail()\n    {\n        Assert.Throws<ArgumentException>(() => new StashboxContainer().Activate<ITest>());\n    }\n\n    [Fact]\n    public void ActivateTests_Fail_On_Scope()\n    {\n        Assert.Throws<ArgumentException>(() => new StashboxContainer().BeginScope().Activate<ITest>());\n    }\n\n    interface ITest;\n\n    class Test : ITest;\n\n    class Test1\n    {\n        public bool InjectionMethodCalled { get; set; }\n\n        public Test Test { get; set; }\n\n        [Dependency]\n        public Test Test2 { get; set; }\n\n        public Test1(Test test)\n        {\n            this.Test = test;\n        }\n\n        [InjectionMethod]\n        public void InjectMethod()\n        {\n            this.InjectionMethodCalled = true;\n        }\n    }\n}"
  },
  {
    "path": "test/AssemblyTests.cs",
    "content": "﻿using Stashbox.Configuration;\nusing Stashbox.Lifetime;\nusing System.Linq;\nusing TestAssembly;\nusing Xunit;\n\nnamespace Stashbox.Tests;\n\npublic class AssemblyTests\n{\n    [Fact]\n    public void LoadTestAssembly()\n    {\n        using var container = new StashboxContainer()\n            .RegisterAssembly(typeof(ITA_T1).Assembly);\n\n        var regs = container.GetRegistrationDiagnostics().ToArray();\n\n        Assert.Equal(34, regs.Length);\n    }\n\n    [Fact]\n    public void LoadTestAssembly_Just_Interfaces_And_Self()\n    {\n        using var container = new StashboxContainer()\n            .RegisterAssembly(typeof(ITA_T1).Assembly,\n                serviceTypeSelector: Rules.ServiceRegistrationFilters.Interfaces);\n\n        var regs = container.GetRegistrationDiagnostics().ToArray();\n\n        Assert.Equal(32, regs.Length);\n    }\n\n    [Fact]\n    public void LoadTestAssembly_Just_Abstarct_And_Self()\n    {\n        using var container = new StashboxContainer()\n            .RegisterAssembly(typeof(ITA_T1).Assembly,\n                serviceTypeSelector: Rules.ServiceRegistrationFilters.AbstractClasses);\n\n        var regs = container.GetRegistrationDiagnostics().ToArray();\n\n        Assert.Equal(18, regs.Length);\n    }\n\n    [Fact]\n    public void LoadTestAssembly_Just_Abstarct_Without_Self()\n    {\n        using var container = new StashboxContainer()\n            .RegisterAssembly(typeof(ITA_T1).Assembly,\n                serviceTypeSelector: Rules.ServiceRegistrationFilters.AbstractClasses,\n                registerSelf: false);\n\n        var regs = container.GetRegistrationDiagnostics().ToArray();\n\n        Assert.Equal(2, regs.Length);\n    }\n\n    [Fact]\n    public void RegistersTests_RegisterAssembly()\n    {\n        using var container = new StashboxContainer();\n        container.RegisterAssemblyContaining<ITA_T1>();\n\n        var regs = container.ContainerContext.RegistrationRepository.GetRegistrationMappings().ToArray();\n\n        Assert.Equal(34, regs.Length);\n    }\n\n    [Fact]\n    public void RegistersTests_RegisterAssembly_AsSelf()\n    {\n        using var container = new StashboxContainer();\n        container.RegisterAssemblyContaining<ITA_T1>();\n\n        var regs = container.ContainerContext.RegistrationRepository.GetRegistrationMappings().ToArray();\n\n        Assert.Equal(34, regs.Length);\n        Assert.Contains(regs, reg => reg.Key == typeof(TA_T1));\n    }\n\n    [Fact]\n    public void RegistersTests_RegisterAssemblies()\n    {\n        using var container = new StashboxContainer();\n\n        var assembly1 = typeof(ITA_T1).Assembly;\n        var assembly2 = typeof(IStashboxContainer).Assembly;\n\n        container.RegisterAssemblies(new[] { assembly1, assembly2 }, t => t.FullName.Contains(\"TestAssembly\") || t == typeof(StashboxContainer));\n\n        var regs = container.ContainerContext.RegistrationRepository.GetRegistrationMappings();\n\n        Assert.Contains(regs, r => r.Key == typeof(IStashboxContainer));\n        Assert.Contains(regs, r => r.Key == typeof(ITA_T1));\n    }\n\n    [Fact]\n    public void RegistersTests_RegisterAssemblies_AsSelf()\n    {\n        using var container = new StashboxContainer();\n\n        var assembly1 = typeof(ITA_T1).Assembly;\n        var assembly2 = typeof(IStashboxContainer).Assembly;\n\n        container.RegisterAssemblies(new[] { assembly1, assembly2 });\n\n        var regs = container.ContainerContext.RegistrationRepository.GetRegistrationMappings();\n\n        Assert.Contains(regs, r => r.Key == typeof(StashboxContainer));\n        Assert.Contains(regs, r => r.Key == typeof(TA_T1));\n    }\n\n    [Fact]\n    public void RegistersTests_RegisterAssembly_Selector()\n    {\n        using var container = new StashboxContainer();\n        container.RegisterAssemblyContaining<ITA_T1>(type => type == typeof(TA_T1));\n\n        var regs = container.ContainerContext.RegistrationRepository.GetRegistrationMappings();\n\n        Assert.Contains(regs, reg => reg.Key == typeof(ITA_T1));\n        Assert.Contains(regs, reg => reg.Key == typeof(TA_T1));\n    }\n\n    [Fact]\n    public void RegistersTests_RegisterAssembly_Configurator()\n    {\n        using var container = new StashboxContainer();\n        container.RegisterAssemblyContaining<ITA_T1>(configurator: context =>\n        {\n            if (context.HasServiceType<ITA_T2>())\n                context.WithScopedLifetime();\n        });\n\n        var regs = container.ContainerContext.RegistrationRepository.GetRegistrationMappings()\n            .Where(r => r.Value.Lifetime is ScopedLifetime).ToArray();\n\n        Assert.True(regs.Length > 0);\n    }\n\n    [Fact]\n    public void RegistersTests_RegisterAssembly_Configurator_AsSelf()\n    {\n        using var container = new StashboxContainer();\n        container.RegisterAssemblyContaining<ITA_T1>(configurator: context =>\n        {\n            if (context.ImplementationType == typeof(TA_T1))\n                context.WithScopedLifetime();\n        });\n\n        var regs = container.ContainerContext.RegistrationRepository.GetRegistrationMappings()\n            .Where(r => r.Value.Lifetime is ScopedLifetime).ToArray();\n\n        Assert.True(regs.Length > 0);\n    }\n}"
  },
  {
    "path": "test/AsyncDisposeTests.cs",
    "content": "﻿using System;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Xunit;\n\n#if HAS_ASYNC_DISPOSABLE\n\nnamespace Stashbox.Tests\n{\n    public class AsyncDisposeTests\n    {\n        [Fact]\n        public async Task Async_Dispose_Works()\n        {\n            AsyncDisposable disposable;\n            {\n                await using var container = new StashboxContainer(c => c.WithDisposableTransientTracking())\n                    .Register<AsyncDisposable>();\n                disposable = container.Resolve<AsyncDisposable>();\n            }\n\n            Assert.True(disposable.Disposed);\n        }\n\n        [Fact]\n        public async Task Async_Dispose_Multiple()\n        {\n            var container = new StashboxContainer(c => c.WithDisposableTransientTracking())\n                .Register<AsyncDisposable>();\n            var disposable = container.Resolve<AsyncDisposable>();\n\n            await container.DisposeAsync();\n            await container.DisposeAsync();\n\n            Assert.True(disposable.Disposed);\n        }\n\n        [Fact]\n        public async Task Async_Dispose_Multiple_Scoped()\n        {\n            await using var container = new StashboxContainer(c => c.WithDisposableTransientTracking())\n                .RegisterScoped<AsyncDisposable>();\n\n            var scope = container.BeginScope();\n            var disposable = scope.Resolve<AsyncDisposable>();\n\n            await scope.DisposeAsync();\n            await scope.DisposeAsync();\n\n            Assert.True(disposable.Disposed);\n        }\n\n        [Fact]\n        public async Task Async_Dispose_Works_On_Scoped()\n        {\n            AsyncDisposable disposable;\n\n            await using var container = new StashboxContainer()\n                .RegisterScoped<AsyncDisposable>();\n\n            {\n                await using var scope = container.BeginScope();\n                disposable = scope.Resolve<AsyncDisposable>();\n            }\n\n            Assert.True(disposable.Disposed);\n        }\n\n        [Fact]\n        public async Task Async_Dispose_Works_On_Singleton()\n        {\n            AsyncDisposable disposable;\n            {\n                await using var container = new StashboxContainer()\n                    .RegisterSingleton<AsyncDisposable>();\n\n                {\n                    await using var scope = container.BeginScope();\n                    disposable = scope.Resolve<AsyncDisposable>();\n                }\n\n                Assert.False(disposable.Disposed);\n            }\n\n            Assert.True(disposable.Disposed);\n        }\n\n        [Fact]\n        public async Task Disposes_Either_Normal_And_Async()\n        {\n            AsyncDisposable asyncDisposable;\n            Disposable disposable;\n            {\n                await using var container = new StashboxContainer(c => c.WithDisposableTransientTracking())\n                    .Register<AsyncDisposable>()\n                    .Register<Disposable>();\n                asyncDisposable = container.Resolve<AsyncDisposable>();\n                disposable = container.Resolve<Disposable>();\n            }\n\n            Assert.True(asyncDisposable.Disposed);\n            Assert.True(disposable.Disposed);\n        }\n\n        [Fact]\n        public async Task Prefers_Async_Disposable_Over_Normal()\n        {\n            A disposable;\n            {\n                await using var container = new StashboxContainer(c => c.WithDisposableTransientTracking())\n                    .Register<A>();\n                disposable = container.Resolve<A>();\n            }\n\n            Assert.True(disposable.Disposed);\n        }\n\n        [Fact]\n        public async Task Async_Dispose_Works_On_Dependencies()\n        {\n            B b;\n            C c;\n            {\n                await using var container = new StashboxContainer(c => c\n                        .WithDisposableTransientTracking()\n                        .WithUnknownTypeResolution())\n                    .Register<B>()\n                    .Register<C>();\n                b = container.Resolve<B>();\n                c = container.Resolve<C>();\n            }\n\n            Assert.True(b.Disposed);\n            Assert.True(b.Disposable.Disposed);\n            Assert.True(c.Disposed);\n            Assert.True(c.Disposable.Disposed);\n        }\n\n        class A : AsyncDisposable, IDisposable\n        {\n            public void Dispose()\n            {\n                throw new InvalidOperationException(\"should not be called.\");\n            }\n        }\n\n        class B : AsyncDisposable\n        {\n            public Disposable Disposable { get; }\n\n            public B(Disposable disposable)\n            {\n                Disposable = disposable;\n            }\n        }\n\n        class C : Disposable\n        {\n            public AsyncDisposable Disposable { get; }\n\n            public C(AsyncDisposable disposable)\n            {\n                Disposable = disposable;\n            }\n        }\n\n        class AsyncDisposable : IAsyncDisposable\n        {\n            private int disposed;\n\n            public bool Disposed => this.disposed == 1;\n\n            public ValueTask DisposeAsync()\n            {\n                if (Interlocked.CompareExchange(ref this.disposed, 1, 0) != 0)\n                    throw new ObjectDisposedException(\"object already disposed\");\n\n                return new ValueTask(Task.CompletedTask);\n            }\n        }\n\n        class Disposable : IDisposable\n        {\n            public bool Disposed { get; private set; }\n\n            public void Dispose()\n            {\n                if (Disposed)\n                    throw new ObjectDisposedException(\"object already disposed\");\n\n                Disposed = true;\n            }\n        }\n    }\n}\n#endif"
  },
  {
    "path": "test/AttributeTests.cs",
    "content": "﻿using Stashbox.Attributes;\nusing Stashbox.Utils;\nusing System;\nusing System.Threading.Tasks;\nusing Xunit;\n\nnamespace Stashbox.Tests;\n\npublic class AttributeTest\n{\n    [Fact]\n    public void AttributeTests_Resolve()\n    {\n        var container = new StashboxContainer();\n        container.Register<ITest1, Test1>();\n        container.Register<ITest1, Test1>(context => context.WithName(\"test1\"));\n        container.Register<ITest1, Test11>(context => context.WithName(\"test11\"));\n        container.Register<ITest1, Test12>(context => context.WithName(\"test12\"));\n        container.Register<ITest2, Test2>(context => context.WithName(\"test2\"));\n        container.Register<ITest2, Test22>(context => context.WithName(\"test22\"));\n        container.Register<ITest3, Test3>();\n        container.Register<ITest4, Test4>();\n\n        var test1 = container.Resolve<ITest1>();\n        var test2 = container.Resolve<ITest2>(\"test2\");\n        var test3 = container.Resolve<ITest3>();\n        var test4 = container.Resolve<Lazy<ITest4>>();\n\n        Assert.NotNull(test1);\n        Assert.NotNull(test2);\n        Assert.NotNull(test3);\n        Assert.NotNull(test4.Value);\n\n        Assert.True(test3.MethodInvoked);\n        Assert.True(test3.MethodInvoked2);\n\n        Assert.IsType<Test11>(test3.test1);\n        Assert.IsType<Test22>(test3.test2);\n    }\n\n    [Fact]\n    public void AttributeTests_Named_Resolution()\n    {\n        var container = new StashboxContainer();\n        container.Register<ITest1, Test1>(context => context.WithName(\"test1\"));\n        container.Register<ITest1, Test11>(context => context.WithName(\"test11\"));\n        container.Register<ITest1, Test12>(context => context.WithName(\"test12\"));\n        container.Register<ITest2, Test2>(context => context.WithName(\"test2\"));\n        container.Register<ITest2, Test22>(context => context.WithName(\"test22\"));\n\n        var test1 = container.Resolve<ITest1>(\"test1\");\n        var test11 = container.Resolve<ITest1>(\"test11\");\n        var test12 = container.Resolve<ITest1>(\"test12\");\n        var test2 = container.Resolve<ITest2>(\"test2\");\n        var test22 = container.Resolve<ITest2>(\"test22\");\n\n        Assert.IsType<Test1>(test1);\n        Assert.IsType<Test11>(test11);\n        Assert.IsType<Test12>(test12);\n        Assert.IsType<Test2>(test2);\n        Assert.IsType<Test22>(test22);\n    }\n\n    [Fact]\n    public void AttributeTests_Parallel_Resolve()\n    {\n        var container = new StashboxContainer();\n        container.Register<ITest1, Test1>();\n        container.Register<ITest1, Test1>(context => context.WithName(\"test1\"));\n        container.Register<ITest1, Test11>(context => context.WithName(\"test11\"));\n        container.Register<ITest1, Test12>(context => context.WithName(\"test12\"));\n        container.Register<ITest2, Test2>(context => context.WithName(\"test2\"));\n        container.Register<ITest2, Test22>(context => context.WithName(\"test22\"));\n        container.Register<ITest3, Test3>();\n\n        Parallel.For(0, 50000, (i) =>\n        {\n            var test1 = container.Resolve<ITest1>();\n            var test2 = container.Resolve<ITest2>(\"test2\");\n            var test3 = container.Resolve<ITest3>();\n\n            Assert.NotNull(test1);\n            Assert.NotNull(test2);\n            Assert.NotNull(test3);\n\n            Assert.True(test3.MethodInvoked);\n\n            Assert.IsType<Test11>(test3.test1);\n            Assert.IsType<Test22>(test3.test2);\n        });\n    }\n\n    [Fact]\n    public void AttributeTests_Parallel_Lazy_Resolve()\n    {\n        var container = new StashboxContainer();\n        container.Register<ITest1, Test1>();\n        container.Register<ITest1, Test1>(context => context.WithName(\"test1\"));\n        container.Register<ITest1, Test11>(context => context.WithName(\"test11\"));\n        container.Register<ITest1, Test12>(context => context.WithName(\"test12\"));\n        container.Register<ITest2, Test2>(context => context.WithName(\"test2\"));\n        container.Register<ITest2, Test22>(context => context.WithName(\"test22\"));\n        container.Register<ITest3, Test3>();\n        container.Register<ITest4, Test4>();\n\n        Parallel.For(0, 50000, (i) =>\n        {\n            var test1 = container.Resolve<Lazy<ITest1>>();\n            var test2 = container.Resolve<Lazy<ITest2>>(\"test2\");\n            var test3 = container.Resolve<Lazy<ITest3>>();\n            var test4 = container.Resolve<Lazy<ITest4>>();\n\n            Assert.NotNull(test1.Value);\n            Assert.NotNull(test2.Value);\n            Assert.NotNull(test3.Value);\n            Assert.NotNull(test4.Value);\n\n            Assert.True(test3.Value.MethodInvoked);\n            Assert.True(test4.Value.MethodInvoked);\n\n            Assert.IsType<Test11>(test3.Value.test1);\n            Assert.IsType<Test22>(test3.Value.test2);\n\n            Assert.IsType<Test11>(test4.Value.test1.Value);\n            Assert.IsType<Test22>(test4.Value.test2.Value);\n        });\n    }\n\n    [Fact]\n    public void AttributeTests_InjectionMethod_WithoutMembers()\n    {\n        var inst = new StashboxContainer()\n            .Register<Test5>()\n            .Resolve<Test5>();\n\n        Assert.True(inst.MethodInvoked);\n    }\n\n    [Fact]\n    public void AttributeTests_InjectionMethod_Private()\n    {\n        var inst = new StashboxContainer()\n            .Register<Test6>()\n            .Resolve<Test6>();\n\n        Assert.True(inst.MethodInvoked);\n    }\n\n    interface ITest1;\n\n    interface ITest2 { ITest1 test1 { get; set; } }\n\n    interface ITest3 { ITest2 test2 { get; set; } ITest1 test1 { get; set; } bool MethodInvoked { get; set; } bool MethodInvoked2 { get; set; } }\n\n    interface ITest4 { Lazy<ITest2> test2 { get; set; } Lazy<ITest1> test1 { get; set; } bool MethodInvoked { get; set; } }\n\n    class Test1 : ITest1;\n\n    class Test11 : ITest1;\n\n    class Test12 : ITest1;\n\n    class Test22 : ITest2 { public ITest1 test1 { get; set; } }\n\n    class Test2 : ITest2\n    {\n        public ITest1 test1 { get; set; }\n\n        public Test2([Dependency(\"test11\")] ITest1 test1)\n        {\n            Shield.EnsureNotNull(test1, nameof(test1));\n            Shield.EnsureTypeOf<Test11>(test1);\n        }\n    }\n\n    class Test3 : ITest3\n    {\n        [Dependency(\"test11\")]\n        public ITest1 test1 { get; set; }\n\n        [Dependency(\"test22\")]\n        public ITest2 test2 { get; set; }\n\n        [InjectionMethod]\n        public void MethodTest([Dependency(\"test22\")] ITest2 test2)\n        {\n            Shield.EnsureNotNull(test2, nameof(test2));\n            this.MethodInvoked = true;\n        }\n\n        [InjectionMethod]\n        public void MethodTest2([Dependency(\"test22\")] ITest2 test2)\n        {\n            Shield.EnsureNotNull(test2, nameof(test2));\n            this.MethodInvoked2 = true;\n        }\n\n        public Test3([Dependency(\"test12\")] ITest1 test12, [Dependency(\"test2\")] ITest2 test2)\n        {\n            Shield.EnsureNotNull(test12, nameof(test12));\n            Shield.EnsureNotNull(test2, nameof(test2));\n\n            Shield.EnsureTypeOf<Test12>(test12);\n            Shield.EnsureTypeOf<Test2>(test2);\n        }\n\n        public bool MethodInvoked { get; set; }\n        public bool MethodInvoked2 { get; set; }\n    }\n\n    class Test4 : ITest4\n    {\n        [Dependency(\"test11\")]\n        public Lazy<ITest1> test1 { get; set; }\n\n        [Dependency(\"test22\")]\n        public Lazy<ITest2> test2 { get; set; }\n\n        [InjectionMethod]\n        public void MethodTest([Dependency(\"test22\")] Lazy<ITest2> test2)\n        {\n            Shield.EnsureNotNull(test2.Value, nameof(test2.Value));\n            this.MethodInvoked = true;\n        }\n\n        public Test4([Dependency(\"test12\")] Lazy<ITest1> test1, [Dependency(\"test2\")] Lazy<ITest2> test2)\n        {\n            Shield.EnsureNotNull(test1.Value, nameof(test1.Value));\n            Shield.EnsureNotNull(test2.Value, nameof(test2.Value));\n\n            Shield.EnsureTypeOf<Test12>(test1.Value);\n            Shield.EnsureTypeOf<Test2>(test2.Value);\n        }\n\n        public bool MethodInvoked { get; set; }\n    }\n\n    class Test5\n    {\n        [InjectionMethod]\n        public void MethodTest()\n        {\n            this.MethodInvoked = true;\n        }\n\n        public bool MethodInvoked { get; set; }\n    }\n\n    class Test6\n    {\n        [InjectionMethod]\n        private void MethodTest()\n        {\n            this.MethodInvoked = true;\n        }\n\n        public bool MethodInvoked { get; set; }\n    }\n}"
  },
  {
    "path": "test/BuildUpTests.cs",
    "content": "﻿using Stashbox.Attributes;\nusing Stashbox.Utils;\nusing System;\nusing Xunit;\n\nnamespace Stashbox.Tests;\n\npublic class BuildUpTests\n{\n    [Fact]\n    public void BuildUpTests_BuildUp_Simple()\n    {\n        using var container = new StashboxContainer();\n        ITest inst = new Test();\n        var built = container.BuildUp(inst);\n\n        Assert.Same(inst, built);\n    }\n\n    [Fact]\n    public void BuildUpTests_BuildUp()\n    {\n        using var container = new StashboxContainer();\n        container.Register<ITest, Test>();\n\n        var test1 = new Test1();\n        container.WireUp<ITest1>(test1);\n\n        var test2 = new Test2();\n        var inst = container.BuildUp(test2);\n\n        Assert.Equal(test2, inst);\n        Assert.NotNull(inst);\n        Assert.NotNull(inst.Test1);\n        Assert.IsType<Test2>(inst);\n        Assert.IsType<Test1>(inst.Test1);\n        Assert.IsType<Test>(inst.Test1.Test);\n    }\n\n    [Fact]\n    public void BuildUpTests_BuildUp_As_InterfaceType()\n    {\n        using var container = new StashboxContainer();\n        container.Register<ITest3, Test3>().Register<ITest, Test>();\n        var test3 = new Test3();\n        var inst = (Test3)container.BuildUp<ITest3>(test3);\n\n        Assert.NotNull(inst.Test);\n    }\n\n    [Fact]\n    public void BuildUpTests_BuildUp_Scoped()\n    {\n        using var container = new StashboxContainer();\n        container.RegisterScoped<ITest, Test>();\n\n        var test1 = new Test1();\n        using (var scope = container.BeginScope())\n        {\n            scope.BuildUp(test1);\n            Assert.False(test1.Test.Disposed);\n        }\n\n        Assert.True(test1.Test.Disposed);\n\n        using (var scope = container.BeginScope())\n        {\n            scope.BuildUp(test1);\n            Assert.False(test1.Test.Disposed);\n        }\n\n        Assert.True(test1.Test.Disposed);\n    }\n\n    interface ITest : IDisposable { bool Disposed { get; } }\n\n    interface ITest1 { ITest Test { get; } }\n\n    interface ITest3;\n\n    class Test : ITest\n    {\n        public void Dispose()\n        {\n            if (this.Disposed)\n                throw new ObjectDisposedException(\"disposed\");\n\n            this.Disposed = true;\n        }\n\n        public bool Disposed { get; private set; }\n    }\n\n    class Test1 : ITest1\n    {\n        [Dependency]\n        public ITest Test { get; set; }\n\n        [InjectionMethod]\n        public void Init()\n        {\n            Shield.EnsureNotNull(this.Test, nameof(this.Test));\n        }\n    }\n\n    class Test2\n    {\n        [Dependency]\n        public ITest1 Test1 { get; set; }\n    }\n\n    class Test3 : ITest3\n    {\n        [Dependency]\n        public ITest Test { get; set; }\n    }\n}"
  },
  {
    "path": "test/CanResolveTests.cs",
    "content": "﻿using Stashbox.Resolution;\nusing System;\nusing System.Collections.Generic;\nusing Stashbox.Exceptions;\nusing Xunit;\n\nnamespace Stashbox.Tests;\n\npublic class CanResolveTests\n{\n    [Fact]\n    public void CanResolveTests_ExplicitService()\n    {\n        using var container = new StashboxContainer()\n            .Register<IA, A>();\n\n        Assert.True(container.CanResolve<IA>());\n        Assert.False(container.CanResolve<A>());\n    }\n\n    [Fact]\n    public void CanResolveTests_OpenGeneric()\n    {\n        using var container = new StashboxContainer()\n            .Register(typeof(IB<>), typeof(B<>));\n\n        Assert.False(container.CanResolve(typeof(IB<>)));\n        Assert.True(container.CanResolve<IB<IA>>());\n    }\n\n    [Fact]\n    public void CanResolveTests_ClosedGeneric()\n    {\n        using var container = new StashboxContainer()\n            .Register(typeof(IB<IA>), typeof(B<IA>));\n\n        Assert.True(container.CanResolve<IB<IA>>());\n    }\n\n    [Fact]\n    public void CanResolveTests_Wrapper()\n    {\n        using var container = new StashboxContainer()\n            .Register<IA, A>();\n\n        Assert.True(container.CanResolve<Func<IA>>());\n        Assert.True(container.CanResolve<Lazy<IA>>());\n        Assert.True(container.CanResolve<Tuple<IA, object>>());\n    }\n\n    [Fact]\n    public void CanResolveTests_Enumerable()\n    {\n        using var container = new StashboxContainer()\n            .Register<IA, A>();\n\n        Assert.True(container.CanResolve<IEnumerable<IA>>());\n        Assert.True(container.CanResolve<IEnumerable<IB<IA>>>());\n    }\n\n    [Fact]\n    public void CanResolveTests_ExplicitService_Scope()\n    {\n        using var scope = new StashboxContainer()\n            .Register<IA, A>().BeginScope();\n\n        Assert.True(scope.CanResolve<IA>());\n        Assert.False(scope.CanResolve<A>());\n    }\n\n    [Fact]\n    public void CanResolveTests_OpenGeneric_Scope()\n    {\n        using var scope = new StashboxContainer()\n            .Register(typeof(IB<>), typeof(B<>)).BeginScope();\n\n        Assert.False(scope.CanResolve(typeof(IB<>)));\n        Assert.True(scope.CanResolve<IB<IA>>());\n    }\n\n    [Fact]\n    public void CanResolveTests_ClosedGeneric_Scope()\n    {\n        using var scope = new StashboxContainer()\n            .Register(typeof(IB<IA>), typeof(B<IA>)).BeginScope();\n\n        Assert.True(scope.CanResolve<IB<IA>>());\n    }\n\n    [Fact]\n    public void CanResolveTests_Wrapper_Scope()\n    {\n        using var scope = new StashboxContainer()\n            .Register<IA, A>().BeginScope();\n\n        Assert.True(scope.CanResolve<Func<IA>>());\n        Assert.True(scope.CanResolve<Lazy<IA>>());\n        Assert.True(scope.CanResolve<Tuple<IA, object>>());\n    }\n\n    [Fact]\n    public void CanResolveTests_Enumerable_Scope()\n    {\n        using var scope = new StashboxContainer()\n            .Register<IA, A>().BeginScope();\n\n        Assert.True(scope.CanResolve<IEnumerable<IA>>());\n        Assert.True(scope.CanResolve<IEnumerable<IB<IA>>>());\n    }\n\n    [Fact]\n    public void CanResolveTests_Special_Types()\n    {\n        using var scope = new StashboxContainer();\n\n        Assert.True(scope.CanResolve<IServiceProvider>());\n        Assert.True(scope.CanResolve<IDependencyResolver>());\n        Assert.True(scope.CanResolve<IRequestContext>());\n    }\n    \n    [Fact]\n    public void CanResolveTests_WithExceptionOverEmptyCollection()\n    {\n        var container = new StashboxContainer(c => c.WithExceptionOverEmptyCollection()).Register<C>();\n\n        Assert.False(container.CanResolve<byte[]>());\n        Assert.Null(container.ResolveOrDefault<C>());\n        var ex = Assert.Throws<ResolutionFailedException>(() => container.Resolve<C>());\n        Assert.Contains(\"Constructor Void .ctor(Byte[]) found with unresolvable parameter: (System.Byte[])payload.\", ex.Message);\n    }\n\n    private interface IA;\n\n    private class A : IA;\n\n    private interface IB<T>;\n\n    private class B<T> : IB<T>;\n\n#pragma warning disable CS9113 // Parameter is unread.\n    private class C(byte[] payload);\n#pragma warning restore CS9113 // Parameter is unread.\n}"
  },
  {
    "path": "test/ChildContainerTests.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing Stashbox.Configuration;\nusing Stashbox.Exceptions;\nusing Stashbox.Resolution;\nusing Stashbox.Tests.Utils;\nusing Stashbox.Utils.Data.Immutable;\nusing Xunit;\n\nnamespace Stashbox.Tests;\n\npublic class ChildContainerTests\n{\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void ChildContainerTests_Dispose_Parent_Disposes_Child(CompilerType compilerType)\n    {\n        var test = new Test();\n        IStashboxContainer container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        var child = container.CreateChildContainer();\n        child.RegisterInstance(test);\n        \n        container.Dispose();\n        container.Dispose();\n        \n        Assert.True(test.Disposed);\n    }\n    \n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void ChildContainerTests_Dispose_Parent_Not_Disposes_Child(CompilerType compilerType)\n    {\n        var test = new Test();\n        IStashboxContainer container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        var child = container.CreateChildContainer(attachToParent: false);\n        child.RegisterInstance(test);\n        \n        container.Dispose();\n        container.Dispose();\n        \n        Assert.False(test.Disposed);\n        \n        child.Dispose();\n        child.Dispose();\n        \n        Assert.True(test.Disposed);\n    }\n    \n#if HAS_ASYNC_DISPOSABLE\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public async Task ChildContainerTests_Dispose_Parent_Disposes_Child_Async(CompilerType compilerType)\n    {\n        var test = new Test();\n        IStashboxContainer container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        var child = container.CreateChildContainer(attachToParent: true);\n        child.RegisterInstance(test);\n        \n        await container.DisposeAsync();\n        await container.DisposeAsync();\n        \n        Assert.True(test.Disposed);\n    }\n    \n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public async Task ChildContainerTests_Dispose_Parent_Not_Disposes_Child_Async(CompilerType compilerType)\n    {\n        var test = new Test();\n        IStashboxContainer container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        var child = container.CreateChildContainer(attachToParent: false);\n        child.RegisterInstance(test);\n        \n        await container.DisposeAsync();\n        await container.DisposeAsync();\n        \n        Assert.False(test.Disposed);\n        \n        child.Dispose();\n        child.Dispose();\n        \n        Assert.True(test.Disposed);\n    }\n#endif\n    \n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void ChildContainerTests_ResolveAll_Parent_Current(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType)).Register<IT, T1>().Register<IT, T2>();\n        var child = container.CreateChildContainer().Register<IT, T3>().Register<IT, T4>();\n\n        Assert.Equal(4, child.ResolveAll<IT>().Count());\n        Assert.Equal(2, child.ResolveAll<IT>(name: null, dependencyOverrides: [new object()], ResolutionBehavior.Current).Count());\n        Assert.Equal(2, child.ResolveAll<IT>(dependencyOverrides: [new object()], ResolutionBehavior.Current).Count());\n        Assert.Equal(2, child.ResolveAll<IT>(name: null, ResolutionBehavior.Current).Count());\n        Assert.Equal(2, child.ResolveAll(typeof(IT), name: null, dependencyOverrides: [new object()], ResolutionBehavior.Parent).Count());\n    }\n    \n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void ChildContainerTests_ResolveAll_Scope_Parent_Current(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType)).Register<IT, T1>().Register<IT, T2>();\n        var child = container.CreateChildContainer().Register<IT, T3>().Register<IT, T4>();\n\n        Assert.Equal(4, child.BeginScope().ResolveAll<IT>().Count());\n        Assert.Equal(2, child.BeginScope().ResolveAll<IT>(name: null, dependencyOverrides: [new object()], ResolutionBehavior.Current).Count());\n        Assert.Equal(2, child.BeginScope().ResolveAll<IT>(dependencyOverrides: [new object()], ResolutionBehavior.Current).Count());\n        Assert.Equal(2, child.BeginScope().ResolveAll<IT>(name: null, ResolutionBehavior.Current).Count());\n        Assert.Equal(2, child.BeginScope().ResolveAll(typeof(IT), name: null, dependencyOverrides: [new object()], ResolutionBehavior.Parent).Count());\n    }\n    \n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void ChildContainerTests_Resolve_Dependency_Parent_Current(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType))\n            .Register<IT, T1>()\n            .Register<IT, T2>()\n            .Register<D1>(c => c.WithInitializer((inst, _) => inst.Init(\"parent\")))\n            .Register<D2>(c => c.WithInitializer((inst, _) => inst.Init(\"parent\")));\n        var child = container.CreateChildContainer()\n            .Register<IT, T3>()\n            .Register<IT, T4>()\n            .Register<D1>(c => c.WithInitializer((inst, _) => inst.Init(\"child\")))\n            .Register<D2>(c => c.WithInitializer((inst, _) => inst.Init(\"child\")));\n\n        Assert.IsType<T4>(child.Resolve<D1>().Dep);\n        Assert.IsType<T4>(child.Resolve<D1>(ResolutionBehavior.Current).Dep);\n        Assert.IsType<T2>(child.Resolve<D1>(ResolutionBehavior.Parent).Dep);\n        \n        Assert.Equal(4, child.Resolve<D2>().Dep.Count());\n        Assert.Equal(2, child.Resolve<D2>(ResolutionBehavior.Current).Dep.Count());\n        Assert.Equal(2, child.Resolve<D2>(ResolutionBehavior.Parent).Dep.Count());\n\n        var deps = child.Resolve<D2>().Dep.Select(t => t.GetType()).ToArray();\n        Assert.Contains(typeof(T1), deps);\n        Assert.Contains(typeof(T2), deps);\n        Assert.Contains(typeof(T3), deps);\n        Assert.Contains(typeof(T4), deps);\n        \n        deps = child.Resolve<D2>(ResolutionBehavior.Current).Dep.Select(t => t.GetType()).ToArray();\n        Assert.Contains(typeof(T3), deps);\n        Assert.Contains(typeof(T4), deps);\n        \n        deps = child.Resolve<D2>(ResolutionBehavior.Parent).Dep.Select(t => t.GetType()).ToArray();\n        Assert.Contains(typeof(T1), deps);\n        Assert.Contains(typeof(T2), deps);\n        \n        Assert.Equal(\"child\", child.Resolve<D1>().ID);\n        Assert.Equal(\"child\", child.Resolve<D1>(ResolutionBehavior.Current).ID);\n        Assert.Equal(\"parent\", child.Resolve<D1>(ResolutionBehavior.Parent).ID);\n        \n        Assert.Equal(\"child\", child.Resolve<D2>().ID);\n        Assert.Equal(\"child\", child.Resolve<D2>(ResolutionBehavior.Current).ID);\n        Assert.Equal(\"parent\", child.Resolve<D2>(ResolutionBehavior.Parent).ID);\n    }\n    \n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void ChildContainerTests_Resolve_Decorator_Parent_Current(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType))\n            .Register<IT, T1>()\n            .Register<IT, T2>()\n            .RegisterDecorator<IT, T6>(c => c.WithInitializer((inst, _) => inst.Init(\"parent\")));\n        var child = container.CreateChildContainer()\n            .Register<IT, T3>()\n            .Register<IT, T4>()\n            .RegisterDecorator<IT, T6>(c => c.WithInitializer((inst, _) => inst.Init(\"child\")));\n\n        Assert.IsType<T6>(((T6)child.Resolve<IT>()).Dep);\n        Assert.IsType<T4>(((T6)child.Resolve<IT>(dependencyOverrides: [new object()], ResolutionBehavior.Current)).Dep);\n        Assert.IsType<T2>(((T6)child.Resolve<IT>(name: null, dependencyOverrides: [new object()], ResolutionBehavior.Parent)).Dep);\n        \n        Assert.Equal(\"child\", ((T6)child.Resolve<IT>()).ID);\n        Assert.Equal(\"child\", ((T6)child.Resolve<IT>(name: null, ResolutionBehavior.Current)).ID);\n        Assert.Equal(\"parent\", ((T6)child.Resolve(typeof(IT), ResolutionBehavior.Parent)).ID);\n    }\n    \n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void ChildContainerTests_Resolve_Scope_Decorator_Parent_Current(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType))\n            .Register<IT, T1>()\n            .Register<IT, T2>()\n            .RegisterDecorator<IT, T6>(c => c.WithInitializer((inst, _) => inst.Init(\"parent\")));\n        var child = container.CreateChildContainer()\n            .Register<IT, T3>()\n            .Register<IT, T4>()\n            .RegisterDecorator<IT, T6>(c => c.WithInitializer((inst, _) => inst.Init(\"child\")));\n\n        Assert.IsType<T6>(((T6)child.BeginScope().Resolve<IT>()).Dep);\n        Assert.IsType<T4>(((T6)child.BeginScope().Resolve<IT>(dependencyOverrides: [new object()], ResolutionBehavior.Current)).Dep);\n        Assert.IsType<T2>(((T6)child.BeginScope().Resolve<IT>(name: null, dependencyOverrides: [new object()], ResolutionBehavior.Parent)).Dep);\n        \n        Assert.Equal(\"child\", ((T6)child.BeginScope().Resolve<IT>()).ID);\n        Assert.Equal(\"child\", ((T6)child.BeginScope().Resolve<IT>(name: null, ResolutionBehavior.Current)).ID);\n        Assert.Equal(\"parent\", ((T6)child.BeginScope().Resolve(typeof(IT), ResolutionBehavior.Parent)).ID);\n    }\n    \n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void ChildContainerTests_ResolveOrDefault_Decorator_Parent_Current(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType))\n            .Register<IT, T1>()\n            .Register<IT, T2>()\n            .RegisterDecorator<IT, T6>(c => c.WithInitializer((inst, _) => inst.Init(\"parent\")));\n        var child = container.CreateChildContainer()\n            .Register<IT, T3>()\n            .Register<IT, T4>()\n            .RegisterDecorator<IT, T6>(c => c.WithInitializer((inst, _) => inst.Init(\"child\")));\n\n        Assert.IsType<T6>(((T6)child.ResolveOrDefault<IT>()).Dep);\n        Assert.IsType<T4>(((T6)child.ResolveOrDefault<IT>(dependencyOverrides: [new object()], ResolutionBehavior.Current)).Dep);\n        Assert.IsType<T2>(((T6)child.ResolveOrDefault<IT>(name: null, dependencyOverrides: [new object()], ResolutionBehavior.Parent)).Dep);\n        \n        Assert.Equal(\"child\", ((T6)child.ResolveOrDefault<IT>()).ID);\n        Assert.Equal(\"child\", ((T6)child.ResolveOrDefault<IT>(name: null, ResolutionBehavior.Current)).ID);\n        Assert.Equal(\"parent\", ((T6)child.ResolveOrDefault(typeof(IT), ResolutionBehavior.Parent)!).ID);\n    }\n    \n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void ChildContainerTests_ResolveOrDefault_Scope_Decorator_Parent_Current(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType))\n            .Register<IT, T1>()\n            .Register<IT, T2>()\n            .RegisterDecorator<IT, T6>(c => c.WithInitializer((inst, _) => inst.Init(\"parent\")));\n        var child = container.CreateChildContainer()\n            .Register<IT, T3>()\n            .Register<IT, T4>()\n            .RegisterDecorator<IT, T6>(c => c.WithInitializer((inst, _) => inst.Init(\"child\")));\n\n        Assert.IsType<T6>(((T6)child.BeginScope().ResolveOrDefault<IT>()).Dep);\n        Assert.IsType<T4>(((T6)child.BeginScope().ResolveOrDefault<IT>(dependencyOverrides: [new object()], ResolutionBehavior.Current)).Dep);\n        Assert.IsType<T2>(((T6)child.BeginScope().ResolveOrDefault<IT>(name: null, dependencyOverrides: [new object()], ResolutionBehavior.Parent)).Dep);\n        \n        Assert.Equal(\"child\", ((T6)child.BeginScope().ResolveOrDefault<IT>()).ID);\n        Assert.Equal(\"child\", ((T6)child.BeginScope().ResolveOrDefault<IT>(name: null, ResolutionBehavior.Current)).ID);\n        Assert.Equal(\"parent\", ((T6)child.BeginScope().ResolveOrDefault(typeof(IT), ResolutionBehavior.Parent)!).ID);\n    }\n    \n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void ChildContainerTests_Resolve_Decorator_Child_Service_Parent(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType))\n            .Register<IT, T1>();\n        var child = container.CreateChildContainer()\n            .RegisterDecorator<IT, T6>();\n\n        Assert.IsType<T1>(((T6)child.Resolve<IT>()).Dep);\n        Assert.IsType<T1>(child.Resolve<IT>(ResolutionBehavior.Parent));\n        Assert.Throws<ResolutionFailedException>(() => child.Resolve<IT>(ResolutionBehavior.Current));\n    }\n    \n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void ChildContainerTests_Resolve_Decorator_Parent_Service_Child(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType))\n            .RegisterDecorator<IT, T6>();\n        var child = container.CreateChildContainer()\n            .Register<IT, T1>();\n\n        Assert.IsType<T1>(((T6)child.Resolve<IT>()).Dep);\n        Assert.Throws<ResolutionFailedException>(() => child.Resolve<IT>(ResolutionBehavior.Parent));\n        Assert.IsType<T1>(child.Resolve<IT>(ResolutionBehavior.Current));\n    }\n    \n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void ChildContainerTests_Resolve_Parent_Dependency(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType))\n            .Register<IT, T1>();\n        var child = container.CreateChildContainer()\n            .Register<D1>();\n\n        Assert.IsType<T1>(child.Resolve<D1>().Dep);\n        Assert.IsType<T1>(child.Resolve<IT>(ResolutionBehavior.Parent));\n        Assert.Throws<ResolutionFailedException>(() => child.Resolve<D1>(ResolutionBehavior.Parent));\n        Assert.Throws<ResolutionFailedException>(() => child.Resolve<D1>(ResolutionBehavior.Current));\n        Assert.IsType<T1>(child.Resolve<D1>(ResolutionBehavior.Current | ResolutionBehavior.ParentDependency).Dep);\n        Assert.Throws<ResolutionFailedException>(() => child.Resolve<IT>(ResolutionBehavior.Current | ResolutionBehavior.ParentDependency));\n    }\n    \n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void ChildContainerTests_Resolve_Parent_Enumerable_Dependency(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType))\n            .Register<IT, T1>();\n        var child = container.CreateChildContainer()\n            .Register<D2>();\n\n        Assert.IsType<T1>(child.Resolve<D2>().Dep.First());\n        Assert.Empty(child.Resolve<D2>(ResolutionBehavior.Current).Dep);\n        Assert.IsType<T1>(child.Resolve<D2>(ResolutionBehavior.Current | ResolutionBehavior.ParentDependency).Dep.First());\n    }\n    \n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void ChildContainerTests_Resolve_Parent_Enumerable_Select_Dependency(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType))\n            .Register<IT, T1>().Register<D2>(c => c.WithInitializer((d, _) => d.Init(\"parent\")));\n        var child = container.CreateChildContainer()\n            .Register<IT, T2>().Register<D2>(c => c.WithInitializer((d, _) => d.Init(\"child\")));\n\n        Assert.Equal(2, child.Resolve<D2>().Dep.Count());\n        Assert.Equal(\"child\", child.Resolve<D2>().ID);\n        Assert.Single(child.Resolve<D2>(ResolutionBehavior.Parent).Dep);\n        Assert.Equal(\"parent\", child.Resolve<D2>(ResolutionBehavior.Parent).ID);\n        Assert.Single(child.Resolve<D2>(ResolutionBehavior.Current).Dep);\n        Assert.Equal(\"child\", child.Resolve<D2>(ResolutionBehavior.Current).ID);\n        Assert.Equal(2, child.Resolve<D2>(ResolutionBehavior.Current | ResolutionBehavior.ParentDependency).Dep.Count());\n        Assert.Equal(\"child\", child.Resolve<D2>(ResolutionBehavior.Current | ResolutionBehavior.ParentDependency).ID);\n    }\n    \n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void ChildContainerTests_Resolve_PreferCurrent_Enumerable_Select_Dependency(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType))\n            .Register<IT, T1>().Register<IT, T2>().Register<IT2, T11>().Register<IT2, T12>()\n            .Register<D2>(c => c.WithInitializer((d, _) => d.Init(\"parent\")))\n            .Register<D2_2>(c => c.WithInitializer((d, _) => d.Init(\"parent2\")));\n        var child = container.CreateChildContainer()\n            .Register<IT, T3>().Register<IT, T4>()\n            .Register<D2>(c => c.WithInitializer((d, _) => d.Init(\"child\")))\n            .Register<D2_2>(c => c.WithInitializer((d, _) => d.Init(\"child2\")));\n\n        var inst = child.Resolve<D2>(ResolutionBehavior.Default | ResolutionBehavior.PreferEnumerableInCurrent);\n        Assert.Equal(2, inst.Dep.Count());\n        Assert.Equal(\"child\", inst.ID);\n        Assert.IsType<T3>(inst.Dep.ElementAt(0));\n        Assert.IsType<T4>(inst.Dep.ElementAt(1));\n        \n        var inst2 = child.Resolve<D2_2>(ResolutionBehavior.Default | ResolutionBehavior.PreferEnumerableInCurrent);\n        Assert.Equal(2, inst2.Dep.Count());\n        Assert.Equal(\"child2\", inst2.ID);\n        Assert.IsType<T11>(inst2.Dep.ElementAt(0));\n        Assert.IsType<T12>(inst2.Dep.ElementAt(1));\n\n        child.Register<IT2, T13>();\n        \n        inst2 = child.Resolve<D2_2>(ResolutionBehavior.Default | ResolutionBehavior.PreferEnumerableInCurrent);\n        Assert.Single(inst2.Dep);\n        Assert.Equal(\"child2\", inst2.ID);\n        Assert.IsType<T13>(inst2.Dep.ElementAt(0));\n\n        var child2 = child.CreateChildContainer();\n        child2.Register<D2_2>(c => c.WithInitializer((d, _) => d.Init(\"child3\")));\n        \n        inst2 = child2.Resolve<D2_2>(ResolutionBehavior.Default | ResolutionBehavior.PreferEnumerableInCurrent);\n        Assert.Equal(3, inst2.Dep.Count());\n        Assert.Equal(\"child3\", inst2.ID);\n        Assert.IsType<T11>(inst2.Dep.ElementAt(0));\n        Assert.IsType<T12>(inst2.Dep.ElementAt(1));\n        Assert.IsType<T13>(inst2.Dep.ElementAt(2));\n    }\n    \n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void ChildContainerTests_Resolve_Parent_Decorator_Dependency(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType))\n            .Register<IT, T1>().RegisterDecorator<IT, T6>();\n        var child = container.CreateChildContainer()\n            .Register<D1>();\n\n        Assert.IsType<T6>(child.Resolve<D1>().Dep);\n        Assert.IsType<T6>(child.Resolve<IT>(ResolutionBehavior.Parent));\n        Assert.Throws<ResolutionFailedException>(() => child.Resolve<D1>(ResolutionBehavior.Parent));\n        Assert.Throws<ResolutionFailedException>(() => child.Resolve<D1>(ResolutionBehavior.Current));\n        Assert.IsType<T6>(child.Resolve<D1>(ResolutionBehavior.Current | ResolutionBehavior.ParentDependency).Dep);\n        Assert.Throws<ResolutionFailedException>(() => child.Resolve<IT>(ResolutionBehavior.Current | ResolutionBehavior.ParentDependency));\n    }\n    \n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void ChildContainerTests_Resolve_Decorator_Enumerable_Parent_Current(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType)).Register<IT, T1>().Register<IT, T2>().RegisterDecorator<IT, T5>();\n        var child = container.CreateChildContainer().Register<IT, T3>().Register<IT, T4>().RegisterDecorator<IT, T5>();\n\n        Assert.Equal(4, ((T5)child.Resolve<IT>()).Dep.Count());\n        Assert.Equal(2, ((T5)child.Resolve<IT>(ResolutionBehavior.Current)).Dep.Count());\n        Assert.Equal(2, ((T5)child.Resolve<IT>(ResolutionBehavior.Parent)).Dep.Count());\n        \n        var deps = ((T5)child.Resolve<IT>()).Dep.SelectMany(t => ((T5)t).Dep.Select(td => td.GetType())).ToArray();\n        Assert.Contains(typeof(T1), deps);\n        Assert.Contains(typeof(T2), deps);\n        Assert.Contains(typeof(T3), deps);\n        Assert.Contains(typeof(T4), deps);\n        \n        deps = ((T5)child.Resolve<IT>(ResolutionBehavior.Current)).Dep.Select(t => t.GetType()).ToArray();\n        Assert.Contains(typeof(T3), deps);\n        Assert.Contains(typeof(T4), deps);\n        \n        deps = ((T5)child.Resolve<IT>(ResolutionBehavior.Parent)).Dep.Select(t => t.GetType()).ToArray();\n        Assert.Contains(typeof(T1), deps);\n        Assert.Contains(typeof(T2), deps);\n    }\n    \n    [Fact]\n    public void ChildContainerTests_Get_NonExisting_Null()\n    {\n        var container = new StashboxContainer();\n\n        Assert.Null(container.GetChildContainer(\"A\"));\n    }\n\n    [Fact]\n    public void ChildContainerTests_Configure()\n    {\n        var container = new StashboxContainer();\n        container.Register<IA, A>();\n\n        container.CreateChildContainer(\"A\", c => c.Register<IA, B>());\n\n        Assert.IsType<A>(container.Resolve<IA>());\n\n        var tenant = container.GetChildContainer(\"A\");\n\n        Assert.NotNull(tenant);\n        Assert.IsType<B>(tenant?.Resolve<IA>());\n    }\n\n    [Fact]\n    public void ChildContainerTests_Configure_Dep()\n    {\n        var container = new StashboxContainer();\n        container.Register<D>();\n        container.Register<IA, A>();\n\n        container.CreateChildContainer(\"A\", c => c.Register<IA, B>());\n\n        var tenant = container.GetChildContainer(\"A\");\n\n        Assert.IsType<A>(container.Resolve<D>().Ia);\n        Assert.IsType<B>(tenant?.Resolve<D>().Ia);\n    }\n\n    [Fact]\n    public void ChildContainerTests_Configure_Validate_Root_Throws()\n    {\n        var container = new StashboxContainer();\n        container.Register<D>();\n\n        container.CreateChildContainer(\"A\", c => c.Register<IA, B>());\n\n        var exception = Assert.Throws<AggregateException>(() => container.Validate());\n        Assert.Single(exception.InnerExceptions);\n    }\n\n    [Fact]\n    public void ChildContainerTests_Configure_Validate_Root_And_Tenants_Throws()\n    {\n        var container = new StashboxContainer();\n        container.Register<D>();\n\n        container.CreateChildContainer(\"A\", c => c.Register<D>());\n\n        var exception = Assert.Throws<AggregateException>(() => container.Validate());\n        Assert.Equal(2, exception.InnerExceptions.Count);\n    }\n\n    [Fact]\n    public void ChildContainerTests_Configure_Validate_Valid()\n    {\n        var container = new StashboxContainer();\n        container.Register<IA, A>();\n\n        container.CreateChildContainer(\"A\", c => c.Register<D>());\n\n        var exception = Record.Exception(() => container.Validate());\n        Assert.Null(exception);\n    }\n\n    [Fact]\n    public void ChildContainerTests_Dispose()\n    {\n        var container = new StashboxContainer(c => c.WithDisposableTransientTracking());\n        container.Register<IA, C>();\n\n        var tenant = container.CreateChildContainer(\"C\", c => { });\n\n        var inst = (C)tenant.Resolve<IA>();\n\n        container.Dispose();\n\n        Assert.True(inst.Disposed);\n        Assert.Throws<ObjectDisposedException>(() => container.Resolve<IA>());\n        Assert.Throws<ObjectDisposedException>(() => tenant.Resolve<IA>());\n    }\n\n    [Fact]\n    public void ChildContainerTests_Dispose_Tenant()\n    {\n        var container = new StashboxContainer(c => c.WithDisposableTransientTracking());\n\n        container.CreateChildContainer(\"C\", c => c.Register<IA, C>());\n        var tenant = container.GetChildContainer(\"C\");\n\n        var inst = (C)tenant?.Resolve<IA>();\n\n        container.Dispose();\n\n        Assert.True(inst?.Disposed);\n\n        Assert.Throws<ObjectDisposedException>(() => container.Resolve<IA>());\n        Assert.Throws<ObjectDisposedException>(() => tenant?.Resolve<IA>());\n    }\n\n    [Fact]\n    public void ChildContainerTests_Dispose_Multiple()\n    {\n        var container = new StashboxContainer();\n        container.Register<IA, C>();\n\n        Assert.Null(Record.Exception(() => container.Dispose()));\n        Assert.Null(Record.Exception(() => container.Dispose()));\n    }\n    \n    [Fact]\n    public void ChildContainerTests_Dispose_Removes_Child()\n    {\n        var container = new StashboxContainer();\n        var a = container.CreateChildContainer(\"A\");\n        container.CreateChildContainer(\"B\");\n        var b = container.GetChildContainer(\"B\");\n        \n        Assert.Equal(2, container.ChildContainers.Count());\n        \n        a.Dispose();\n\n        Assert.Single(container.ChildContainers);\n        \n        b?.Dispose();\n        \n        Assert.Empty(container.ChildContainers);\n    }\n    \n    [Fact]\n    public void ChildContainerTests_Dispose_Parent()\n    {\n        var container = new StashboxContainer();\n        container.CreateChildContainer(\"A\");\n        container.CreateChildContainer(\"B\");\n        \n        Assert.Equal(2, container.ChildContainers.Count());\n        \n        container.Dispose();\n        \n        Assert.Empty(container.ChildContainers);\n    }\n    \n#if HAS_ASYNC_DISPOSABLE\n    [Fact]\n    public async Task ChildContainerTests_Dispose_Async()\n    {\n        var container = new StashboxContainer(c => c.WithDisposableTransientTracking());\n        container.Register<IA, C>();\n\n        var tenant = container.CreateChildContainer(\"C\", c => { });\n\n        var inst = (C)tenant.Resolve<IA>();\n\n        await container.DisposeAsync();\n\n        Assert.True(inst.Disposed);\n        Assert.Throws<ObjectDisposedException>(() => container.Resolve<IA>());\n        Assert.Throws<ObjectDisposedException>(() => tenant.Resolve<IA>());\n    }\n\n    [Fact]\n    public async Task MultitenantTests_Dispose_Tenant_Async()\n    {\n        var container = new StashboxContainer(c => c.WithDisposableTransientTracking());\n\n        container.CreateChildContainer(\"C\", c => c.Register<IA, C>());\n        var tenant = container.GetChildContainer(\"C\");\n\n        var inst = (C)tenant?.Resolve<IA>();\n\n        await container.DisposeAsync();\n\n        Assert.True(inst?.Disposed);\n\n        Assert.Throws<ObjectDisposedException>(() => container.Resolve<IA>());\n        Assert.Throws<ObjectDisposedException>(() => tenant?.Resolve<IA>());\n    }\n\n    [Fact]\n    public async Task MultitenantTests_Dispose_Multiple_Async()\n    {\n        var container = new StashboxContainer();\n        container.Register<IA, C>();\n\n        Assert.Null(await Record.ExceptionAsync(async () => await container.DisposeAsync()));\n        Assert.Null(await Record.ExceptionAsync(async () => await container.DisposeAsync()));\n    }\n    \n    [Fact]\n    public async Task ChildContainerTests_Dispose_Removes_Child_Async()\n    {\n        var container = new StashboxContainer();\n        var a = container.CreateChildContainer(\"A\");\n        container.CreateChildContainer(\"B\");\n        var b = container.GetChildContainer(\"B\");\n        \n        Assert.Equal(2, container.ChildContainers.Count());\n        \n        await a.DisposeAsync();\n\n        Assert.Single(container.ChildContainers);\n        \n        await b!.DisposeAsync();\n        \n        Assert.Empty(container.ChildContainers);\n    }\n#endif\n\n    interface IT;\n    interface IT2;\n    \n    class T1 : IT;\n    class T2 : IT;\n    class T3 : IT;\n    class T4 : IT;\n\n    class T11 : IT2;\n    class T12 : IT2;\n    class T13 : IT2;\n    \n    class T5 : IT\n    {\n        public IEnumerable<IT> Dep { get; }\n        public T5(IEnumerable<IT> Dep) { this.Dep = Dep; }\n    }\n    \n    class T6 : IT\n    {\n        public string ID { get; private set; }\n        public IT Dep { get; }\n        public T6(IT Dep) { this.Dep = Dep; }\n        public void Init(string id) => ID = id;\n    }\n\n    class D1\n    {\n        public string ID { get; private set; }\n        public IT Dep { get; }\n        public D1(IT Dep) { this.Dep = Dep; }\n        public void Init(string id) => ID = id;\n    }\n    \n    class D2\n    {\n        public string ID { get; private set; }\n        public IEnumerable<IT> Dep { get; }\n        public D2(IEnumerable<IT> Dep) { this.Dep = Dep; }\n        public void Init(string id) => ID = id;\n    }\n    \n    class D2_2\n    {\n        public string ID { get; private set; }\n        public IEnumerable<IT2> Dep { get; }\n        public D2_2(IEnumerable<IT2> Dep) { this.Dep = Dep; }\n        public void Init(string id) => ID = id;\n    }\n\n    class Test : IDisposable\n    { \n        public bool Disposed { get; private set; }\n\n        public void Dispose()\n        {\n            if (this.Disposed)\n            {\n                throw new ObjectDisposedException(nameof(Test));\n            }\n\n            this.Disposed = true;\n        }\n    }\n    \n    interface IA;\n\n    class A : IA;\n\n    class B : IA;\n\n    class C : IA, IDisposable\n    {\n        public bool Disposed { get; private set; }\n\n        public void Dispose()\n        {\n            if (this.Disposed)\n                throw new ObjectDisposedException(nameof(C));\n\n            this.Disposed = true;\n        }\n    }\n\n    class D\n    {\n        public D(IA ia)\n        {\n            Ia = ia;\n        }\n\n        public IA Ia { get; }\n    }\n}"
  },
  {
    "path": "test/CircularDependencyTests.cs",
    "content": "﻿using Stashbox.Attributes;\nusing Stashbox.Exceptions;\nusing System;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\nusing Xunit;\n\nnamespace Stashbox.Tests;\n\npublic class CircularDependencyTests\n{\n    [Fact]\n    public void CircularDependencyTests_StandardResolve()\n    {\n        using var container = new StashboxContainer();\n        container.Register<ITest1, Test1>();\n        var exception = Assert.Throws<ResolutionFailedException>(container.Resolve<ITest1>);\n        Assert.Equal(typeof(Test1), exception.Type);\n        Assert.Contains(\"Circular dependency was detected while resolving\", exception.Message);\n    }\n    \n    [Fact]\n    public void CircularDependencyTests_StandardResolve_Exception_Override()\n    {\n        using var container = new StashboxContainer(c => c.OverrideResolutionFailedExceptionWith<InvalidOperationException>());\n        container.Register<ITest1, Test1>();\n        var exception = Assert.Throws<InvalidOperationException>(container.Resolve<ITest1>);\n        Assert.Contains(\"Circular dependency was detected while resolving\", exception.Message);\n    }\n\n    [Fact]\n    public void CircularDependencyTests_StandardResolve_Parallel_ShouldNotThrow()\n    {\n        using var container = new StashboxContainer();\n        container.Register<ITest1, Test4>();\n        Parallel.For(0, 5000, i =>\n        {\n            container.Resolve<ITest1>();\n        });\n    }\n\n    [Fact]\n    public void CircularDependencyTests_DependencyProperty()\n    {\n        using var container = new StashboxContainer();\n        container.Register<ITest1, Test2>();\n        Assert.Throws<ResolutionFailedException>(container.Resolve<ITest1>);\n    }\n\n    [Fact]\n    public void CircularDependencyTests_InjectionMethod()\n    {\n        using var container = new StashboxContainer();\n        container.Register<ITest1, Test3>();\n        Assert.Throws<ResolutionFailedException>(container.Resolve<ITest1>);\n    }\n\n    [Fact]\n    public void CircularDependencyTests_Generic_StandardResolve()\n    {\n        using var container = new StashboxContainer();\n        container.Register(typeof(ITest1<,>), typeof(Test1<,>));\n        Assert.Throws<ResolutionFailedException>(container.Resolve<ITest1<int, int>>);\n    }\n\n    [Fact]\n    public void CircularDependencyTests_Generic_DependencyProperty()\n    {\n        using var container = new StashboxContainer();\n        container.Register(typeof(ITest1<,>), typeof(Test2<,>));\n        Assert.Throws<ResolutionFailedException>(container.Resolve<ITest1<int, int>>);\n    }\n\n    [Fact]\n    public void CircularDependencyTests_Generic_InjectionMethod()\n    {\n        using var container = new StashboxContainer();\n        container.Register(typeof(ITest1<,>), typeof(Test3<,>));\n        Assert.Throws<ResolutionFailedException>(container.Resolve<ITest1<int, int>>);\n    }\n\n    [Fact]\n    public void CircularDependencyTests_Func()\n    {\n        using var container = new StashboxContainer();\n        container.Register<ITest1, Test5>();\n        Assert.Throws<ResolutionFailedException>(container.Resolve<ITest1>);\n    }\n\n    [Fact]\n    public void CircularDependencyTests_Lazy()\n    {\n        using var container = new StashboxContainer();\n        container.Register<ITest1, Test6>();\n        Assert.Throws<ResolutionFailedException>(container.Resolve<ITest1>);\n    }\n\n    [Fact]\n    public void CircularDependencyTests_Tuple()\n    {\n        using var container = new StashboxContainer();\n        container.Register<ITest1, Test7>(c => c.WithMetadata(new object()));\n        Assert.Throws<ResolutionFailedException>(container.Resolve<ITest1>);\n    }\n\n    [Fact]\n    public void CircularDependencyTests_Enumerable()\n    {\n        using var container = new StashboxContainer();\n        container.Register<ITest1, Test8>();\n        Assert.Throws<ResolutionFailedException>(container.Resolve<ITest1>);\n    }\n\n    [Fact]\n    public void CircularDependencyTests_Runtime()\n    {\n        using var container = new StashboxContainer();\n        container.Register<ITest1, Test1>(config => config.WithFactory<ITest1>(d => new Test1(d)));\n        Assert.Throws<ResolutionFailedException>(container.Resolve<ITest1>);\n    }\n\n    [Fact]\n    public void CircularDependencyTests_Runtime_Parameterized_Factory()\n    {\n        using var container = new StashboxContainer();\n        container.Register<ITest1, Test1>(config => config.WithFactory<ITest1>(t => (Test1)t));\n        Assert.Throws<ResolutionFailedException>(container.Resolve<ITest1>);\n    }\n\n#if HAS_ASYNC_DISPOSABLE\n        [Fact]\n        public async Task CircularDependencyTests_Runtime_Async()\n        {\n            await using var container = new StashboxContainer();\n            container.Register<ITest1, Test1>(config => config.WithFactory<ITest1>(t => new Test1(t)));\n            Assert.Throws<ResolutionFailedException>(container.Resolve<ITest1>);\n        }\n\n        [Fact]\n        public async Task CircularDependencyTests_Runtime_Async_Parameterized_Factory()\n        {\n            await using var container = new StashboxContainer();\n            container.Register<ITest1, Test1>(config => config.WithFactory<ITest1>(t => (Test1)t));\n            Assert.Throws<ResolutionFailedException>(container.Resolve<ITest1>);\n        }\n#endif\n\n    interface ITest1;\n\n    interface ITest2;\n\n    interface ITest3;\n\n    interface ITest1<I, K>;\n\n    class Test4 : ITest1;\n\n    class Test1<I, K> : ITest1<I, K>\n    {\n        public Test1(ITest1<I, K> test1)\n        {\n        }\n    }\n\n    class Test2<I, K> : ITest1<I, K>\n    {\n        [Dependency]\n        public ITest1<I, K> Test1 { get; set; }\n    }\n\n    class Test3<I, K> : ITest1<I, K>\n    {\n        [InjectionMethod]\n        public void Inject(ITest1<I, K> test1)\n        { }\n    }\n\n    class Test1 : ITest1\n    {\n        public Test1(ITest1 test1)\n        {\n        }\n    }\n\n    class Test2 : ITest1\n    {\n        [Dependency]\n        public ITest1 Test1 { get; set; }\n    }\n\n    class Test3 : ITest1\n    {\n        [InjectionMethod]\n        public void Inject(ITest1 test1)\n        { }\n    }\n\n    class Test5 : ITest1\n    {\n        public Test5(Func<ITest1> test1)\n        {\n        }\n    }\n\n    class Test6 : ITest1\n    {\n        public Test6(Lazy<ITest1> test1)\n        {\n        }\n    }\n\n    class Test7 : ITest1\n    {\n        public Test7(Tuple<ITest1, object> test1)\n        {\n        }\n    }\n\n    class Test8 : ITest1\n    {\n        public Test8(IEnumerable<ITest1> test1)\n        {\n        }\n    }\n}"
  },
  {
    "path": "test/CompilerTests/ConstantTests.cs",
    "content": "﻿using System;\nusing System.Linq.Expressions;\nusing Xunit;\n\nnamespace Stashbox.Tests.CompilerTests;\n\npublic class ConstantTests\n{\n    enum FakeEnum { Default }\n\n    [Theory]\n    [InlineData(2)]\n    [InlineData(true)]\n    [InlineData((byte)4)]\n    [InlineData((char)5)]\n    [InlineData((ushort)6)]\n    [InlineData((uint)7)]\n    [InlineData((ulong)8)]\n    [InlineData((sbyte)9)]\n    [InlineData((short)10)]\n    [InlineData((long)11)]\n    [InlineData(\"test\")]\n    [InlineData((float)12)]\n    [InlineData((double)13)]\n    [InlineData(typeof(object))]\n    [InlineData(FakeEnum.Default)]\n    public void Compile_Constant_Values(object expectedResult)\n    {\n        var func = expectedResult.AsConstant().ConvertTo(typeof(object)).AsLambda<Func<object>>().CompileFunc();\n\n        Assert.NotNull(func);\n        Assert.Equal(expectedResult, func());\n    }\n}"
  },
  {
    "path": "test/CompilerTests/DefaultTests.cs",
    "content": "﻿using System;\nusing System.Linq.Expressions;\nusing Xunit;\n\nnamespace Stashbox.Tests.CompilerTests;\n\npublic class DefaultTests\n{\n    [Theory]\n    [InlineData(typeof(int), default(int))]\n    [InlineData(typeof(bool), default(bool))]\n    [InlineData(typeof(byte), default(byte))]\n    [InlineData(typeof(char), default(char))]\n    [InlineData(typeof(ushort), default(ushort))]\n    [InlineData(typeof(uint), default(uint))]\n    [InlineData(typeof(ulong), default(ulong))]\n    [InlineData(typeof(sbyte), default(sbyte))]\n    [InlineData(typeof(short), default(short))]\n    [InlineData(typeof(long), default(long))]\n    [InlineData(typeof(string), default(string))]\n    [InlineData(typeof(float), default(float))]\n    [InlineData(typeof(double), default(double))]\n    [InlineData(typeof(object), default)]\n    public void Compile_Default_Values(Type type, object expectedResult)\n    {\n        var func = type.AsDefault().ConvertTo(typeof(object)).AsLambda<Func<object>>().CompileFunc();\n\n        Assert.NotNull(func);\n        Assert.Equal(expectedResult, func());\n    }\n\n    [Fact]\n    public void Compile_DateTime_Default_Value()\n    {\n        var func = typeof(DateTime).AsDefault().AsLambda<Func<DateTime>>().CompileFunc();\n\n        Assert.NotNull(func);\n        Assert.Equal(default, func());\n    }\n\n    [Fact]\n    public void Compile_TimeSpan_Default_Value()\n    {\n        var func = typeof(TimeSpan).AsDefault().AsLambda<Func<TimeSpan>>().CompileFunc();\n\n        Assert.NotNull(func);\n        Assert.Equal(default, func());\n    }\n\n    [Fact]\n    public void Compile_Decimal_Default_Value()\n    {\n        var func = typeof(decimal).AsDefault().AsLambda<Func<decimal>>().CompileFunc();\n\n        Assert.NotNull(func);\n        Assert.Equal(default, func());\n    }\n}"
  },
  {
    "path": "test/CompilerTests/NullableTests.cs",
    "content": "﻿using System;\nusing System.Linq.Expressions;\nusing Xunit;\n\nnamespace Stashbox.Tests.CompilerTests;\n\npublic class NullableTests\n{\n    [Fact]\n    public void Compile_Nullable_Primitive()\n    {\n        Expression<Func<int?>> expr = () => 5;\n        var func = expr.CompileFunc();\n\n        Assert.Equal(5, func().Value);\n    }\n\n    [Fact]\n    public void Compile_Nullable_Primitive_Null()\n    {\n        Expression<Func<int?>> expr = () => null;\n        var func = expr.CompileFunc();\n\n        Assert.False(func().HasValue);\n    }\n\n    [Fact]\n    public void Compile_Nullable_ValueType()\n    {\n        Expression<Func<TimeSpan?>> expr = () => TimeSpan.FromSeconds(1);\n        var func = expr.CompileFunc();\n\n        Assert.Equal(TimeSpan.FromSeconds(1), func().Value);\n    }\n\n    [Fact]\n    public void Compile_Nullable_ValueType_Null()\n    {\n        Expression<Func<TimeSpan?>> expr = () => null;\n        var func = expr.CompileFunc();\n\n        Assert.False(func().HasValue);\n    }\n}"
  },
  {
    "path": "test/ComplexResolution.cs",
    "content": "﻿using Stashbox.Configuration;\nusing Stashbox.Tests.Utils;\nusing Xunit;\n\nnamespace Stashbox.Tests;\n\npublic class ComplexResolution\n{\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void Ensure_Complex_Resolution_Works(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithDisposableTransientTracking().WithCompiler(compilerType))\n            .Register<T1>()\n            .Register<T2>()\n            .Register<T3>()\n            .Register<T4>()\n            .RegisterScoped<Scoped1>()\n            .RegisterScoped<Scoped2>()\n            .RegisterScoped<Scoped3>()\n            .RegisterSingleton<Single1>()\n            .RegisterSingleton<Single2>()\n            .RegisterSingleton<Single3>()\n            .Register<Func1>(c => c.WithFactory(r => new Func1(r.Resolve<T4>(), r.Resolve<Scoped3>(), r.Resolve<Single3>())))\n            .Register<Func2>(c => c.WithFactory(r => new Func2(r.Resolve<T4>(), r.Resolve<Single1>(), r.Resolve<Single2>())));\n\n        {\n            using var scope = container.BeginScope();\n            var t1 = scope.Resolve<T1>();\n\n            Assert.NotNull(t1);\n            Assert.NotNull(t1.T2);\n            Assert.NotNull(t1.Single1);\n            Assert.NotNull(t1.Scoped1);\n            Assert.NotNull(t1.Scoped2);\n            Assert.NotNull(t1.T2.T3);\n            Assert.NotNull(t1.T2.T4);\n            Assert.NotNull(t1.T2.Single1);\n            Assert.NotNull(t1.T2.Single2);\n            Assert.NotNull(t1.T2.Scoped1);\n            Assert.NotNull(t1.T2.Scoped3);\n            Assert.NotNull(t1.Single1.Single2);\n            Assert.NotNull(t1.Single1.Single3);\n            Assert.NotNull(t1.Scoped1.T4);\n            Assert.NotNull(t1.Scoped1.Single1);\n            Assert.NotNull(t1.Scoped1.Scoped2);\n            Assert.NotNull(t1.Scoped1.Func1);\n            Assert.NotNull(t1.Scoped2.T4);\n            Assert.NotNull(t1.Scoped2.Single2);\n            Assert.NotNull(t1.Scoped2.Single3);\n            Assert.NotNull(t1.Scoped2.Scoped3);\n            Assert.NotNull(t1.Scoped2.Func2);\n            Assert.NotNull(t1.T2.T3.T4);\n            Assert.NotNull(t1.T2.T3.Scoped1);\n            Assert.NotNull(t1.T2.T3.Scoped3);\n            Assert.NotNull(t1.T2.T3.Single3);\n            Assert.NotNull(t1.Scoped1.Func1.T4);\n            Assert.NotNull(t1.Scoped1.Func1.Scoped3);\n            Assert.NotNull(t1.Scoped1.Func1.Single3);\n        }\n\n        {\n            using var scope1 = container.BeginScope();\n            var t2 = scope1.Resolve<T2>();\n\n            Assert.NotNull(t2);\n            Assert.NotNull(t2.T3);\n            Assert.NotNull(t2.T4);\n            Assert.NotNull(t2.Single1);\n            Assert.NotNull(t2.Single2);\n            Assert.NotNull(t2.Scoped1);\n            Assert.NotNull(t2.Scoped3);\n            Assert.NotNull(t2.Single1.Single2);\n            Assert.NotNull(t2.Single1.Single3);\n            Assert.NotNull(t2.Scoped1.T4);\n            Assert.NotNull(t2.Scoped1.Single1);\n            Assert.NotNull(t2.Scoped1.Scoped2);\n            Assert.NotNull(t2.Scoped1.Func1);\n            Assert.NotNull(t2.T3.T4);\n            Assert.NotNull(t2.T3.Scoped1);\n            Assert.NotNull(t2.T3.Scoped3);\n            Assert.NotNull(t2.T3.Single3);\n            Assert.NotNull(t2.Scoped1.Func1.T4);\n            Assert.NotNull(t2.Scoped1.Func1.Scoped3);\n            Assert.NotNull(t2.Scoped1.Func1.Single3);\n        }\n    }\n\n    class T1\n    {\n        public T1(T2 t2, Scoped1 scoped1, Scoped2 scoped2, Single1 single1)\n        {\n            T2 = t2;\n            Scoped1 = scoped1;\n            Scoped2 = scoped2;\n            Single1 = single1;\n        }\n\n        public T2 T2 { get; }\n        public Scoped1 Scoped1 { get; }\n        public Scoped2 Scoped2 { get; }\n        public Single1 Single1 { get; }\n    }\n\n    class T2\n    {\n        public T2(T3 t3, T4 t4, Scoped1 scoped1, Scoped3 scoped3, Single1 single1, Single2 single2)\n        {\n            T3 = t3;\n            T4 = t4;\n            Scoped1 = scoped1;\n            Scoped3 = scoped3;\n            Single1 = single1;\n            Single2 = single2;\n        }\n\n        public T3 T3 { get; }\n        public T4 T4 { get; }\n        public Scoped1 Scoped1 { get; }\n        public Scoped3 Scoped3 { get; }\n        public Single1 Single1 { get; }\n        public Single2 Single2 { get; }\n    }\n\n    class T3\n    {\n        public T3(T4 t4, Scoped1 scoped1, Scoped3 scoped3, Single3 single3)\n        {\n            T4 = t4;\n            Scoped1 = scoped1;\n            Scoped3 = scoped3;\n            Single3 = single3;\n        }\n\n        public T4 T4 { get; }\n        public Scoped1 Scoped1 { get; }\n        public Scoped3 Scoped3 { get; }\n        public Single3 Single3 { get; }\n    }\n\n    class T4;\n\n    class Scoped1\n    {\n        public Scoped1(T4 t4, Scoped2 scoped2, Func1 func1, Single1 single1)\n        {\n            T4 = t4;\n            Scoped2 = scoped2;\n            Func1 = func1;\n            Single1 = single1;\n        }\n\n        public T4 T4 { get; }\n        public Scoped2 Scoped2 { get; }\n        public Func1 Func1 { get; }\n        public Single1 Single1 { get; }\n    }\n\n    class Scoped2\n    {\n        public Scoped2(T4 t4, Scoped3 scoped3, Func2 func2, Single2 single2, Single3 single3)\n        {\n            T4 = t4;\n            Scoped3 = scoped3;\n            Func2 = func2;\n            Single2 = single2;\n            Single3 = single3;\n        }\n\n        public T4 T4 { get; }\n        public Scoped3 Scoped3 { get; }\n        public Func2 Func2 { get; }\n        public Single2 Single2 { get; }\n        public Single3 Single3 { get; }\n    }\n\n    class Scoped3;\n\n    class Single1\n    {\n        public Single1(Single2 single2, Single3 single3)\n        {\n            Single2 = single2;\n            Single3 = single3;\n        }\n\n        public Single2 Single2 { get; }\n        public Single3 Single3 { get; }\n    }\n\n    class Single2\n    {\n        public Single2(Single3 single3)\n        {\n            Single3 = single3;\n        }\n\n        public Single3 Single3 { get; }\n    }\n\n    class Single3;\n\n    class Func1\n    {\n        public Func1(T4 t4, Scoped3 scoped3, Single3 single3)\n        {\n            T4 = t4;\n            Scoped3 = scoped3;\n            Single3 = single3;\n        }\n\n        public T4 T4 { get; }\n        public Scoped3 Scoped3 { get; }\n        public Single3 Single3 { get; }\n    }\n\n    class Func2\n    {\n        public Func2(T4 t4, Single1 single1, Single2 single2)\n        {\n            T4 = t4;\n            Single1 = single1;\n            Single2 = single2;\n        }\n        public T4 T4 { get; }\n        public Single1 Single1 { get; }\n        public Single2 Single2 { get; }\n    }\n}"
  },
  {
    "path": "test/CompositionTests.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing TestAssembly;\nusing Xunit;\n\nnamespace Stashbox.Tests;\n\npublic class CompositionTests\n{\n    [Fact]\n    public void Composition_Test()\n    {\n        using var container = new StashboxContainer()\n            .Register<IA, A>()\n            .Register<IB, B>()\n            .Register<IC, C>()\n            .RegisterDecorator<IA, D1>(c => c.AsImplementedTypes());\n\n        var a = container.Resolve<IA>();\n\n        Assert.IsType<D1>(a);\n        Assert.IsType<A>(((D1)a).A);\n        Assert.IsType<B>(((D1)a).B);\n        Assert.IsType<C>(((D1)a).C);\n\n        var b = container.Resolve<IB>();\n\n        Assert.IsType<D1>(b);\n        Assert.IsType<A>(((D1)b).A);\n        Assert.IsType<B>(((D1)b).B);\n        Assert.IsType<C>(((D1)b).C);\n\n        var c = container.Resolve<IC>();\n\n        Assert.IsType<D1>(c);\n        Assert.IsType<A>(((D1)c).A);\n        Assert.IsType<B>(((D1)c).B);\n        Assert.IsType<C>(((D1)c).C);\n    }\n\n    [Fact]\n    public void Composition_Test_Generic()\n    {\n        using var container = new StashboxContainer()\n            .Register(typeof(IG<>), typeof(G<>))\n            .Register(typeof(IG1<>), typeof(G1<>))\n            .RegisterDecorator(typeof(D4<>));\n\n        var m = container.ContainerContext.DecoratorRepository.GetRegistrationMappings();\n\n        var a = container.Resolve<IG<string>>();\n\n        Assert.IsType<D4<string>>(a);\n        Assert.IsType<G<string>>(((D4<string>)a).A);\n        Assert.IsType<G1<string>>(((D4<string>)a).B);\n\n        var b = container.Resolve<IG1<string>>();\n\n        Assert.IsType<D4<string>>(a);\n        Assert.IsType<G<string>>(((D4<string>)a).A);\n        Assert.IsType<G1<string>>(((D4<string>)a).B);\n    }\n\n    [Fact]\n    public void Composition_Test_MultipleDecorators()\n    {\n        using var container = new StashboxContainer()\n            .Register<IA, A>()\n            .Register<IB, B>()\n            .Register<IC, C>()\n            .RegisterDecorator<IA, AD>()\n            .RegisterDecorator<IB, BD>()\n            .RegisterDecorator<IC, CD>()\n            .RegisterDecorator<D1>();\n\n        var d = container.Resolve<IA>();\n\n        Assert.IsType<D1>(d);\n        Assert.IsType<AD>(((D1)d).A);\n        Assert.IsType<A>(((AD)((D1)d).A).A);\n        Assert.IsType<BD>(((D1)d).B);\n        Assert.IsType<B>(((BD)((D1)d).B).B);\n        Assert.IsType<CD>(((D1)d).C);\n        Assert.IsType<C>(((CD)((D1)d).C).C);\n    }\n\n    [Fact]\n    public void Composition_Test_MultipleDecorators_Factory()\n    {\n        using var container = new StashboxContainer()\n            .Register<IA, A>()\n            .Register<IB, B>()\n            .Register<IC, C>()\n            .RegisterDecorator<IA, AD>()\n            .RegisterDecorator<IB, BD>()\n            .RegisterDecorator<IC, CD>()\n            .RegisterDecorator<D1>(c => c.WithFactory<IA, IA, IB, IC>((a, a1, b, c) =>\n            {\n                Assert.IsType<AD>(a);\n                Assert.IsType<A>(((AD)a).A);\n                Assert.IsType<AD>(a1);\n                Assert.IsType<A>(((AD)a1).A);\n                Assert.IsType<BD>(b);\n                Assert.IsType<B>(((BD)b).B);\n                Assert.IsType<CD>(c);\n                Assert.IsType<C>(((CD)c).C);\n\n                return new D1(a, b, c);\n            }));\n\n        container.Resolve<IA>();\n    }\n\n    [Fact]\n    public void Composition_Test_MultipleDecorators_Non_Generic_Factory()\n    {\n        using var container = new StashboxContainer()\n            .Register<IA, A>()\n            .Register<IB, B>()\n            .Register<IC, C>()\n            .RegisterDecorator<IA, AD>()\n            .RegisterDecorator<IB, BD>()\n            .RegisterDecorator<IC, CD>()\n            .RegisterDecorator(typeof(D1), c => c.WithFactory<IA, IA, IB, IC>((a, a1, b, c) =>\n            {\n                Assert.IsType<AD>(a);\n                Assert.IsType<A>(((AD)a).A);\n                Assert.IsType<AD>(a1);\n                Assert.IsType<A>(((AD)a1).A);\n                Assert.IsType<BD>(b);\n                Assert.IsType<B>(((BD)b).B);\n                Assert.IsType<CD>(c);\n                Assert.IsType<C>(((CD)c).C);\n\n                return new D1(a, b, c);\n            }));\n\n        container.Resolve<IA>();\n    }\n\n    [Fact]\n    public void Composition_Test_Enumerable()\n    {\n        using var container = new StashboxContainer()\n            .Register<IA, A>()\n            .Register<IA, AA>()\n            .RegisterDecorator<IA, D2>();\n\n        var d = container.Resolve<IA>();\n\n        Assert.IsType<D2>(d);\n        Assert.IsAssignableFrom<IEnumerable<IA>>(((D2)d).A);\n        Assert.IsType<A>(((D2)d).A.ElementAt(0));\n        Assert.IsType<AA>(((D2)d).A.ElementAt(1));\n    }\n\n    [Fact]\n    public void Composition_Test_Enumerable_MultipleDecorators()\n    {\n        using var container = new StashboxContainer()\n            .Register<IA, A>()\n            .Register<IA, AA>()\n            .RegisterDecorator<IA, AD>()\n            .RegisterDecorator<IA, D2>();\n\n        var d = container.Resolve<IA>();\n\n        Assert.IsType<D2>(d);\n        Assert.IsType<AD>(((D2)d).A.ElementAt(0));\n        Assert.IsType<A>(((AD)((D2)d).A.ElementAt(0)).A);\n        Assert.IsType<AD>(((D2)d).A.ElementAt(1));\n        Assert.IsType<AA>(((AD)((D2)d).A.ElementAt(1)).A);\n    }\n\n    [Fact]\n    public void Composition_Test_Enumerable_Generic()\n    {\n        using var container = new StashboxContainer()\n            .Register(typeof(IG<>), typeof(G<>))\n            .Register(typeof(IG<>), typeof(GG<>))\n            .RegisterDecorator(typeof(IG<>), typeof(D3<>));\n\n        var d = container.Resolve<IG<string>>();\n\n        Assert.IsType<D3<string>>(d);\n        Assert.IsType<G<string>>(((D3<string>)d).G.ElementAt(0));\n        Assert.IsType<GG<string>>(((D3<string>)d).G.ElementAt(1));\n    }\n\n    [Fact]\n    public void Composition_Named_From_DifferentAssembly()\n    {\n        using var container = new StashboxContainer()\n            .ComposeAssembly(typeof(Composition).Assembly);\n\n        container.RegisterFunc<string, bool>((name, resolver) => container.IsRegistered<IComp>(\"Comp\"), name: \"IsTokenProviderRegistered\");\n        var factory = container.Resolve<Func<string, bool>>(\"IsTokenProviderRegistered\");\n\n        Assert.True(factory(\"Comp\"));\n    }\n\n    interface IA;\n\n    interface IB;\n\n    interface IC;\n\n    interface IG<T>;\n\n    interface IG1<T>;\n\n    class A : IA;\n\n    class AA : IA;\n\n    class B : IB;\n\n    class BB : IB;\n\n    class C : IC;\n\n    class CC : IC;\n\n    class G<T> : IG<T>;\n\n    class G1<T> : IG1<T>;\n\n    class GG<T>/*WP*/ : IG<T>;\n\n    class D1 : IA, IB, IC\n    {\n        public D1(IA a, IB b, IC c)\n        {\n            A = a;\n            B = b;\n            C = c;\n        }\n\n        public IA A { get; }\n        public IB B { get; }\n        public IC C { get; }\n    }\n\n    class D2 : IA\n    {\n        public D2(IEnumerable<IA> a)\n        {\n            A = a;\n        }\n\n        public IEnumerable<IA> A { get; }\n    }\n\n    class D3<T> : IG<T>\n    {\n        public D3(IEnumerable<IG<T>> g)\n        {\n            G = g;\n        }\n\n        public IEnumerable<IG<T>> G { get; }\n    }\n\n    class D4<T> : IG<T>, IG1<T>\n    {\n        public D4(IG<T> a, IG1<T> b)\n        {\n            A = a;\n            B = b;\n        }\n\n        public IG<T> A { get; }\n        public IG1<T> B { get; }\n    }\n\n    class AD : IA\n    {\n        public AD(IA a)\n        {\n            A = a;\n        }\n\n        public IA A { get; }\n    }\n\n    class BD : IB\n    {\n        public BD(IB b)\n        {\n            B = b;\n        }\n\n        public IB B { get; }\n    }\n\n    class CD : IC\n    {\n        public CD(IC c)\n        {\n            C = c;\n        }\n\n        public IC C { get; }\n    }\n}"
  },
  {
    "path": "test/ConditionalTests.cs",
    "content": "﻿using Stashbox.Attributes;\nusing System;\nusing Xunit;\n\nnamespace Stashbox.Tests;\n\npublic class ConditionalTests\n{\n    [Fact]\n    public void ConditionalTests_ParentTypeCondition_First()\n    {\n        var container = new StashboxContainer();\n        container.Register<ITest1, Test1>(context => context.WhenDependantIs<Test2>());\n        container.Register<ITest1, Test11>();\n        container.Register<ITest1, Test12>();\n        container.Register<ITest2, Test2>();\n\n        var test2 = container.Resolve<ITest2>();\n\n        Assert.IsType<Test1>(test2.test1);\n        Assert.IsType<Test1>(test2.test12);\n    }\n\n    [Fact]\n    public void ConditionalTests_ParentTypeCondition_When_First()\n    {\n        var container = new StashboxContainer();\n        container.Register<ITest1, Test1>(context => context.When(type => type.ParentType == typeof(Test2)));\n        container.Register<ITest1, Test11>();\n        container.Register<ITest1, Test12>();\n        container.Register<ITest2, Test2>();\n\n        var test2 = container.Resolve<ITest2>();\n\n        Assert.IsType<Test1>(test2.test1);\n        Assert.IsType<Test1>(test2.test12);\n    }\n\n    [Fact]\n    public void ConditionalTests_ParentTypeCondition_First_NonGeneric()\n    {\n        var container = new StashboxContainer();\n        container.Register<ITest1, Test1>(context => context.WhenDependantIs(typeof(Test2)));\n        container.Register<ITest1, Test11>();\n        container.Register<ITest1, Test12>();\n        container.Register<ITest2, Test2>();\n\n        var test2 = container.Resolve<ITest2>();\n\n        Assert.IsType<Test1>(test2.test1);\n        Assert.IsType<Test1>(test2.test12);\n    }\n\n    [Fact]\n    public void ConditionalTests_ParentTypeCondition_Second()\n    {\n        var container = new StashboxContainer();\n        container.Register<ITest1, Test1>();\n        container.Register<ITest1, Test11>(context => context.WhenDependantIs<Test2>());\n        container.Register<ITest1, Test12>();\n        container.Register<ITest2, Test2>();\n\n        var test2 = container.Resolve<ITest2>();\n\n        Assert.IsType<Test11>(test2.test1);\n        Assert.IsType<Test11>(test2.test12);\n    }\n\n    [Fact]\n    public void ConditionalTests_ParentTypeCondition_Second_NonGeneric()\n    {\n        var container = new StashboxContainer();\n        container.Register<ITest1, Test1>();\n        container.Register<ITest1, Test11>(context => context.WhenDependantIs(typeof(Test2)));\n        container.Register<ITest1, Test12>();\n        container.Register<ITest2, Test2>();\n\n        var test2 = container.Resolve<ITest2>();\n\n        Assert.IsType<Test11>(test2.test1);\n        Assert.IsType<Test11>(test2.test12);\n    }\n\n    [Fact]\n    public void ConditionalTests_ParentTypeCondition_Third()\n    {\n        var container = new StashboxContainer();\n        container.Register<ITest1, Test1>();\n        container.Register<ITest1, Test11>();\n        container.Register<ITest1, Test12>(context => context.WhenDependantIs<Test2>());\n        container.Register<ITest2, Test2>();\n\n        var test2 = container.Resolve<ITest2>();\n\n        Assert.IsType<Test12>(test2.test1);\n        Assert.IsType<Test12>(test2.test12);\n    }\n\n    [Fact]\n    public void ConditionalTests_ParentTypeCondition_Third_NonGeneric()\n    {\n        var container = new StashboxContainer();\n        container.Register<ITest1, Test1>();\n        container.Register<ITest1, Test11>();\n        container.Register<ITest1, Test12>(context => context.WhenDependantIs(typeof(Test2)));\n        container.Register<ITest2, Test2>();\n\n        var test2 = container.Resolve<ITest2>();\n\n        Assert.IsType<Test12>(test2.test1);\n        Assert.IsType<Test12>(test2.test12);\n    }\n\n    [Fact]\n    public void ConditionalTests_ParentTypeCondition_Third_WithName()\n    {\n        var name = \"A\".ToLower();\n        var container = new StashboxContainer();\n        container.Register<ITest1, Test1>();\n        container.Register<ITest1, Test11>();\n        container.Register<ITest1, Test12>(context => context.WhenDependantIs<Test2>(name));\n        container.Register<ITest2, Test2>(name);\n\n        var test2 = container.Resolve<ITest2>(name);\n\n        Assert.IsType<Test12>(test2.test1);\n        Assert.IsType<Test12>(test2.test12);\n    }\n\n    [Fact]\n    public void ConditionalTests_ParentTypeCondition_Third_NonGenericWithName()\n    {\n        var name = \"A\".ToLower();\n        var container = new StashboxContainer();\n        container.Register<ITest1, Test1>();\n        container.Register<ITest1, Test11>();\n        container.Register<ITest1, Test12>(context => context.WhenDependantIs(typeof(Test2), name));\n        container.Register<ITest2, Test2>(name);\n\n        var test2 = container.Resolve<ITest2>(name);\n\n        Assert.IsType<Test12>(test2.test1);\n        Assert.IsType<Test12>(test2.test12);\n    }\n\n    [Fact]\n    public void ConditionalTests_AttributeCondition_First()\n    {\n        var container = new StashboxContainer();\n        container.Register<ITest1, Test1>(context => context.WhenHas<TestConditionAttribute>());\n        container.Register<ITest1, Test11>();\n        container.Register<ITest1, Test12>(context => context.WhenHas<TestCondition2Attribute>());\n        container.Register<ITest2, Test3>();\n\n        var test3 = container.Resolve<ITest2>();\n\n        Assert.IsType<Test1>(test3.test1);\n        Assert.IsType<Test12>(test3.test12);\n    }\n\n    [Fact]\n    public void ConditionalTests_AttributeCondition_First_NonGeneric()\n    {\n        var container = new StashboxContainer();\n        container.Register<ITest1, Test1>(context => context.WhenHas(typeof(TestConditionAttribute)));\n        container.Register<ITest1, Test11>();\n        container.Register<ITest1, Test12>(context => context.WhenHas(typeof(TestCondition2Attribute)));\n        container.Register<ITest2, Test3>();\n\n        var test3 = container.Resolve<ITest2>();\n\n        Assert.IsType<Test1>(test3.test1);\n        Assert.IsType<Test12>(test3.test12);\n    }\n\n    [Fact]\n    public void ConditionalTests_AttributeCondition_Second()\n    {\n        var container = new StashboxContainer();\n        container.Register<ITest1, Test1>();\n        container.Register<ITest1, Test11>(context => context.WhenHas<TestCondition2Attribute>());\n        container.Register<ITest1, Test12>(context => context.WhenHas<TestConditionAttribute>());\n        container.Register<ITest2, Test3>();\n\n        var test3 = container.Resolve<ITest2>();\n\n        Assert.IsType<Test12>(test3.test1);\n        Assert.IsType<Test11>(test3.test12);\n    }\n\n    [Fact]\n    public void ConditionalTests_AttributeCondition_Second_NonGeneric()\n    {\n        var container = new StashboxContainer();\n        container.Register<ITest1, Test1>();\n        container.Register<ITest1, Test11>(context => context.WhenHas(typeof(TestCondition2Attribute)));\n        container.Register<ITest1, Test12>(context => context.WhenHas(typeof(TestConditionAttribute)));\n        container.Register<ITest2, Test3>();\n\n        var test3 = container.Resolve<ITest2>();\n\n        Assert.IsType<Test12>(test3.test1);\n        Assert.IsType<Test11>(test3.test12);\n    }\n\n    [Fact]\n    public void ConditionalTests_AttributeCondition_Third()\n    {\n        var container = new StashboxContainer();\n        container.Register<ITest1, Test1>(context => context.WhenHas<TestCondition2Attribute>());\n        container.Register<ITest1, Test11>(context => context.WhenHas<TestConditionAttribute>());\n        container.Register<ITest1, Test12>();\n        container.Register<ITest2, Test3>();\n\n        var test3 = container.Resolve<ITest2>();\n\n        Assert.IsType<Test11>(test3.test1);\n        Assert.IsType<Test1>(test3.test12);\n    }\n\n    [Fact]\n    public void ConditionalTests_AttributeCondition_Third_NonGeneric()\n    {\n        var container = new StashboxContainer();\n        container.Register<ITest1, Test1>(context => context.WhenHas(typeof(TestCondition2Attribute)));\n        container.Register<ITest1, Test11>(context => context.WhenHas(typeof(TestConditionAttribute)));\n        container.Register<ITest1, Test12>();\n        container.Register<ITest2, Test3>();\n\n        var test3 = container.Resolve<ITest2>();\n\n        Assert.IsType<Test11>(test3.test1);\n        Assert.IsType<Test1>(test3.test12);\n    }\n\n    [Fact]\n    public void ConditionalTests_AttributeCondition_Third_WithName()\n    {\n        var name = \"A\".ToLower();\n        var container = new StashboxContainer();\n        container.Register<ITest1, Test1>(context => context.WhenHas<TestCondition2Attribute>().WithName(name));\n        container.Register<ITest1, Test11>(context => context.WhenHas<TestCondition2Attribute>().WithName(\"B\"));\n        container.Register<ITest1, Test12>();\n        container.Register<ITest2, Test3>(context => context.WithDependencyBinding<ITest1>(name));\n\n        var test3 = container.Resolve<ITest2>();\n\n        Assert.IsType<Test12>(test3.test1);\n        Assert.IsType<Test1>(test3.test12);\n    }\n\n    [Fact]\n    public void ConditionalTests_AttributeCondition_Third_NonGeneric_WithName()\n    {\n        var name = \"A\".ToLower();\n        var container = new StashboxContainer();\n        container.Register<ITest1, Test1>(context => context.WhenHas(typeof(TestCondition2Attribute)).WithName(name));\n        container.Register<ITest1, Test11>(context => context.WhenHas(typeof(TestConditionAttribute)).WithName(\"B\"));\n        container.Register<ITest1, Test12>();\n        container.Register<ITest2, Test3>(context => context.WithDependencyBinding<ITest1>(name));\n\n        var test3 = container.Resolve<ITest2>();\n\n        Assert.IsType<Test12>(test3.test1);\n        Assert.IsType<Test1>(test3.test12);\n    }\n\n    [Fact]\n    public void ConditionalTests_Combined()\n    {\n        var container = new StashboxContainer();\n        container.Register<ITest1, Test1>(context => context.WhenDependantIs<Test4>().WhenDependantIs<Test5>());\n        container.Register<ITest1, Test11>();\n        container.Register<ITest1, Test12>();\n        container.Register<Test4>();\n        container.Register<Test5>();\n\n        var t1 = container.Resolve<Test4>();\n        var t2 = container.Resolve<Test5>();\n\n        Assert.IsType<Test1>(t1.Test);\n        Assert.IsType<Test1>(t2.Test);\n    }\n\n    [Fact]\n    public void ConditionalTests_Combined_Common()\n    {\n        var container = new StashboxContainer();\n        container.Register<ITest1, Test1>(context => context.When(t => t.ParentType == typeof(Test4)).When(t => t.ParentType == typeof(Test5)));\n        container.Register<ITest1, Test11>();\n        container.Register<ITest1, Test12>();\n        container.Register<Test4>();\n        container.Register<Test5>();\n\n        var t1 = container.Resolve<Test4>();\n        var t2 = container.Resolve<Test5>();\n\n        Assert.IsType<Test1>(t1.Test);\n        Assert.IsType<Test1>(t2.Test);\n    }\n\n    [Fact]\n    public void ConditionalTests_InResolutionPath()\n    {\n        var container = new StashboxContainer();\n        container.Register<Dummy>(context => context.WhenInResolutionPathOf<Test4>());\n        container.Register<Test4>();\n        container.Register<ITest1, Test13>();\n\n        var t = container.Resolve<Test4>();\n\n        Assert.NotNull(((Test13)t.Test).Dummy);\n    }\n\n    [Fact]\n    public void ConditionalTests_InResolutionPath_Attribute()\n    {\n        var container = new StashboxContainer();\n        container.Register<Dummy>(context => context.WhenResolutionPathHas<TestConditionAttribute>());\n        container.Register<Test6>();\n        container.Register<ITest1, Test13>();\n\n        var t = container.Resolve<Test6>();\n\n        Assert.NotNull(((Test13)t.Test).Dummy);\n    }\n\n    [Fact]\n    public void ConditionalTests_InResolutionPath_WithName()\n    {\n        var name = \"A\".ToLower();\n        var container = new StashboxContainer();\n        container.Register<Dummy>(context => context.WhenInResolutionPathOf<Test4>(name));\n        container.Register<Test4>(name);\n        container.Register<ITest1, Test13>();\n\n        var t = container.Resolve<Test4>(name);\n\n        Assert.NotNull(((Test13)t.Test).Dummy);\n    }\n\n    [Fact]\n    public void ConditionalTests_InResolutionPath_Attribute_WithName()\n    {\n        var name = \"A\".ToLower();\n        var container = new StashboxContainer();\n        container.Register<Dummy>(context => context.WhenResolutionPathHas<TestConditionAttribute>(name));\n        container.Register<Test6>(context => context.WithDependencyBinding<ITest1>(name));\n        container.Register<ITest1, Test13>(name);\n\n        var t = container.Resolve<Test6>();\n\n        Assert.NotNull(((Test13)t.Test).Dummy);\n    }\n\n    interface ITest1;\n\n    interface ITest2 { ITest1 test1 { get; set; } ITest1 test12 { get; set; } }\n\n    class Dummy;\n\n    class Test1 : ITest1;\n\n    class Test11 : ITest1;\n\n    class Test12 : ITest1;\n\n    class Test13 : ITest1\n    {\n        public Test13(Dummy dummy)\n        {\n            Dummy = dummy;\n        }\n\n        public Dummy Dummy { get; }\n    }\n\n    class Test2 : ITest2\n    {\n        [Dependency]\n        public ITest1 test1 { get; set; }\n        public ITest1 test12 { get; set; }\n\n        public Test2(ITest1 test12)\n        {\n            this.test12 = test12;\n        }\n    }\n\n    class Test3 : ITest2\n    {\n        [Dependency, TestCondition]\n        public ITest1 test1 { get; set; }\n\n        public ITest1 test12 { get; set; }\n\n        public Test3([TestCondition2] ITest1 test12)\n        {\n            this.test12 = test12;\n        }\n    }\n\n    class Test4\n    {\n        public Test4(ITest1 test)\n        {\n            Test = test;\n        }\n\n        public ITest1 Test { get; }\n    }\n\n    class Test5\n    {\n        public Test5(ITest1 test)\n        {\n            Test = test;\n        }\n\n        public ITest1 Test { get; }\n    }\n\n    class Test6\n    {\n        public Test6([TestCondition]ITest1 test)\n        {\n            Test = test;\n        }\n\n        public ITest1 Test { get; }\n    }\n\n    [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Parameter)]\n    class TestConditionAttribute : Attribute;\n\n    [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Parameter)]\n    class TestCondition2Attribute : Attribute;\n}"
  },
  {
    "path": "test/ConfigurationTests.cs",
    "content": "﻿using Stashbox.Configuration;\nusing Xunit;\n\nnamespace Stashbox.Tests;\n\npublic class ConfigurationTests\n{\n    [Fact]\n    public void Ensure_Unknown_Type_Configurations_Working()\n    {\n        using var container = new StashboxContainer(c => c.WithUnknownTypeResolution());\n        Assert.True(container.ContainerContext.ContainerConfiguration.UnknownTypeResolutionEnabled);\n        Assert.Null(container.ContainerContext.ContainerConfiguration.UnknownTypeConfigurator);\n\n        container.Configure(c => c.WithUnknownTypeResolution(co => { }));\n        Assert.True(container.ContainerContext.ContainerConfiguration.UnknownTypeResolutionEnabled);\n        Assert.NotNull(container.ContainerContext.ContainerConfiguration.UnknownTypeConfigurator);\n\n        container.Configure(c => c.WithUnknownTypeResolution(enabled: false));\n        Assert.False(container.ContainerContext.ContainerConfiguration.UnknownTypeResolutionEnabled);\n    }\n\n    [Fact]\n    public void Ensure_Auto_Member_Injection_Configurations_Working()\n    {\n        using var container = new StashboxContainer(c => c.WithAutoMemberInjection());\n        Assert.True(container.ContainerContext.ContainerConfiguration.AutoMemberInjectionEnabled);\n        Assert.Equal(Rules.AutoMemberInjectionRules.PropertiesWithPublicSetter, container.ContainerContext.ContainerConfiguration.AutoMemberInjectionRule);\n        Assert.Null(container.ContainerContext.ContainerConfiguration.AutoMemberInjectionFilter);\n\n        container.Configure(c => c.WithAutoMemberInjection(Rules.AutoMemberInjectionRules.PrivateFields));\n        Assert.True(container.ContainerContext.ContainerConfiguration.AutoMemberInjectionEnabled);\n        Assert.Equal(Rules.AutoMemberInjectionRules.PrivateFields, container.ContainerContext.ContainerConfiguration.AutoMemberInjectionRule);\n        Assert.Null(container.ContainerContext.ContainerConfiguration.AutoMemberInjectionFilter);\n\n        container.Configure(c => c.WithAutoMemberInjection(filter: m => true));\n        Assert.True(container.ContainerContext.ContainerConfiguration.AutoMemberInjectionEnabled);\n        Assert.Equal(Rules.AutoMemberInjectionRules.PropertiesWithPublicSetter, container.ContainerContext.ContainerConfiguration.AutoMemberInjectionRule);\n        Assert.NotNull(container.ContainerContext.ContainerConfiguration.AutoMemberInjectionFilter);\n\n        container.Configure(c => c.WithAutoMemberInjection(enabled: false));\n        Assert.False(container.ContainerContext.ContainerConfiguration.AutoMemberInjectionEnabled);\n    }\n\n    [Fact]\n    public void Ensure_Feature_Configurations_Working()\n    {\n        using var container = new StashboxContainer();\n\n        container.Configure(c => c.WithDefaultValueInjection());\n        Assert.True(container.ContainerContext.ContainerConfiguration.DefaultValueInjectionEnabled);\n\n        container.Configure(c => c.WithDefaultValueInjection(false));\n        Assert.False(container.ContainerContext.ContainerConfiguration.DefaultValueInjectionEnabled);\n\n\n        container.Configure(c => c.WithDisposableTransientTracking());\n        Assert.True(container.ContainerContext.ContainerConfiguration.TrackTransientsForDisposalEnabled);\n\n        container.Configure(c => c.WithDisposableTransientTracking(false));\n        Assert.False(container.ContainerContext.ContainerConfiguration.TrackTransientsForDisposalEnabled);\n\n\n        container.Configure(c => c.WithLifetimeValidation());\n        Assert.True(container.ContainerContext.ContainerConfiguration.LifetimeValidationEnabled);\n\n        container.Configure(c => c.WithLifetimeValidation(false));\n        Assert.False(container.ContainerContext.ContainerConfiguration.LifetimeValidationEnabled);\n\n\n        container.Configure(c => c.WithExpressionCompiler(Rules.ExpressionCompilers.MicrosoftExpressionCompiler));\n        Assert.NotNull(container.ContainerContext.ContainerConfiguration.ExternalExpressionCompiler);\n\n        container.Configure(c => c.WithExpressionCompiler(null));\n        Assert.Null(container.ContainerContext.ContainerConfiguration.ExternalExpressionCompiler);\n\n        Assert.True(container.ContainerContext.ContainerConfiguration.NamedDependencyResolutionForUnNamedCollectionRequestsEnabled);\n        container.Configure(c => c.WithNamedDependencyResolutionForUnNamedRequests());\n        Assert.True(container.ContainerContext.ContainerConfiguration.NamedDependencyResolutionForUnNamedRequestsEnabled);\n        container.Configure(c => c.WithNamedDependencyResolutionForUnNamedRequests(false, false));\n        Assert.False(container.ContainerContext.ContainerConfiguration.NamedDependencyResolutionForUnNamedRequestsEnabled);\n        Assert.False(container.ContainerContext.ContainerConfiguration.NamedDependencyResolutionForUnNamedCollectionRequestsEnabled);\n        \n        container.Configure(c => c.TreatParameterAndMemberNameAsDependencyName());\n        Assert.True(container.ContainerContext.ContainerConfiguration.TreatingParameterAndMemberNameAsDependencyNameEnabled);\n\n        container.Configure(c => c.TreatParameterAndMemberNameAsDependencyName(false));\n        Assert.False(container.ContainerContext.ContainerConfiguration.TreatingParameterAndMemberNameAsDependencyNameEnabled);\n    }\n\n    [Fact]\n    public void Ensure_Configuration_Change_Does_Not_Affect_Parent()\n    {\n        using var container = new StashboxContainer(c => c.WithLifetimeValidation());\n        Assert.True(container.ContainerContext.ContainerConfiguration.LifetimeValidationEnabled);\n\n        using var child = container.CreateChildContainer();\n        child.Configure(c => c.WithLifetimeValidation(false));\n\n        Assert.True(container.ContainerContext.ContainerConfiguration.LifetimeValidationEnabled);\n        Assert.False(child.ContainerContext.ContainerConfiguration.LifetimeValidationEnabled);\n    }\n}"
  },
  {
    "path": "test/ConstructorSelectionTests.cs",
    "content": "﻿using Stashbox.Exceptions;\nusing Xunit;\n\nnamespace Stashbox.Tests;\n\npublic class ConstructorSelectionTests\n{\n    [Fact]\n    public void ConstructorSelectionTests_ArgTypes()\n    {\n        using var container = new StashboxContainer(config => config.WithUnknownTypeResolution());\n        container.Register<Test>(context => context.WithConstructorByArgumentTypes(typeof(Dep), typeof(Dep2)));\n        Assert.NotNull(container.Resolve<Test>());\n    }\n\n    [Fact]\n    public void ConstructorSelectionTests_Args()\n    {\n        using var container = new StashboxContainer();\n        var dep = new Dep();\n        var dep2 = new Dep2();\n\n        container.Register<Test>(context => context.WithConstructorByArguments(dep, dep2));\n        var test = container.Resolve<Test>();\n\n        Assert.Same(dep, test.Dep);\n        Assert.Same(dep2, test.Dep2);\n    }\n\n    [Fact]\n    public void ConstructorSelectionTests_ArgTypes_Throws_ResolutionFailed()\n    {\n        using var container = new StashboxContainer();\n        container.Register<Test>(context => context.WithConstructorByArgumentTypes(typeof(Dep), typeof(Dep2)));\n        var exception = Assert.Throws<ResolutionFailedException>(() => container.Resolve<Test>());\n\n        Assert.Equal(typeof(Test), exception.Type);\n    }\n\n    [Fact]\n    public void ConstructorSelectionTests_ArgTypes_Throws_MissingConstructor()\n    {\n        using var container = new StashboxContainer();\n        Assert.Throws<ConstructorNotFoundException>(() => container.Register<Test>(context => context.WithConstructorByArgumentTypes()));\n    }\n\n    [Fact]\n    public void ConstructorSelectionTests_Args_Throws_MissingConstructor()\n    {\n        using var container = new StashboxContainer();\n        Assert.Throws<ConstructorNotFoundException>(() =>\n            container.Register<Test>(context => context.WithConstructorByArguments()));\n    }\n\n    [Fact]\n    public void ConstructorSelectionTests_Args_Throws_MissingConstructor_OneParam()\n    {\n        using var container = new StashboxContainer();\n        Assert.Throws<ConstructorNotFoundException>(() =>\n            container.Register<Test>(context => context.WithConstructorByArguments(new object())));\n    }\n\n    [Fact]\n    public void ConstructorSelectionTests_Args_Throws_MissingConstructor_MoreParams()\n    {\n        using var container = new StashboxContainer();\n        Assert.Throws<ConstructorNotFoundException>(() =>\n            container.Register<Test>(context =>\n                context.WithConstructorByArguments(new object(), new object())));\n    }\n\n    [Fact]\n    public void ConstructorSelectionTests_Decorator_ArgTypes()\n    {\n        using var container = new StashboxContainer(config => config.WithUnknownTypeResolution());\n        container.RegisterDecorator<Dep, DepDecorator>(context => context.WithConstructorByArgumentTypes(typeof(Dep), typeof(Dep2)));\n        var test = container.Resolve<Dep>();\n\n        Assert.IsType<DepDecorator>(test);\n    }\n\n    [Fact]\n    public void ConstructorSelectionTests_Decorator_Args()\n    {\n        using var container = new StashboxContainer(config => config.WithUnknownTypeResolution());\n        var dep = new Dep();\n        var dep2 = new Dep2();\n\n        container.RegisterDecorator<Dep, DepDecorator>(context => context.WithConstructorByArguments(dep, dep2));\n        var test = container.Resolve<Dep>();\n\n        Assert.Same(dep, ((DepDecorator)test).Dep);\n        Assert.Same(dep2, ((DepDecorator)test).Dep2);\n    }\n\n    [Fact]\n    public void ConstructorSelectionTests_Arg_ByInterface()\n    {\n        using var container = new StashboxContainer();\n        var arg = new Arg();\n        var arg1 = new Arg1();\n\n        container.Register<Test1>(context => context.WithConstructorByArguments(arg, arg1));\n        var test = container.Resolve<Test1>();\n\n        Assert.Same(arg, test.PArg);\n        Assert.Same(arg1, test.PArg1);\n    }\n\n    class Dep;\n\n    class Dep2;\n\n    class Dep3;\n\n    class DepDecorator : Dep\n    {\n        public Dep Dep { get; }\n        public Dep2 Dep2 { get; }\n\n        public DepDecorator(Dep dep)\n        {\n            Assert.True(false, \"wrong constructor\");\n        }\n\n        public DepDecorator(Dep dep, Dep2 dep2)\n        {\n            this.Dep = dep;\n            this.Dep2 = dep2;\n        }\n\n        public DepDecorator(Dep dep, Dep2 dep2, Dep3 dep3)\n        {\n            Assert.True(false, \"wrong constructor\");\n        }\n    }\n\n    class Test\n    {\n        public Dep Dep { get; }\n        public Dep2 Dep2 { get; }\n\n        public Test(Dep dep)\n        {\n            Assert.True(false, \"wrong constructor\");\n        }\n\n        public Test(Dep dep, Dep2 dep2)\n        {\n            this.Dep = dep;\n            this.Dep2 = dep2;\n        }\n\n        public Test(Dep dep, Dep2 dep2, Dep3 dep3)\n        {\n            Assert.True(false, \"wrong constructor\");\n        }\n    }\n\n    interface IArg;\n\n    interface IArg1;\n\n    class Arg : IArg;\n\n    class Arg1 : IArg1;\n\n    class Test1\n    {\n        public IArg PArg { get; }\n        public IArg1 PArg1 { get; }\n\n        public Test1(IArg arg, IArg1 arg1)\n        {\n            this.PArg = arg;\n            this.PArg1 = arg1;\n        }\n    }\n}"
  },
  {
    "path": "test/ContainerTests.cs",
    "content": "﻿using Moq;\nusing Stashbox.Configuration;\nusing Stashbox.Exceptions;\nusing Stashbox.Lifetime;\nusing Stashbox.Resolution;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Linq.Expressions;\nusing Xunit;\n\nnamespace Stashbox.Tests;\n\npublic class ContainerTests\n{\n    [Fact]\n    public void ContainerTests_ChildContainer()\n    {\n        var container = new StashboxContainer();\n        container.Register<ITest1, Test1>();\n        container.Register<ITest2, Test2>();\n\n        var child = container.CreateChildContainer();\n        child.Register<ITest3, Test3>();\n\n        var test3 = child.Resolve<ITest3>();\n\n        Assert.NotNull(test3);\n        Assert.IsType<Test3>(test3);\n        Assert.Equal(container.ContainerContext, child.ContainerContext.ParentContext);\n    }\n\n    [Fact]\n    public void ContainerTests_ChildContainer_ResolveFromParent()\n    {\n        var container = new StashboxContainer();\n        container.Register<ITest1, Test1>();\n\n        var child = container.CreateChildContainer();\n\n        var test1 = child.Resolve<ITest1>();\n\n        Assert.NotNull(test1);\n        Assert.IsType<Test1>(test1);\n    }\n\n    [Fact]\n    public void ContainerTests_Validate_MissingDependency()\n    {\n        using var container = new StashboxContainer();\n        container.Register<ITest2, Test2>();\n        var agr = Assert.Throws<AggregateException>(() => container.Validate());\n        Assert.IsType<ResolutionFailedException>(agr.InnerExceptions[0]);\n    }\n\n    [Fact]\n    public void ContainerTests_Validate_CircularDependency()\n    {\n        using var container = new StashboxContainer();\n        container.Register<ITest1, Test4>();\n        container.Register<ITest3, Test3>();\n        var agr = Assert.Throws<AggregateException>(() => container.Validate());\n        Assert.IsType<ResolutionFailedException>(agr.InnerExceptions[0]);\n    }\n\n    [Fact]\n    public void ContainerTests_Validate_Ok()\n    {\n        using var container = new StashboxContainer();\n        container.Register<ITest1, Test1>();\n        container.Register<ITest2, Test2>();\n        container.Validate();\n    }\n\n    [Fact]\n    public void ContainerTests_Validate_Skips_Open_Generic()\n    {\n        using var container = new StashboxContainer();\n        container.Register(typeof(TestOpenGeneric<>));\n        container.Validate();\n    }\n\n    [Fact]\n    public void ContainerTests_Validate_Throws_When_No_Public_Constructor_Found()\n    {\n        using var container = new StashboxContainer();\n        container.Register<NoPublicConstructor>();\n        var agr = Assert.Throws<AggregateException>(() => container.Validate());\n        Assert.IsType<ResolutionFailedException>(agr.InnerExceptions[0]);\n    }\n\n    [Fact]\n    public void ContainerTests_Validate_Throws_Multiple()\n    {\n        using var container = new StashboxContainer();\n        container.Register<NoPublicConstructor>();\n        container.Register<ITest1, Test4>();\n        container.Register<ITest3, Test3>();\n        var agr = Assert.Throws<AggregateException>(() => container.Validate());\n\n        Assert.Equal(3, agr.InnerExceptions.Count);\n        Assert.Equal(3, agr.InnerExceptions.Count(e => e is ResolutionFailedException));\n    }\n\n    [Fact]\n    public void ContainerTests_Ensure_Validate_Does_Not_Build_Singletons()\n    {\n        using var container = new StashboxContainer();\n        container.RegisterSingleton<Test1>();\n\n        container.Validate();\n\n        var reg = container.GetRegistrationMappings().First(r => r.Key == typeof(Test1));\n        var t = new Test1();\n        var res = container.ContainerContext.RootScope.GetOrAddScopedObject(reg.Value.RegistrationId, (s, r) => t, null, typeof(Test1));\n\n        Assert.Same(t, res);\n    }\n\n    [Fact]\n    public void ContainerTests_CheckRegistration()\n    {\n        using var container = new StashboxContainer();\n        container.Register<ITest1, Test1>();\n\n        var reg = container.GetRegistrationMappings().FirstOrDefault(r => r.Key == typeof(ITest1));\n\n        Assert.Equal(typeof(Test1), reg.Value.ImplementationType);\n\n        reg = container.GetRegistrationMappings().FirstOrDefault(r => r.Value.ImplementationType == typeof(Test1));\n\n        Assert.Equal(typeof(Test1), reg.Value.ImplementationType);\n    }\n\n    [Fact]\n    public void ContainerTests_CanResolve()\n    {\n        var container = new StashboxContainer();\n        container.Register<ITest1, Test1>();\n        container.Register<ITest2, Test2>();\n\n        var child = container.CreateChildContainer();\n\n        Assert.True(container.CanResolve<ITest1>());\n        Assert.True(container.CanResolve(typeof(ITest2)));\n        Assert.True(container.CanResolve<IEnumerable<ITest2>>());\n        Assert.True(container.CanResolve<Lazy<ITest2>>());\n        Assert.True(container.CanResolve<Func<ITest2>>());\n        Assert.True(container.CanResolve<Tuple<ITest2, object>>());\n\n        Assert.True(child.CanResolve<ITest1>());\n        Assert.True(child.CanResolve(typeof(ITest2)));\n        Assert.True(child.CanResolve<IEnumerable<ITest2>>());\n        Assert.True(child.CanResolve<Lazy<ITest2>>());\n        Assert.True(child.CanResolve<Func<ITest2>>());\n        Assert.True(child.CanResolve<Tuple<ITest2, object>>());\n\n        Assert.False(container.CanResolve<ITest3>());\n        Assert.False(container.CanResolve<ITest1>(\"test\"));\n        Assert.False(container.CanResolve(typeof(ITest1), \"test\"));\n    }\n\n    [Fact]\n    public void ContainerTests_IsRegistered()\n    {\n        var container = new StashboxContainer();\n        container.Register<ITest1, Test1>();\n        container.Register<ITest2, Test2>(context => context.WithName(\"test\"));\n\n        var child = container.CreateChildContainer();\n\n        Assert.True(container.IsRegistered<ITest1>());\n        Assert.True(container.IsRegistered<ITest2>(\"test\"));\n        Assert.True(container.IsRegistered(typeof(ITest1)));\n        Assert.False(container.IsRegistered<IEnumerable<ITest1>>());\n        Assert.False(container.IsRegistered<Func<ITest1>>());\n        Assert.False(container.IsRegistered<Lazy<ITest1>>());\n\n        Assert.False(child.IsRegistered<ITest1>());\n        Assert.False(child.IsRegistered(typeof(ITest1)));\n        Assert.False(child.IsRegistered<IEnumerable<ITest1>>());\n    }\n\n    [Fact]\n    public void ContainerTests_IsRegistered_VariableName()\n    {\n        var name = \"name\".ToLower();\n        var container = new StashboxContainer();\n        container.Register<ITest1, Test1>(c => c.WithName(\"name\"));\n\n        Assert.True(container.IsRegistered<ITest1>(name));\n    }\n\n    [Fact]\n    public void ContainerTests_IsRegistered_OpenGeneric()\n    {\n        var container = new StashboxContainer()\n            .Register<ITest1, Test1>()\n            .Register(typeof(TestOpenGeneric<>));\n\n        Assert.True(container.IsRegistered(typeof(TestOpenGeneric<>)));\n        Assert.False(container.IsRegistered<TestOpenGeneric<ITest1>>());\n    }\n\n    [Fact]\n    public void ContainerTests_ResolverTest()\n    {\n        var container = new StashboxContainer();\n        container.RegisterResolver(new TestResolver());\n        var inst = container.Resolve<ITest1>();\n\n        Assert.IsType<Test1>(inst);\n    }\n\n    [Fact]\n    public void ContainerTests_ResolverTest_SupportsMany()\n    {\n        var container = new StashboxContainer();\n        container.RegisterResolver(new TestResolver2());\n        var inst = container.Resolve<IEnumerable<ITest1>>();\n\n        Assert.IsType<Test1>(inst.First());\n    }\n\n    [Fact]\n    public void ContainerTests_ResolverTest_Null_Context_DoesNot_Break()\n    {\n        var container = new StashboxContainer();\n        var mockResolver = new Mock<IServiceResolver>();\n        mockResolver.Setup(r => r.CanUseForResolution(It.IsAny<TypeInformation>(), It.IsAny<ResolutionContext>())).Returns(true);\n        mockResolver.Setup(r => r.GetExpression(It.IsAny<IResolutionStrategy>(), It.IsAny<TypeInformation>(), It.IsAny<ResolutionContext>())).Returns<ServiceContext>(null);\n        container.RegisterResolver(mockResolver.Object);\n\n        Assert.Throws<ResolutionFailedException>(() => container.Resolve<ITest1>());\n        mockResolver.Verify(r => r.GetExpression(It.IsAny<IResolutionStrategy>(), It.IsAny<TypeInformation>(), It.IsAny<ResolutionContext>()), Times.Once);\n    }\n\n    [Fact]\n    public void ContainerTests_UnknownType_Config()\n    {\n        var container = new StashboxContainer(config => config\n            .WithUnknownTypeResolution(context => context.WithSingletonLifetime()));\n\n        container.Resolve<Test1>();\n\n        var regs = container.ContainerContext.RegistrationRepository.GetRegistrationMappings().ToArray();\n\n        Assert.Single(regs);\n        Assert.Equal(typeof(Test1), regs[0].Key);\n        Assert.True(regs[0].Value.Lifetime is SingletonLifetime);\n    }\n\n    [Fact]\n    public void ContainerTests_ChildContainer_Singleton()\n    {\n        var container = new StashboxContainer();\n        container.RegisterSingleton<ITest1, Test1>();\n\n        var child = container.CreateChildContainer();\n        child.RegisterSingleton<ITest2, Test2>();\n\n        var test = child.Resolve<ITest2>();\n\n        Assert.NotNull(test);\n        Assert.IsType<Test2>(test);\n    }\n\n    [Fact]\n    public void ContainerTests_ChildContainer_Scoped()\n    {\n        var container = new StashboxContainer();\n        container.RegisterScoped<ITest1, Test1>();\n\n        var child = container.CreateChildContainer();\n        child.Register<ITest2, Test2>();\n\n        var test = child.BeginScope().Resolve<ITest2>();\n\n        Assert.NotNull(test);\n        Assert.IsType<Test2>(test);\n    }\n\n    [Fact]\n    public void ContainerTests_ConfigurationChanged()\n    {\n        ContainerConfiguration newConfig = null;\n        var container = new StashboxContainer(config => config.OnContainerConfigurationChanged(nc => newConfig = nc));\n        container.Configure(config => config.WithUnknownTypeResolution());\n\n        Assert.True(newConfig.UnknownTypeResolutionEnabled);\n    }\n\n    [Fact]\n    public void ContainerTests_ConfigurationChange_Null()\n    {\n        Assert.Throws<ArgumentNullException>(() => new StashboxContainer().Configure(null));\n    }\n\n    [Fact]\n    public void ContainerTests_Configuration_DuplicatedBehavior_Throws()\n    {\n        var exception = Assert.Throws<ServiceAlreadyRegisteredException>(() => new StashboxContainer(c =>\n                c.WithRegistrationBehavior(Rules.RegistrationBehavior.ThrowException))\n            .Register<S>().Register<S>());\n        Assert.Equal(typeof(S), exception.Type);\n    }\n\n    [Fact]\n    public void ContainerTests_Configuration_DuplicatedBehavior_Does_Not_Throw_On_Replace()\n    {\n        using var container = new StashboxContainer(c =>\n            c.WithRegistrationBehavior(Rules.RegistrationBehavior.ThrowException));\n\n        container.Register<S>().Register<S>(c => c.ReplaceExisting());\n\n        Assert.Single(container.GetRegistrationDiagnostics().Where(r => r.ServiceType == typeof(S)));\n    }\n\n    [Fact]\n    public void ContainerTests_Configuration_DuplicatedBehavior_Does_Not_Throw_On_Replace_Only_If_Exists()\n    {\n        using var container = new StashboxContainer(c =>\n            c.WithRegistrationBehavior(Rules.RegistrationBehavior.ThrowException));\n\n        container.Register<S>().Register<S>(c => c.ReplaceOnlyIfExists());\n\n        Assert.Single(container.GetRegistrationDiagnostics().Where(r => r.ServiceType == typeof(S)));\n    }\n\n    [Fact]\n    public void ContainerTests_Configuration_DuplicatedBehavior_Does_Not_Throw_On_Different_Implementation()\n    {\n        using var container = new StashboxContainer(c =>\n            c.WithRegistrationBehavior(Rules.RegistrationBehavior.ThrowException));\n\n        container.Register<ITest1, Test1>().Register<ITest1, Test11>();\n\n        Assert.Equal(2, container.GetRegistrationDiagnostics().Count(r => r.ServiceType == typeof(ITest1)));\n    }\n\n    [Fact]\n    public void ContainerTests_Configuration_DuplicatedBehavior_Skip()\n    {\n        using var container = new StashboxContainer(c =>\n                c.WithRegistrationBehavior(Rules.RegistrationBehavior.SkipDuplications))\n            .Register<S>(c => c.WithInitializer((s, r) => s.Id = 0)).Register<S>(c => c.WithInitializer((s, r) => s.Id = 1));\n        var regs = container.GetRegistrationMappings();\n\n        Assert.Single(regs);\n        Assert.Equal(0, container.Resolve<S>().Id);\n    }\n\n    [Fact]\n    public void ContainerTests_Configuration_DuplicatedBehavior_Preserve()\n    {\n        var regs = new StashboxContainer(c =>\n                c.WithRegistrationBehavior(Rules.RegistrationBehavior.PreserveDuplications))\n            .Register<Test1>().Register<Test1>().GetRegistrationDiagnostics();\n\n        Assert.Equal(2, regs.Count());\n    }\n\n    [Fact]\n    public void ContainerTests_Diagnostics_Print()\n    {\n        var regs = new StashboxContainer()\n            .Register<ITest1, Test1>(\"t1\").Register<Test1>().GetRegistrationDiagnostics().Select(d => d.ToString()).OrderBy(s => s).ToArray();\n\n        Assert.Equal(\"ITest1 => Test1, name: t1\", regs[0]);\n        Assert.Equal(\"Test1 => Test1, name: null\", regs[1]);\n    }\n\n    [Fact]\n    public void ContainerTests_Diagnostics_Generic_Print()\n    {\n        var regs = new StashboxContainer()\n            .Register(typeof(TestOpenGeneric<>), c => c.WithName(\"t1\"))\n            .Register(typeof(TestOpenGeneric<>)).GetRegistrationDiagnostics()\n            .Select(d => d.ToString()).OrderBy(s => s)\n            .ToArray();\n\n        Assert.Equal(\"TestOpenGeneric<> => TestOpenGeneric<>, name: null\", regs[0]);\n        Assert.Equal(\"TestOpenGeneric<> => TestOpenGeneric<>, name: t1\", regs[1]);\n    }\n\n    [Fact]\n    public void ContainerTests_Cache_Diag()\n    {\n        using var container = new StashboxContainer()\n            .Register<ITest1, Test1>(\"t1\").Register<ITest1, Test1>().Register<Test1>();\n\n        container.Resolve<ITest1>();\n        container.Resolve<ITest1>(\"t1\");\n        container.Resolve<Test1>();\n        container.Resolve<Test1>(ResolutionBehavior.Current);\n\n        var cache = container.GetDelegateCacheEntries().OrderBy(c => c.ServiceType.FullName).ToArray();\n\n        Assert.Equal(3, cache.Length);\n        Assert.Equal(typeof(ITest1), cache[0].ServiceType);\n        Assert.Equal(typeof(Test1), cache[1].ServiceType);\n        Assert.Equal(typeof(Test1), cache[2].ServiceType);\n        Assert.IsType<Test1>(cache[0].CachedDelegate?.Invoke(container.ContainerContext.RootScope, null));\n        Assert.IsType<Test1>(cache[1].CachedDelegate?.Invoke(container.ContainerContext.RootScope, null));\n        Assert.IsType<Test1>(cache[2].CachedDelegate?.Invoke(container.ContainerContext.RootScope, null));\n        Assert.Single(cache[0].NamedCacheEntries ?? new NamedCacheEntry[]{});\n        Assert.Null(cache[1].NamedCacheEntries);\n        Assert.Null(cache[2].NamedCacheEntries);\n        Assert.Equal(\"t1\", cache[0].NamedCacheEntries?.First().Name);\n        Assert.Equal(ResolutionBehavior.Default, cache[0].ResolutionBehavior);\n        Assert.Equal(ResolutionBehavior.Current, cache[1].ResolutionBehavior);\n        Assert.Equal(ResolutionBehavior.Default, cache[2].ResolutionBehavior);\n    }\n\n    [Fact]\n    public void ContainerTests_Configuration_DuplicatedBehavior_Preserve_Cache_Invalidates()\n    {\n        using var container = new StashboxContainer(c =>\n                c.WithRegistrationBehavior(Rules.RegistrationBehavior.PreserveDuplications))\n            .Register<ITest1, Test1>();\n\n        var a = container.Resolve<ITest1>();\n\n        container.Register<ITest1, Test11>();\n\n        a = container.Resolve<ITest1>();\n\n        Assert.IsType<Test11>(a);\n    }\n\n    [Fact]\n    public void ContainerTests_Configuration_DuplicatedBehavior_Replace()\n    {\n        using var container = new StashboxContainer(c =>\n                c.WithRegistrationBehavior(Rules.RegistrationBehavior.ReplaceExisting))\n            .Register<S>(c => c.WithInitializer((s, r) => s.Id = 0)).Register<S>(c => c.WithInitializer((s, r) => s.Id = 1));\n        var regs = container.GetRegistrationMappings();\n\n        Assert.Single(regs);\n        Assert.Equal(1, container.Resolve<S>().Id);\n    }\n\n    [Fact]\n    public void ContainerTests_Throws_When_TypeMap_Invalid()\n    {\n        using var container = new StashboxContainer();\n        Assert.Equal(typeof(Test2), Assert.Throws<InvalidRegistrationException>(() => container.Register(typeof(ITest1), typeof(Test2))).Type);\n        Assert.Equal(typeof(Test2), Assert.Throws<InvalidRegistrationException>(() => container.RegisterDecorator(typeof(ITest1), typeof(Test2))).Type);\n        Assert.Equal(typeof(Test2), Assert.Throws<InvalidRegistrationException>(() => container.RegisterDecorator<ITest1>(typeof(Test2))).Type);\n        Assert.Equal(typeof(Test2), Assert.Throws<InvalidRegistrationException>(() => container.ReMapDecorator<ITest1>(typeof(Test2))).Type);\n    }\n\n    [Fact]\n    public void ContainerTests_ChildContainer_Rebuild_Singletons_In_Child()\n    {\n        using var container = new StashboxContainer();\n\n        container.RegisterSingleton<ITest1, Test1>();\n\n        var a = container.Resolve<ITest1>();\n        var b = container.Resolve<ITest1>();\n\n        using var child = container.CreateChildContainer();\n\n        var c = child.Resolve<ITest1>();\n\n        Assert.Same(a, b);\n        Assert.Same(a, c);\n        Assert.Same(b, c);\n\n        child.Configure(c => c.WithReBuildSingletonsInChildContainer());\n        c = child.Resolve<ITest1>();\n\n        Assert.Same(a, b);\n        Assert.NotSame(a, c);\n        Assert.NotSame(b, c);\n    }\n\n    [Fact]\n    public void ContainerTests_ChildContainer_Rebuild_Singletons_In_Child_Deps()\n    {\n        using var container = new StashboxContainer(c => c.WithReBuildSingletonsInChildContainer());\n\n        container.Register<ITest1, Test1>();\n        container.RegisterSingleton<Test2>();\n\n        var a = container.Resolve<Test2>();\n\n        Assert.IsType<Test1>(a.Test1);\n\n        using var child = container.CreateChildContainer();\n        child.Register<ITest1, Test11>();\n\n        var b = child.Resolve<Test2>();\n\n        Assert.IsType<Test11>(b.Test1);\n    }\n\n    [Fact]\n    public void ContainerTests_ChildContainer_Rebuild_Singletons_In_Child_Deps_Config_On_Child()\n    {\n        using var container = new StashboxContainer();\n\n        container.Register<ITest1, Test1>();\n        container.RegisterSingleton<Test2>();\n\n        var a = container.Resolve<Test2>();\n\n        Assert.IsType<Test1>(a.Test1);\n\n        using var child = container.CreateChildContainer(c => c.WithReBuildSingletonsInChildContainer());\n        child.Register<ITest1, Test11>();\n\n        var b = child.Resolve<Test2>();\n\n        Assert.IsType<Test11>(b.Test1);\n    }\n\n    [Fact]\n    public void ContainerTests_Throws_Disposed_Exceptions()\n    {\n        var container = new StashboxContainer();\n\n        var scope = container.BeginScope();\n        scope.Dispose();\n\n        Assert.Throws<ObjectDisposedException>(() => scope.Activate(this.GetType()));\n        Assert.Throws<ObjectDisposedException>(() => scope.BeginScope());\n        Assert.Throws<ObjectDisposedException>(() => scope.BuildUp(new object()));\n        Assert.Throws<ObjectDisposedException>(() => scope.CanResolve(this.GetType()));\n        Assert.Throws<ObjectDisposedException>(() => scope.GetService(this.GetType()));\n        Assert.Throws<ObjectDisposedException>(() => scope.PutInstanceInScope(this.GetType()));\n        Assert.Throws<ObjectDisposedException>(() => scope.Resolve(this.GetType()));\n        Assert.Throws<ObjectDisposedException>(() => scope.ResolveAll(this.GetType()));\n        Assert.Throws<ObjectDisposedException>(() => scope.ResolveFactory(this.GetType()));\n        Assert.ThrowsAsync<ObjectDisposedException>(async () => await scope.InvokeAsyncInitializers());\n\n        container.Dispose();\n\n        Assert.Throws<ObjectDisposedException>(() => container.Activate(this.GetType()));\n        Assert.Throws<ObjectDisposedException>(() => container.BeginScope());\n        Assert.Throws<ObjectDisposedException>(() => container.BuildUp(new object()));\n        Assert.Throws<ObjectDisposedException>(() => container.CanResolve(this.GetType()));\n        Assert.Throws<ObjectDisposedException>(() => container.ComposeAssemblies(new[] { this.GetType().Assembly }));\n        Assert.Throws<ObjectDisposedException>(() => container.ComposeAssembly(this.GetType().Assembly));\n        Assert.Throws<ObjectDisposedException>(() => container.ComposeBy(this.GetType()));\n        Assert.Throws<ObjectDisposedException>(() => container.Configure(c => { }));\n        Assert.Throws<ObjectDisposedException>(() => container.CreateChildContainer());\n        Assert.Throws<ObjectDisposedException>(() => container.GetRegistrationMappings());\n        Assert.Throws<ObjectDisposedException>(() => container.GetService(this.GetType()));\n        Assert.Throws<ObjectDisposedException>(() => container.IsRegistered(this.GetType()));\n        Assert.Throws<ObjectDisposedException>(() => container.PutInstanceInScope(this.GetType()));\n        Assert.Throws<ObjectDisposedException>(() => container.Register(this.GetType()));\n        Assert.Throws<ObjectDisposedException>(() => container.RegisterAssemblies(new[] { this.GetType().Assembly }));\n        Assert.Throws<ObjectDisposedException>(() => container.RegisterAssembly(this.GetType().Assembly));\n        Assert.Throws<ObjectDisposedException>(() => container.RegisterAssemblyContaining<ITest1>());\n        Assert.Throws<ObjectDisposedException>(() => container.RegisterDecorator(this.GetType(), this.GetType()));\n        Assert.Throws<ObjectDisposedException>(() => container.RegisterFunc<ITest1>(r => new Test1()));\n        Assert.Throws<ObjectDisposedException>(() => container.RegisterInstance(new object()));\n        Assert.Throws<ObjectDisposedException>(() => container.RegisterInstances(new object()));\n        Assert.Throws<ObjectDisposedException>(() => container.RegisterResolver(null));\n        Assert.Throws<ObjectDisposedException>(() => container.RegisterScoped<ITest1, Test1>());\n        Assert.Throws<ObjectDisposedException>(() => container.RegisterSingleton<ITest1, Test1>());\n        Assert.Throws<ObjectDisposedException>(() => container.RegisterTypes(new[] { this.GetType() }));\n        Assert.Throws<ObjectDisposedException>(() => container.RegisterTypesAs<ITest1>(this.GetType().Assembly));\n        Assert.Throws<ObjectDisposedException>(() => container.ReMap<ITest1, Test1>());\n        Assert.Throws<ObjectDisposedException>(() => container.ReMapDecorator(this.GetType(), this.GetType()));\n        Assert.Throws<ObjectDisposedException>(() => container.Resolve(this.GetType()));\n        Assert.Throws<ObjectDisposedException>(() => container.ResolveOrDefault(this.GetType()));\n        Assert.Throws<ObjectDisposedException>(() => container.ResolveAll(this.GetType()));\n        Assert.Throws<ObjectDisposedException>(() => container.ResolveFactory(this.GetType()));\n        Assert.Throws<ObjectDisposedException>(() => container.ResolveFactoryOrDefault(this.GetType()));\n        Assert.Throws<ObjectDisposedException>(() => container.Validate());\n        Assert.Throws<ObjectDisposedException>(() => container.WireUp(new object()));\n        Assert.ThrowsAsync<ObjectDisposedException>(async () => await container.InvokeAsyncInitializers());\n    }\n\n    interface ITest1;\n\n    interface ITest2;\n\n    interface ITest3;\n\n    interface ITest5\n    {\n        Func<ITest2> Func { get; }\n        Lazy<ITest2> Lazy { get; }\n        IEnumerable<ITest3> Enumerable { get; }\n        Tuple<ITest2, ITest3> Tuple { get; }\n    }\n\n    class Test1 : ITest1;\n\n    class Test11 : ITest1;\n\n    class Test2 : ITest2\n    {\n        public Test2(ITest1 test1)\n        {\n            Test1 = test1;\n        }\n\n        public ITest1 Test1 { get; }\n    }\n\n    class Test3 : ITest3\n    {\n        public Test3(ITest1 test1, ITest2 test2)\n        {\n        }\n    }\n\n    class Test4 : ITest1\n    {\n        public Test4(ITest3 test3)\n        {\n\n        }\n    }\n\n    class Test5 : ITest5\n    {\n        public Test5(Func<ITest2> func, Lazy<ITest2> lazy, IEnumerable<ITest3> enumerable, Tuple<ITest2, ITest3> tuple)\n        {\n            Func = func;\n            Lazy = lazy;\n            Enumerable = enumerable;\n            Tuple = tuple;\n        }\n\n        public Func<ITest2> Func { get; }\n        public Lazy<ITest2> Lazy { get; }\n        public IEnumerable<ITest3> Enumerable { get; }\n        public Tuple<ITest2, ITest3> Tuple { get; }\n    }\n\n    class TestResolver : IServiceResolver\n    {\n        public bool CanUseForResolution(TypeInformation typeInfo, ResolutionContext resolutionInfo)\n        {\n            return typeInfo.Type == typeof(ITest1);\n        }\n\n        public ServiceContext GetExpression(\n            IResolutionStrategy resolutionStrategy,\n            TypeInformation typeInfo,\n            ResolutionContext resolutionInfo)\n        {\n            return new ServiceContext(Expression.Constant(new Test1()), null);\n        }\n    }\n\n    class TestResolver2 : IEnumerableSupportedResolver\n    {\n        public bool CanUseForResolution(TypeInformation typeInfo, ResolutionContext resolutionInfo)\n        {\n            return typeInfo.Type == typeof(ITest1);\n        }\n\n        public ServiceContext GetExpression(\n            IResolutionStrategy resolutionStrategy,\n            TypeInformation typeInfo,\n            ResolutionContext resolutionInfo)\n        {\n            return new ServiceContext(Expression.Constant(new Test1()), null);\n        }\n\n        public IEnumerable<ServiceContext> GetExpressionsForEnumerableRequest(\n            IResolutionStrategy resolutionStrategy,\n            TypeInformation typeInfo,\n            ResolutionContext resolutionInfo)\n        {\n            return new ServiceContext[] { new ServiceContext(Expression.Constant(new Test1()), null) };\n        }\n    }\n\n    class S { public int Id { get; set; } }\n\n    class TestOpenGeneric<T>;\n\n    class NoPublicConstructor\n    {\n        protected NoPublicConstructor() { }\n    }\n}"
  },
  {
    "path": "test/DataTests/TreeTests.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing Stashbox.Tests.Utils;\nusing Stashbox.Utils.Data;\nusing Stashbox.Utils.Data.Immutable;\nusing Xunit;\n\nnamespace Stashbox.Tests.DataTests;\n\npublic class TreeTests\n{\n    [Fact]\n    public void Test_Collision_Check()\n    {\n        var key1 = new H1();\n        var key2 = new H2();\n        \n        var a = new A();\n        var b = new B();\n        var c = new C();\n        var imTree = ImmutableTree<object, List<object>>.Empty;\n        var tree = new HashTree<object, List<object>>();\n\n        imTree = imTree.AddOrUpdate(key1, [a], false);\n        imTree = imTree.AddOrUpdate(key2, [b], false);\n        tree.Add(key1, [a]);\n        tree.Add(key2, [b]);\n        \n        Assert.Equal([a], imTree.GetOrDefaultByValue(key1));\n        Assert.Equal([b], imTree.GetOrDefaultByValue(key2));\n        Assert.Equal([a], tree.GetOrDefault(key1));\n        Assert.Equal([b], tree.GetOrDefault(key2));\n\n        imTree = imTree.AddOrUpdate(key2, [c], false, (list, n) => [..list, ..n]);\n        \n        Assert.Equal([a], imTree.GetOrDefaultByValue(key1));\n        Assert.Equal([b, c], imTree.GetOrDefaultByValue(key2));\n\n        imTree = imTree.AddOrUpdate(key2, [b], false, true);\n        \n        Assert.Equal([a], imTree.GetOrDefaultByValue(key1));\n        Assert.Equal([b], imTree.GetOrDefaultByValue(key2));\n        \n        imTree = imTree.UpdateIfExists(key2, false, list => [..list, c]);\n        \n        Assert.Equal([a], imTree.GetOrDefaultByValue(key1));\n        Assert.Equal([b, c], imTree.GetOrDefaultByValue(key2));\n        \n        imTree = imTree.UpdateIfExists(key2, [b], false);\n        \n        Assert.Equal([a], imTree.GetOrDefaultByValue(key1));\n        Assert.Equal([b], imTree.GetOrDefaultByValue(key2));\n    }\n    \n    [Fact]\n    public void Test_Ref_Collision_Check()\n    {\n        var (key1, key2) = TypeGen.GetCollidingTypes();\n\n        var a = new A();\n        var b = new B();\n        var c = new C();\n        var imTree = ImmutableTree<Type, List<object>>.Empty;\n        var tree = new HashTree<Type, List<object>>();\n\n        imTree = imTree.AddOrUpdate(key1, [a], true);\n        imTree = imTree.AddOrUpdate(key2, [b], true);\n        tree.Add(key1, [a]);\n        tree.Add(key2, [b]);\n        \n        Assert.Equal([a], imTree.GetOrDefaultByRef(key1));\n        Assert.Equal([b], imTree.GetOrDefaultByRef(key2));\n        Assert.Equal([a], tree.GetOrDefault(key1));\n        Assert.Equal([b], tree.GetOrDefault(key2));\n\n        imTree = imTree.AddOrUpdate(key2, [c], true, (list, n) => [..list, ..n]);\n        \n        Assert.Equal([a], imTree.GetOrDefaultByRef(key1));\n        Assert.Equal([b, c], imTree.GetOrDefaultByRef(key2));\n\n        imTree = imTree.AddOrUpdate(key2, [b], true, true);\n        \n        Assert.Equal([a], imTree.GetOrDefaultByRef(key1));\n        Assert.Equal([b], imTree.GetOrDefaultByRef(key2));\n        \n        imTree = imTree.UpdateIfExists(key2, true, list => [..list, c]);\n        \n        Assert.Equal([a], imTree.GetOrDefaultByRef(key1));\n        Assert.Equal([b, c], imTree.GetOrDefaultByRef(key2));\n        \n        imTree = imTree.UpdateIfExists(key2, [b], true);\n        \n        Assert.Equal([a], imTree.GetOrDefaultByRef(key1));\n        Assert.Equal([b], imTree.GetOrDefaultByRef(key2));\n    }\n    \n    [Fact]\n    public void Test_Remove_Keep_Collisions()\n    {\n        var key1 = new H1();\n        var key2 = new H2();\n        var key3 = new H3();\n        \n        var a = new A();\n        var b = new B();\n        var c = new C();\n        var imTree = ImmutableTree<object, object>.Empty;\n\n        imTree = imTree.AddOrUpdate(key1, a, false);\n        imTree = imTree.AddOrUpdate(key2, b, false);\n        imTree = imTree.AddOrUpdate(key3, c, false);\n\n        imTree = imTree.Remove(key1, false);\n        \n        Assert.False(imTree.IsEmpty);\n        Assert.Null(imTree.GetOrDefaultByValue(key1));\n        Assert.Equal(b, imTree.GetOrDefaultByValue(key2));\n        Assert.Equal(c, imTree.GetOrDefaultByValue(key3));\n        \n        imTree = imTree.Remove(key2, false);\n        \n        Assert.False(imTree.IsEmpty);\n        Assert.Null(imTree.GetOrDefaultByValue(key1));\n        Assert.Null(imTree.GetOrDefaultByValue(key2));\n        Assert.Equal(c, imTree.GetOrDefaultByValue(key3));\n        \n        imTree = imTree.Remove(key3, false);\n        \n        Assert.True(imTree.IsEmpty);\n        Assert.Null(imTree.GetOrDefaultByValue(key1));\n        Assert.Null(imTree.GetOrDefaultByValue(key2));\n        Assert.Null(imTree.GetOrDefaultByValue(key3));\n    }\n    \n    [Fact]\n    public void Test_Collision_Remove()\n    {\n        var key1 = new H1();\n        var key2 = new H2();\n        var key3 = new H3();\n        \n        var a = new A();\n        var b = new B();\n        var c = new C();\n        var imTree = ImmutableTree<object, object>.Empty;\n\n        imTree = imTree.AddOrUpdate(key1, a, false);\n        imTree = imTree.AddOrUpdate(key2, b, false);\n        imTree = imTree.AddOrUpdate(key3, c, false);\n\n        imTree = imTree.Remove(key2, false);\n        \n        Assert.False(imTree.IsEmpty);\n        Assert.Equal(a, imTree.GetOrDefaultByValue(key1));\n        Assert.Equal(c, imTree.GetOrDefaultByValue(key3));\n        Assert.Null(imTree.GetOrDefaultByValue(key2));\n        \n        imTree = imTree.Remove(key1, false);\n        \n        Assert.False(imTree.IsEmpty);\n        Assert.Null(imTree.GetOrDefaultByValue(key1));\n        Assert.Equal(c, imTree.GetOrDefaultByValue(key3));\n        Assert.Null(imTree.GetOrDefaultByValue(key2));\n        \n        imTree = imTree.Remove(key3, false);\n        \n        Assert.True(imTree.IsEmpty);\n        Assert.Null(imTree.GetOrDefaultByValue(key1));\n        Assert.Null(imTree.GetOrDefaultByValue(key3));\n        Assert.Null(imTree.GetOrDefaultByValue(key2));\n    }\n    \n    private class A;\n    private class B;\n    private class C;\n    \n    private class H1\n    {\n        public override int GetHashCode()\n        {\n            return 1;\n        }\n    }\n    \n    private class H2\n    {\n        public override int GetHashCode()\n        {\n            return 1;\n        }\n    }\n    \n    private class H3\n    {\n        public override int GetHashCode()\n        {\n            return 1;\n        }\n    }\n}"
  },
  {
    "path": "test/DecoratorTests.cs",
    "content": "﻿using Stashbox.Attributes;\nusing Stashbox.Configuration;\nusing Stashbox.Exceptions;\nusing Stashbox.Lifetime;\nusing Stashbox.Registration;\nusing Stashbox.Tests.Utils;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing Xunit;\n\nnamespace Stashbox.Tests;\n\npublic class DecoratorTests\n{\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void DecoratorTests_Simple(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<ITest1, Test1>();\n        container.RegisterDecorator<ITest1, TestDecorator1>();\n        var test = container.Resolve<ITest1>();\n\n        Assert.NotNull(test);\n        Assert.IsType<TestDecorator1>(test);\n\n        Assert.NotNull(test.Test);\n        Assert.IsType<Test1>(test.Test);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void DecoratorTests_Simple2(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<ITest1, Test1>();\n        container.RegisterDecorator<ITest1>(typeof(TestDecorator1));\n        var test = container.Resolve<ITest1>();\n\n        Assert.NotNull(test);\n        Assert.IsType<TestDecorator1>(test);\n\n        Assert.NotNull(test.Test);\n        Assert.IsType<Test1>(test.Test);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void DecoratorTests_Simple3(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<ITest1, Test1>();\n        container.RegisterDecorator(typeof(ITest1), typeof(TestDecorator1));\n        var test = container.Resolve<ITest1>();\n\n        Assert.NotNull(test);\n        Assert.IsType<TestDecorator1>(test);\n\n        Assert.NotNull(test.Test);\n        Assert.IsType<Test1>(test.Test);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void DecoratorTests_Simple_Lazy(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<ITest1, Test1>();\n        container.RegisterDecorator<ITest1, TestDecorator1>();\n        var test = container.Resolve<Lazy<ITest1>>();\n\n        Assert.NotNull(test.Value);\n        Assert.IsType<TestDecorator1>(test.Value);\n\n        Assert.NotNull(test.Value.Test);\n        Assert.IsType<Test1>(test.Value.Test);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void DecoratorTests_Simple_Func(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<ITest1, Test1>();\n        container.RegisterDecorator<ITest1, TestDecorator1>();\n        var test = container.Resolve<Func<ITest1>>();\n\n        Assert.NotNull(test());\n        Assert.IsType<TestDecorator1>(test());\n\n        Assert.NotNull(test().Test);\n        Assert.IsType<Test1>(test().Test);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void DecoratorTests_Simple_Enumerable(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<ITest1, Test1>();\n        container.Register<ITest1, Test11>();\n        container.RegisterDecorator<ITest1, TestDecorator1>();\n        var test = container.Resolve<IEnumerable<ITest1>>();\n\n        Assert.NotNull(test);\n        Assert.IsAssignableFrom<IEnumerable<ITest1>>(test);\n\n        var arr = test.ToArray();\n\n        Assert.NotNull(arr[0]);\n        Assert.IsType<TestDecorator1>(arr[0]);\n\n        Assert.NotNull(arr[1]);\n        Assert.IsType<TestDecorator1>(arr[1]);\n\n        Assert.NotNull(arr[0].Test);\n        Assert.IsType<Test1>(arr[0].Test);\n\n        Assert.NotNull(arr[1].Test);\n        Assert.IsType<Test11>(arr[1].Test);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void DecoratorTests_Decorator_Holds_Lazy(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<ITest1, Test1>();\n        container.RegisterDecorator<ITest1, TestDecorator6>();\n        var test = container.Resolve<ITest1>();\n\n        Assert.NotNull(test);\n        Assert.IsType<TestDecorator6>(test);\n\n        Assert.NotNull(test.Test);\n        Assert.IsType<Test1>(test.Test);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void DecoratorTests_Decorator_Holds_Func(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<ITest1, Test1>();\n        container.RegisterDecorator<ITest1, TestDecorator7>();\n        var test = container.Resolve<ITest1>();\n\n        Assert.NotNull(test);\n        Assert.IsType<TestDecorator7>(test);\n\n        Assert.NotNull(test.Test);\n        Assert.IsType<Test1>(test.Test);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void DecoratorTests_Decorator_Holds_Enumerable(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<ITest1, Test1>();\n        container.RegisterDecorator<ITest1, TestDecorator1>();\n        container.RegisterDecorator<ITest1, TestDecorator8>();\n        var test = container.Resolve<ITest1>();\n\n        Assert.NotNull(test);\n        Assert.IsType<TestDecorator8>(test);\n\n        Assert.NotNull(test.Test);\n        Assert.IsType<TestDecorator1>(test.Test);\n\n        Assert.NotNull(test.Test);\n        Assert.IsType<Test1>(test.Test.Test);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void DecoratorTests_Dependency(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<ITest1, Test1>();\n        container.RegisterDecorator<ITest1, TestDecorator3>();\n        var test = container.Resolve<ITest1>();\n\n        Assert.NotNull(test);\n        Assert.IsType<TestDecorator3>(test);\n\n        Assert.NotNull(test.Test);\n        Assert.IsType<Test1>(test.Test);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void DecoratorTests_Inject_Member_With_Config(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<ITest1, Test1>();\n        container.RegisterDecorator<ITest1, TestDecorator3Attributeless>(config => config.WithDependencyBinding(\"Test\"));\n        var test = container.Resolve<ITest1>();\n\n        Assert.NotNull(test);\n        Assert.IsType<TestDecorator3Attributeless>(test);\n\n        Assert.NotNull(test.Test);\n        Assert.IsType<Test1>(test.Test);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void DecoratorTests_Inject_Member_With_Config_Non_Generic_Implementation(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<ITest1, Test1>();\n        container.RegisterDecorator<ITest1>(typeof(TestDecorator3Attributeless), config => config.WithDependencyBinding(\"Test\"));\n        var test = container.Resolve<ITest1>();\n\n        Assert.NotNull(test);\n        Assert.IsType<TestDecorator3Attributeless>(test);\n\n        Assert.NotNull(test.Test);\n        Assert.IsType<Test1>(test.Test);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void DecoratorTests_AutoMemberInjection_Throw_When_Member_Unresolvable(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<ITest1, Test1>();\n        container.RegisterDecorator<ITest1, TestDecorator4>(context => context.WithAutoMemberInjection(Rules.AutoMemberInjectionRules.PropertiesWithLimitedAccess));\n        Assert.Throws<ResolutionFailedException>(() => container.Resolve<ITest1>());\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void DecoratorTests_AutoMemberInjection_InjectionParameter(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<ITest1, Test1>();\n        container.RegisterDecorator<ITest1, TestDecorator4>(context => context\n            .WithAutoMemberInjection(Rules.AutoMemberInjectionRules.PropertiesWithLimitedAccess)\n            .WithInjectionParameter(\"Name\", \"test\"));\n        var test = container.Resolve<ITest1>();\n\n        Assert.NotNull(test);\n        Assert.IsType<TestDecorator4>(test);\n\n        Assert.NotNull(test.Test);\n        Assert.IsType<Test1>(test.Test);\n        Assert.Equal(\"test\", ((TestDecorator4)test).Name);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void DecoratorTests_AutoMemberInjection_InjectionParameter_Fluent(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<ITest1, Test1>();\n        container.RegisterDecorator<ITest1, TestDecorator4>(context => context\n            .WithAutoMemberInjection(Rules.AutoMemberInjectionRules.PropertiesWithLimitedAccess)\n            .WithInjectionParameter(\"Name\", \"test\"));\n        var test = container.Resolve<ITest1>();\n\n        Assert.NotNull(test);\n        Assert.IsType<TestDecorator4>(test);\n\n        Assert.NotNull(test.Test);\n        Assert.IsType<Test1>(test.Test);\n        Assert.Equal(\"test\", ((TestDecorator4)test).Name);\n    }\n\n    [Fact]\n    public void DecoratorTests_ConstructorSelection_LeastParameters()\n    {\n        using var container = new StashboxContainer();\n        container.Register<ITest1, Test1>();\n        container.RegisterDecorator<ITest1, TestDecorator5>(context => context.WithConstructorSelectionRule(Rules.ConstructorSelection.PreferLeastParameters));\n        var test = container.Resolve<ITest1>();\n\n        Assert.NotNull(test);\n        Assert.IsType<TestDecorator5>(test);\n\n        Assert.Null(test.Test);\n    }\n\n    [Fact]\n    public void DecoratorTests_ConstructorSelection_MostParameters()\n    {\n        using var container = new StashboxContainer();\n        container.Register<ITest1, Test1>();\n        container.RegisterDecorator<ITest1, TestDecorator5>(context => context.WithConstructorSelectionRule(Rules.ConstructorSelection.PreferMostParameters));\n        var test = container.Resolve<ITest1>();\n\n        Assert.NotNull(test);\n        Assert.IsType<TestDecorator5>(test);\n\n        Assert.NotNull(test.Test);\n        Assert.IsType<Test1>(test.Test);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void DecoratorTests_Multiple(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<ITest1, Test1>();\n        container.RegisterDecorator<ITest1, TestDecorator1>();\n        container.RegisterDecorator<ITest1, TestDecorator2>();\n        var test = container.Resolve<ITest1>();\n\n        Assert.NotNull(test);\n        Assert.IsType<TestDecorator2>(test);\n\n        Assert.NotNull(test.Test);\n        Assert.IsType<TestDecorator1>(test.Test);\n\n        Assert.NotNull(test.Test.Test);\n        Assert.IsType<Test1>(test.Test.Test);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void DecoratorTests_Multiple_Scoped(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.RegisterScoped<ITest1, Test1>();\n        container.RegisterDecorator<ITest1, TestDecorator1>();\n        container.RegisterDecorator<ITest1, TestDecorator2>();\n\n        using var child = container.BeginScope();\n        var test = child.Resolve<ITest1>();\n\n        Assert.NotNull(test);\n        Assert.IsType<TestDecorator2>(test);\n\n        Assert.NotNull(test.Test);\n        Assert.IsType<TestDecorator1>(test.Test);\n\n        Assert.NotNull(test.Test.Test);\n        Assert.IsType<Test1>(test.Test.Test);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void DecoratorTests_OpenGeneric(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register(typeof(ITest1<>), typeof(Test1<>));\n        container.RegisterDecorator(typeof(ITest1<>), typeof(TestDecorator1<>));\n        var test = container.Resolve<ITest1<int>>();\n\n        Assert.NotNull(test);\n        Assert.IsType<TestDecorator1<int>>(test);\n\n        Assert.NotNull(test.Test);\n        Assert.IsType<Test1<int>>(test.Test);\n    }\n\n    [Fact]\n    public void DecoratorTests_DecoratorDependency_Null()\n    {\n        using var container = new StashboxContainer();\n        container.Register<ITest1, Test1>();\n        container.RegisterDecorator<ITest1, TestDecorator9>();\n\n        var inst = container.ResolveOrDefault<ITest1>();\n\n        Assert.Null(inst);\n    }\n\n    [Fact]\n    public void DecoratorTests_DecoreteeDependency_Null()\n    {\n        using var container = new StashboxContainer();\n        container.Register<ITest1, Test12>();\n        container.RegisterDecorator<ITest1, TestDecorator9>();\n\n        var inst = container.ResolveOrDefault<ITest1>();\n\n        Assert.Null(inst);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void DecoratorTests_Disposed(CompilerType compilerType)\n    {\n        IDisp test;\n        using (var container = new StashboxContainer(config => config.WithDisposableTransientTracking().WithCompiler(compilerType)))\n        {\n            container.Register<IDisp, TestDisp>();\n            container.RegisterDecorator<IDisp, TestDispDecorator>();\n\n            test = container.Resolve<IDisp>();\n\n            Assert.NotNull(test);\n            Assert.NotNull(test.Test);\n        }\n\n        Assert.True(test.Disposed);\n        Assert.True(test.Test.Disposed);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void DecoratorTests_Disposed_OnlyDecoreteeDisposal(CompilerType compilerType)\n    {\n        IDisp test;\n        using (var container = new StashboxContainer(config => config.WithDisposableTransientTracking().WithCompiler(compilerType)))\n        {\n            container.Register<IDisp, TestDisp>(context => context.WithoutDisposalTracking());\n            container.RegisterDecorator<IDisp, TestDispDecorator>();\n\n            test = container.Resolve<IDisp>();\n\n            Assert.NotNull(test);\n            Assert.NotNull(test.Test);\n        }\n\n        Assert.True(test.Disposed);\n        Assert.False(test.Test.Disposed);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void DecoratorTests_Disposed_BothDisposal(CompilerType compilerType)\n    {\n        IDisp test;\n        using (var container = new StashboxContainer(config => config.WithDisposableTransientTracking().WithCompiler(compilerType)))\n        {\n            container.Register<IDisp, TestDisp>(context => context.WithoutDisposalTracking());\n            container.RegisterDecorator<IDisp, TestDispDecorator>(context => context.WithoutDisposalTracking());\n\n            test = container.Resolve<IDisp>();\n\n            Assert.NotNull(test);\n            Assert.NotNull(test.Test);\n        }\n\n        Assert.False(test.Disposed);\n        Assert.False(test.Test.Disposed);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void DecoratorTests_ReplaceDecorator(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<ITest1, Test1>();\n        container.RegisterDecorator<ITest1, TestDecorator1>();\n\n        var test = container.Resolve<ITest1>();\n\n        Assert.IsType<TestDecorator1>(test);\n        Assert.IsType<Test1>(test.Test);\n\n        container.RegisterDecorator<ITest1, TestDecorator1>(context => context.ReplaceExisting());\n\n        test = container.Resolve<ITest1>();\n\n        Assert.IsType<TestDecorator1>(test);\n        Assert.IsType<Test1>(test.Test);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void DecoratorTests_RemapDecorator(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<ITest1, Test1>();\n        container.RegisterDecorator<ITest1, TestDecorator1>();\n        container.RegisterDecorator<ITest1, TestDecorator2>();\n\n        var test = container.Resolve<ITest1>();\n\n        Assert.IsType<TestDecorator2>(test);\n        Assert.IsType<TestDecorator1>(test.Test);\n        Assert.IsType<Test1>(test.Test.Test);\n\n        container.ReMapDecorator<ITest1, TestDecorator3>();\n\n        test = container.Resolve<ITest1>();\n\n        Assert.IsType<TestDecorator3>(test);\n        Assert.IsType<Test1>(test.Test);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void DecoratorTests_RemapDecorator_V2(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<ITest1, Test1>();\n        container.RegisterDecorator<ITest1, TestDecorator1>();\n        container.RegisterDecorator<ITest1, TestDecorator2>();\n\n        var test = container.Resolve<ITest1>();\n\n        Assert.IsType<TestDecorator2>(test);\n        Assert.IsType<TestDecorator1>(test.Test);\n        Assert.IsType<Test1>(test.Test.Test);\n\n        container.ReMapDecorator<ITest1>(typeof(TestDecorator3));\n\n        test = container.Resolve<ITest1>();\n\n        Assert.IsType<TestDecorator3>(test);\n        Assert.IsType<Test1>(test.Test);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void DecoratorTests_RemapDecorator_WithConfig(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<ITest1, Test1>();\n        container.RegisterDecorator<ITest1, TestDecorator1>();\n        container.RegisterDecorator<ITest1, TestDecorator2>();\n\n        var test = container.Resolve<ITest1>();\n\n        Assert.IsType<TestDecorator2>(test);\n        Assert.IsType<TestDecorator1>(test.Test);\n        Assert.IsType<Test1>(test.Test.Test);\n\n        container.ReMapDecorator(typeof(ITest1), typeof(TestDecorator3), context => context.WithoutDisposalTracking());\n\n        test = container.Resolve<ITest1>();\n\n        Assert.IsType<TestDecorator3>(test);\n        Assert.IsType<Test1>(test.Test);\n    }\n\n    [Fact]\n    public void DecoratorTests_Service_ImplementationType()\n    {\n        using var container = new StashboxContainer();\n        container.RegisterDecorator<ITest1, TestDecorator1>(context =>\n        {\n            Assert.Equal(typeof(ITest1), context.ServiceType);\n            Assert.Equal(typeof(TestDecorator1), context.ImplementationType);\n        });\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void DecoratorTests_Conditional(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<ITest1, Test1>(\"t1\");\n        container.Register<ITest1, Test11>(\"t2\");\n        container.RegisterDecorator<ITest1, TestDecorator1>();\n        container.RegisterDecorator<ITest1, TestDecorator2>(c => c.WhenDecoratedServiceIs<Test11>());\n\n        var t1 = container.Resolve<ITest1>(\"t1\");\n        var t2 = container.Resolve<ITest1>(\"t2\");\n\n        Assert.IsType<TestDecorator1>(t1);\n        Assert.IsType<Test1>(t1.Test);\n\n        Assert.IsType<TestDecorator2>(t2);\n        Assert.IsType<TestDecorator1>(t2.Test);\n        Assert.IsType<Test11>(t2.Test.Test);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void DecoratorTests_Enumerable(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<ITest1, Test1>();\n        container.Register<ITest1, Test11>();\n        container.RegisterDecorator<ITest1, TestDecorator1>();\n        container.RegisterDecorator<ITest1, TestDecorator2>(c => c.WhenDecoratedServiceIs<Test11>());\n\n        var t = container.Resolve<ITest1[]>();\n\n        Assert.IsType<TestDecorator1>(t[0]);\n        Assert.IsType<Test1>(t[0].Test);\n\n        Assert.IsType<TestDecorator2>(t[1]);\n        Assert.IsType<TestDecorator1>(t[1].Test);\n        Assert.IsType<Test11>(t[1].Test.Test);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void DecoratorTests_Conditional_Named(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<ITest1, Test1>(\"t1\");\n        container.Register<ITest1, Test11>(\"t2\");\n        container.RegisterDecorator<ITest1, TestDecorator1>();\n        container.RegisterDecorator<ITest1, TestDecorator2>(c => c.When(t => t.DependencyName.Equals(\"t2\")));\n\n        var t1 = container.Resolve<ITest1>(\"t1\");\n        var t2 = container.Resolve<ITest1>(\"t2\");\n\n        Assert.IsType<TestDecorator1>(t1);\n        Assert.IsType<Test1>(t1.Test);\n\n        Assert.IsType<TestDecorator2>(t2);\n        Assert.IsType<TestDecorator1>(t2.Test);\n        Assert.IsType<Test11>(t2.Test.Test);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void DecoratorTests_Conditional_Named_Short(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<ITest1, Test1>(\"t1\");\n        container.Register<ITest1, Test11>(\"t2\");\n        container.RegisterDecorator<ITest1, TestDecorator1>();\n        container.RegisterDecorator<ITest1, TestDecorator2>(c => c.WhenDecoratedServiceIs(\"t2\"));\n\n        var t1 = container.Resolve<ITest1>(\"t1\");\n        var t2 = container.Resolve<ITest1>(\"t2\");\n\n        Assert.IsType<TestDecorator1>(t1);\n        Assert.IsType<Test1>(t1.Test);\n\n        Assert.IsType<TestDecorator2>(t2);\n        Assert.IsType<TestDecorator1>(t2.Test);\n        Assert.IsType<Test11>(t2.Test.Test);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void DecoratorTests_Conditional_Parent(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithAutoMemberInjection().WithUnknownTypeResolution().WithCompiler(compilerType));\n        container.Register<ITest1, Test1>();\n        container.RegisterDecorator<ITest1, TestDecorator1>();\n        container.RegisterDecorator<ITest1, TestDecorator2>(c => c.When(t => t.ParentType == typeof(TestHolder2)));\n\n        var t1 = container.Resolve<TestHolder1>();\n        var t2 = container.Resolve<TestHolder2>();\n\n        Assert.IsType<TestDecorator1>(t1.Test1);\n        Assert.IsType<Test1>(t1.Test1.Test);\n\n        Assert.IsType<TestDecorator2>(t2.Test1);\n        Assert.IsType<TestDecorator1>(t2.Test1.Test);\n        Assert.IsType<Test1>(t2.Test1.Test.Test);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void DecoratorTests_Conditional_Attribute(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithAutoMemberInjection().WithUnknownTypeResolution().WithCompiler(compilerType));\n        container.Register<ITest1, Test1>();\n        container.RegisterDecorator<ITest1, TestDecorator1>(c => c.WhenHas<Decorator1Attribute>());\n        container.RegisterDecorator<ITest1, TestDecorator2>(c => c.WhenHas<Decorator2Attribute>());\n\n        var t1 = container.Resolve<TestHolder1>();\n        var t2 = container.Resolve<TestHolder2>();\n\n        Assert.IsType<TestDecorator2>(t1.Test1);\n        Assert.IsType<TestDecorator1>(t1.Test1.Test);\n        Assert.IsType<Test1>(t1.Test1.Test.Test);\n\n        Assert.IsType<TestDecorator2>(t2.Test1);\n        Assert.IsType<Test1>(t2.Test1.Test);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void DecoratorTests_Conditional_Attribute_Multiple(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithAutoMemberInjection().WithUnknownTypeResolution().WithCompiler(compilerType));\n        container.Register<ITest1, Test1>();\n        container.RegisterDecorator<ITest1, TestDecorator1>(c => c.WhenHas<Decorator1Attribute>());\n        container.RegisterDecorator<ITest1, TestDecorator2>(c => c.WhenHas<Decorator2Attribute>());\n        container.RegisterDecorator<ITest1, TestDecorator3>(c => c.WhenHas<Decorator1Attribute>().WhenHas<Decorator3Attribute>());\n\n        var t = container.Resolve<TestHolder3>();\n\n        Assert.IsType<TestDecorator3>(t.Test1);\n        Assert.IsType<TestDecorator2>(t.Test1.Test);\n        Assert.IsType<Test1>(t.Test1.Test.Test);\n\n        Assert.IsType<TestDecorator3>(t.Test11);\n        Assert.IsType<TestDecorator1>(t.Test11.Test);\n        Assert.IsType<Test1>(t.Test11.Test.Test);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void DecoratorTests_Conditional_Attribute_Multiple_Scoped(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithAutoMemberInjection().WithUnknownTypeResolution().WithCompiler(compilerType));\n        container.RegisterScoped<ITest1, Test1>();\n        container.RegisterDecorator<ITest1, TestDecorator1>(c => c.WhenHas<Decorator1Attribute>().WithTransientLifetime());\n        container.RegisterDecorator<ITest1, TestDecorator2>(c => c.WhenHas<Decorator2Attribute>().WithTransientLifetime());\n        container.RegisterDecorator<ITest1, TestDecorator3>(c => c.WhenHas<Decorator1Attribute>().WhenHas<Decorator3Attribute>().WithTransientLifetime());\n\n        var t = container.Resolve<TestHolder3>();\n\n        Assert.IsType<TestDecorator3>(t.Test1);\n        Assert.IsType<TestDecorator2>(t.Test1.Test);\n        Assert.IsType<Test1>(t.Test1.Test.Test);\n\n        Assert.IsType<TestDecorator3>(t.Test11);\n        Assert.IsType<TestDecorator1>(t.Test11.Test);\n        Assert.IsType<Test1>(t.Test11.Test.Test);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void DecoratorTests_Different_Lifetime(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.RegisterSingleton<ITest1, Test1>();\n        container.RegisterDecorator<ITest1, TestDecorator1>(c => c.WithScopedLifetime());\n\n        using var scope1 = container.BeginScope();\n        var t1 = scope1.Resolve<ITest1>();\n\n        using var scope2 = scope1.BeginScope();\n        var t2 = scope2.Resolve<ITest1>();\n\n        Assert.NotSame(t1, t2);\n        Assert.Same(t1.Test, t2.Test);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void DecoratorTests_Inheriting_Lifetime(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.RegisterSingleton<ITest1, Test1>();\n        container.RegisterDecorator<ITest1, TestDecorator1>();\n\n        var t1 = container.Resolve<ITest1>();\n        var t2 = container.Resolve<ITest1>();\n\n        Assert.Same(t1, t2);\n        Assert.Same(t1.Test, t2.Test);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void DecoratorTests_Different_Decoretees(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<ITest1, Test1>();\n        container.Register<ITest2, T2>();\n        container.RegisterDecorator<ITest2, TestDecorator10>();\n        container.RegisterDecorator<ITest1, TestDecorator1>();\n\n        var t = container.Resolve<ITest2>();\n\n        Assert.IsType<TestDecorator10>(t);\n\n        Assert.IsType<TestDecorator1>(((TestDecorator10)t).Test1);\n        Assert.IsType<T2>(t.Test2);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void DecoratorTests_Different_Decoretees_Indirect(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<ITest1, Test1>();\n        container.Register<ITest2, T3>();\n        container.RegisterDecorator<ITest2, TestDecorator11>();\n        container.RegisterDecorator<ITest1, TestDecorator1>();\n\n        var t = container.Resolve<ITest2>();\n\n        Assert.IsType<TestDecorator11>(t);\n        Assert.IsType<T3>(t.Test2);\n        Assert.IsType<TestDecorator1>(((T3)t.Test2).Test);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void DecoratorTests_Different_Decoretees_Indirect2(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<ITest2, T2>();\n        container.Register<ITest1, T4>();\n        container.RegisterDecorator<ITest2, TestDecorator12>();\n        container.RegisterDecorator<ITest2, TestDecorator11>();\n        container.RegisterDecorator<ITest1, TestDecorator1>();\n\n        var t = container.Resolve<ITest2>();\n\n        Assert.IsType<TestDecorator11>(t);\n        Assert.IsType<TestDecorator12>(t.Test2);\n        Assert.IsType<T2>(t.Test2.Test2);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void DecoratorTests_NamedScope(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<ITest1, Test1>();\n        container.RegisterDecorator<ITest1, TestDecorator1>();\n        container.RegisterDecorator<ITest1, TestDecorator2>(c => c.InNamedScope(\"A\"));\n\n        var t = container.Resolve<ITest1>();\n\n        Assert.IsType<TestDecorator1>(t);\n        Assert.IsType<Test1>(t.Test);\n\n        using var scope = container.BeginScope(\"A\");\n        t = scope.Resolve<ITest1>();\n\n        Assert.IsType<TestDecorator2>(t);\n        Assert.IsType<TestDecorator1>(t.Test);\n        Assert.IsType<Test1>(t.Test.Test);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void DecoratorTests_NamedScope_Different_Decoretee(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<ITest1, Test1>();\n        container.Register<ITest1, Test11>(c => c.InNamedScope(\"A\"));\n        container.RegisterDecorator<ITest1, TestDecorator1>();\n        container.RegisterDecorator<ITest1, TestDecorator2>(c => c.InNamedScope(\"A\"));\n\n        var t = container.Resolve<ITest1>();\n\n        Assert.IsType<TestDecorator1>(t);\n        Assert.IsType<Test1>(t.Test);\n\n        using var scope = container.BeginScope(\"A\");\n        t = scope.Resolve<ITest1>();\n\n        Assert.IsType<TestDecorator2>(t);\n        Assert.IsType<TestDecorator1>(t.Test);\n        Assert.IsType<Test11>(t.Test.Test);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void DecoratorTests_Factory(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<ITest1, Test1>();\n        container.RegisterDecorator(typeof(ITest1), typeof(TestDecorator3), c => c.WithFactory(() => new TestDecorator3()));\n        container.RegisterDecorator(typeof(ITest1), typeof(TestDecorator13), c => c.WithFactory(r => new TestDecorator13 { Name = \"T4\" }));\n\n        var t = container.Resolve<ITest1>();\n\n        Assert.IsType<TestDecorator13>(t);\n        Assert.IsType<TestDecorator3>(t.Test);\n        Assert.IsType<Test1>(t.Test.Test);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void DecoratorTests_Factory_Generic(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<ITest1, Test1>();\n        container.RegisterDecorator<ITest1, TestDecorator3>(c => c.WithFactory(() => new TestDecorator3()));\n        container.RegisterDecorator<ITest1, TestDecorator13>(c => c.WithFactory(r => new TestDecorator13 { Name = \"T4\" }));\n\n        var t = container.Resolve<ITest1>();\n\n        Assert.IsType<TestDecorator13>(t);\n        Assert.IsType<TestDecorator3>(t.Test);\n        Assert.IsType<Test1>(t.Test.Test);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void DecoratorTests_Target_Attribute(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<ITest1, TestService>(\"t1\");\n        container.Register<ITest1, Test1>(\"t2\");\n        container.RegisterDecorator<ITest1, TestDecorator1>(c => c.WhenDecoratedServiceHas<Decorator1Attribute>());\n        container.RegisterDecorator<ITest1, TestDecorator2>();\n\n        var t = container.Resolve<ITest1>(\"t1\");\n\n        Assert.IsType<TestDecorator2>(t);\n        Assert.IsType<TestDecorator1>(t.Test);\n        Assert.IsType<TestService>(t.Test.Test);\n\n        t = container.Resolve<ITest1>(\"t2\");\n\n        Assert.IsType<TestDecorator2>(t);\n        Assert.IsType<Test1>(t.Test);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void DecoratorTests_InjectMember(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<ITest1, Test1>();\n        container.RegisterDecorator<ITest1, TestDecorator14>();\n\n        var t = container.Resolve<ITest1>();\n\n        Assert.IsType<TestDecorator14>(t);\n        Assert.IsType<Test1>(t.Test);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void DecoratorTests_InjectMember_AttributeLess(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<ITest1, Test1>();\n        container.RegisterDecorator<ITest1, TestDecorator3Attributeless>(c => c.WithDependencyBinding(d => d.Test));\n\n        var t = container.Resolve<ITest1>();\n\n        Assert.IsType<TestDecorator3Attributeless>(t);\n        Assert.IsType<Test1>(t.Test);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void DecoratorTests_WithFinalizer(CompilerType compilerType)\n    {\n        var finalized = false;\n        {\n            using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n            container.Register<ITest1, Test1>();\n            container.RegisterDecorator<ITest1, TestDecorator1>(c => c.WithFinalizer(d => { finalized = true; }));\n            container.Resolve<ITest1>();\n        }\n\n        Assert.True(finalized);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void DecoratorTests_Factory_Param1(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<ITest1, Test1>();\n        container.RegisterDecorator<ITest1, TestDecorator1>(c => c.WithFactory<ITest1>(t1 =>\n        {\n            Assert.IsType<Test1>(t1);\n            return new TestDecorator1(t1);\n        }));\n        container.Resolve<ITest1>();\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void DecoratorTests_Factory_Param_NextDecorator(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<ITest1, Test1>();\n        container.RegisterDecorator<ITest1, TestDecorator2>();\n        container.RegisterDecorator<ITest1, TestDecorator1>(c => c.WithFactory<ITest1>(t1 =>\n        {\n            Assert.IsType<TestDecorator2>(t1);\n            return new TestDecorator1(t1);\n        }));\n        container.Resolve<ITest1>();\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void DecoratorTests_Factory_Param2(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<ITest1, Test1>();\n        container.Register<TComp>(c => c.AsImplementedTypes());\n        container.RegisterDecorator<ITest1, TestDecorator1>(c => c.WithFactory<ITest1, IT1>((t1, t2) =>\n        {\n            Assert.IsType<Test1>(t1);\n            Assert.IsType<TComp>(t2);\n            return new TestDecorator1(t1);\n        }));\n        container.Resolve<ITest1>();\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void DecoratorTests_Factory_Param3(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<ITest1, Test1>();\n        container.Register<TComp>(c => c.AsImplementedTypes());\n        container.RegisterDecorator<ITest1, TestDecorator1>(c => c.WithFactory<ITest1, IT1, IT2>((t1, t2, t3) =>\n        {\n            Assert.IsType<Test1>(t1);\n            Assert.IsType<TComp>(t2);\n            Assert.IsType<TComp>(t3);\n            return new TestDecorator1(t1);\n        }));\n        container.Resolve<ITest1>();\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void DecoratorTests_Factory_Param4(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<ITest1, Test1>();\n        container.Register<TComp>(c => c.AsImplementedTypes());\n        container.RegisterDecorator<ITest1, TestDecorator1>(c => c.WithFactory<ITest1, IT1, IT2, IT4>((t1, t2, t3, t4) =>\n        {\n            Assert.IsType<Test1>(t1);\n            Assert.IsType<TComp>(t2);\n            Assert.IsType<TComp>(t3);\n            Assert.IsType<TComp>(t4);\n            return new TestDecorator1(t1);\n        }));\n        container.Resolve<ITest1>();\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void DecoratorTests_Factory_Param5(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<ITest1, Test1>();\n        container.Register<TComp>(c => c.AsImplementedTypes());\n        container.RegisterDecorator<ITest1, TestDecorator1>(c => c.WithFactory<ITest1, IT1, IT2, IT4, IT5>((t1, t2, t3, t4, t5) =>\n        {\n            Assert.IsType<Test1>(t1);\n            Assert.IsType<TComp>(t2);\n            Assert.IsType<TComp>(t3);\n            Assert.IsType<TComp>(t4);\n            Assert.IsType<TComp>(t5);\n            return new TestDecorator1(t1);\n        }));\n        container.Resolve<ITest1>();\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void DecoratorTests_NonGeneric_Factory_Param1(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<ITest1, Test1>();\n        container.RegisterDecorator(typeof(ITest1), typeof(TestDecorator1), c => c.WithFactory<ITest1>(t1 =>\n        {\n            Assert.IsType<Test1>(t1);\n            return new TestDecorator1(t1);\n        }));\n        container.Resolve<ITest1>();\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void DecoratorTests_NonGeneric_Factory_Param_NextDecorator(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<ITest1, Test1>();\n        container.RegisterDecorator<ITest1, TestDecorator2>();\n        container.RegisterDecorator(typeof(ITest1), typeof(TestDecorator1), c => c.WithFactory<ITest1>(t1 =>\n        {\n            Assert.IsType<TestDecorator2>(t1);\n            return new TestDecorator1(t1);\n        }));\n        container.Resolve<ITest1>();\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void DecoratorTests_NonGeneric_Factory_Param2(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<ITest1, Test1>();\n        container.Register<TComp>(c => c.AsImplementedTypes());\n        container.RegisterDecorator(typeof(ITest1), typeof(TestDecorator1), c => c.WithFactory<ITest1, IT1>((t1, t2) =>\n        {\n            Assert.IsType<Test1>(t1);\n            Assert.IsType<TComp>(t2);\n            return new TestDecorator1(t1);\n        }));\n        container.Resolve<ITest1>();\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void DecoratorTests_NonGeneric_Factory_Param3(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<ITest1, Test1>();\n        container.Register<TComp>(c => c.AsImplementedTypes());\n        container.RegisterDecorator(typeof(ITest1), typeof(TestDecorator1), c => c.WithFactory<ITest1, IT1, IT2>((t1, t2, t3) =>\n        {\n            Assert.IsType<Test1>(t1);\n            Assert.IsType<TComp>(t2);\n            Assert.IsType<TComp>(t3);\n            return new TestDecorator1(t1);\n        }));\n        container.Resolve<ITest1>();\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void DecoratorTests_NonGeneric_Factory_Param4(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<ITest1, Test1>();\n        container.Register<TComp>(c => c.AsImplementedTypes());\n        container.RegisterDecorator(typeof(ITest1), typeof(TestDecorator1), c => c.WithFactory<ITest1, IT1, IT2, IT4>((t1, t2, t3, t4) =>\n        {\n            Assert.IsType<Test1>(t1);\n            Assert.IsType<TComp>(t2);\n            Assert.IsType<TComp>(t3);\n            Assert.IsType<TComp>(t4);\n            return new TestDecorator1(t1);\n        }));\n        container.Resolve<ITest1>();\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void DecoratorTests_NonGeneric_Factory_Param5(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<ITest1, Test1>();\n        container.Register<TComp>(c => c.AsImplementedTypes());\n        container.RegisterDecorator(typeof(ITest1), typeof(TestDecorator1), c => c.WithFactory<ITest1, IT1, IT2, IT4, IT5>((t1, t2, t3, t4, t5) =>\n        {\n            Assert.IsType<Test1>(t1);\n            Assert.IsType<TComp>(t2);\n            Assert.IsType<TComp>(t3);\n            Assert.IsType<TComp>(t4);\n            Assert.IsType<TComp>(t5);\n            return new TestDecorator1(t1);\n        }));\n        container.Resolve<ITest1>();\n    }\n\n    [Fact]\n    public void DecoratorTests_Compositor_Works()\n    {\n        using var container = new StashboxContainer();\n        container.RegisterDecorator<ITest1, TestDecorator1>(c => c\n            .WithInitializer((d, r) => { })\n            .WithSingletonLifetime()\n            .WhenDecoratedServiceIs<Test1>());\n\n        var registration = container.ContainerContext.DecoratorRepository.GetRegistrationMappings().First().Value;\n\n        Assert.NotNull(registration.RegistrationOptions[RegistrationOption.Initializer]);\n        Assert.Equal(Lifetimes.Singleton, registration.Lifetime);\n    }\n    \n    [Fact]\n    public void DecoratorTests_Compositor_ChildContainer()\n    {\n        using var container = new StashboxContainer();\n\n        container.RegisterScoped<ITest1, Test1>();\n        container.RegisterScoped<ITest1, Test11>();\n        container.RegisterDecorator<ITest1, TestDecorator8>();\n\n        var child = container.CreateChildContainer();\n\n        child.RegisterInstance<ITest1>(new Test13());\n\n        var a = child.Resolve<ITest1>();\n        \n        Assert.NotEmpty(((TestDecorator8)a).Decoretees);\n    }\n\n    interface IT1;\n\n    interface IT2;\n\n    interface IT3;\n\n    interface IT4;\n\n    interface IT5;\n\n    class TComp : IT1, IT2, IT3, IT4, IT5;\n\n\n    interface ITest1 { ITest1 Test { get; } }\n\n    interface ITest2 { ITest2 Test2 { get; } }\n\n    interface IDecoratorDep;\n\n    interface IDep;\n\n    interface ITest1<T> { ITest1<T> Test { get; } }\n\n    interface IDisp : IDisposable\n    {\n        IDisp Test { get; }\n\n        bool Disposed { get; }\n    }\n\n    class Test1 : ITest1\n    {\n        public ITest1 Test { get; }\n    }\n\n    class T2 : ITest2\n    {\n        public ITest2 Test2 { get; }\n    }\n\n    class T3 : ITest2\n    {\n        public ITest2 Test2 { get; }\n\n        [Dependency]\n        public ITest1 Test { get; set; }\n    }\n\n    class T4 : ITest1\n    {\n        [Dependency]\n        public ITest2 Test2 { get; set; }\n\n        public ITest1 Test { get; set; }\n    }\n\n    class Test11 : ITest1\n    {\n        public ITest1 Test { get; }\n    }\n\n    class Test12 : ITest1\n    {\n        public ITest1 Test { get; }\n\n        public Test12(IDep dep)\n        {\n\n        }\n    }\n    \n    class Test13 : ITest1\n    {\n        public ITest1 Test { get; }\n    }\n\n    class TestDisp : IDisp\n    {\n        public void Dispose()\n        {\n            if (this.Disposed)\n                throw new ObjectDisposedException(nameof(TestDisp));\n\n            this.Disposed = true;\n        }\n\n        public bool Disposed { get; private set; }\n        public IDisp Test { get; }\n    }\n\n    class TestDispDecorator : IDisp\n    {\n        public TestDispDecorator(IDisp disp)\n        {\n            this.Test = disp;\n        }\n\n        public void Dispose()\n        {\n            if (this.Disposed)\n                throw new ObjectDisposedException(nameof(TestDisp));\n\n            this.Disposed = true;\n        }\n\n        public bool Disposed { get; private set; }\n        public IDisp Test { get; }\n    }\n\n    class Test1<T> : ITest1<T>\n    {\n        public ITest1<T> Test { get; }\n    }\n\n    class TestDecorator1<T> : ITest1<T>\n    {\n        public ITest1<T> Test { get; }\n\n        public TestDecorator1(ITest1<T> test1)\n        {\n            this.Test = test1;\n        }\n    }\n\n    class TestDecorator1 : ITest1\n    {\n        public ITest1 Test { get; }\n\n        public TestDecorator1(ITest1 test1)\n        {\n            this.Test = test1;\n        }\n    }\n\n    class TestDecorator2 : ITest1\n    {\n        public ITest1 Test { get; }\n\n        public TestDecorator2(ITest1 test1)\n        {\n            this.Test = test1;\n        }\n    }\n\n    class TestDecorator3 : ITest1\n    {\n        [Dependency]\n        public ITest1 Test { get; set; }\n    }\n\n    class TestDecorator14 : ITest1\n    {\n        [Dependency]\n        public ITest1 Test { get; set; }\n    }\n\n    class TestDecorator3Attributeless : ITest1\n    {\n        public ITest1 Test { get; set; }\n    }\n\n    class TestDecorator4 : ITest1\n    {\n        public string Name { get; private set; }\n\n        public ITest1 Test { get; private set; }\n    }\n\n    class TestDecorator5 : ITest1\n    {\n        public ITest1 Test { get; }\n\n        public TestDecorator5()\n        { }\n\n        public TestDecorator5(ITest1 test1)\n        {\n            this.Test = test1;\n        }\n    }\n\n    class TestDecorator6 : ITest1\n    {\n        public ITest1 Test { get; }\n\n        public TestDecorator6(Lazy<ITest1> test1)\n        {\n            this.Test = test1.Value;\n        }\n    }\n\n    class TestDecorator7 : ITest1\n    {\n        public ITest1 Test { get; }\n\n        public TestDecorator7(Func<ITest1> test1)\n        {\n            this.Test = test1();\n        }\n    }\n\n    class TestDecorator8 : ITest1\n    {\n        public IEnumerable<ITest1> Decoretees { get; }\n        public ITest1 Test { get; }\n\n        public TestDecorator8(IEnumerable<ITest1> test1)\n        {\n            Decoretees = test1;\n            this.Test = test1.First();\n        }\n    }\n\n    class TestDecorator9 : ITest1\n    {\n        public ITest1 Test { get; }\n\n        public TestDecorator9(ITest1 test1, IDecoratorDep dep)\n        {\n            this.Test = test1;\n        }\n    }\n\n    class TestDecorator10 : ITest2\n    {\n        public ITest2 Test2 { get; }\n        public ITest1 Test1 { get; }\n\n        public TestDecorator10(ITest2 test2, ITest1 test1)\n        {\n            this.Test2 = test2;\n            this.Test1 = test1;\n        }\n    }\n\n    class TestDecorator11 : ITest2\n    {\n        public ITest2 Test2 { get; }\n\n        public TestDecorator11(ITest2 test2)\n        {\n            this.Test2 = test2;\n        }\n    }\n\n    class TestDecorator12 : ITest2\n    {\n        public ITest2 Test2 { get; }\n\n        public TestDecorator12(ITest1 test1)\n        {\n            this.Test2 = ((T4)test1.Test).Test2;\n        }\n    }\n\n    class TestDecorator13 : ITest1\n    {\n        public string Name { get; set; }\n\n        [Dependency]\n        public ITest1 Test { get; set; }\n    }\n\n    class TestHolder1\n    {\n        [Decorator1, Decorator2]\n        public ITest1 Test1 { get; set; }\n    }\n\n    class TestHolder2\n    {\n        [Decorator2]\n        public ITest1 Test1 { get; set; }\n    }\n\n    class TestHolder3\n    {\n        [Decorator2, Decorator3]\n        public ITest1 Test1 { get; set; }\n\n        [Decorator1]\n        public ITest1 Test11 { get; set; }\n    }\n\n    class Decorator1Attribute : Attribute;\n\n    class Decorator2Attribute : Attribute;\n\n    class Decorator3Attribute : Attribute;\n\n    [Decorator1]\n    class TestService : ITest1\n    {\n        public ITest1 Test { get; }\n    }\n}"
  },
  {
    "path": "test/DependencyBindingTests.cs",
    "content": "﻿using Stashbox.Attributes;\nusing Xunit;\n\nnamespace Stashbox.Tests;\n\npublic class DependencyBindingTests\n{\n    [Fact]\n    public void DependencyBindingTests_Bind_To_The_Same_Type()\n    {\n        var inst = new StashboxContainer()\n            .Register<ITest1, Test1>(\"test1\")\n            .Register<ITest1, Test11>(\"test2\")\n            .Register<ITest1, Test12>(\"test3\")\n            .Register<Test>(ctx => ctx.WithDependencyBinding(typeof(ITest1), \"test2\"))\n            .Resolve<Test>();\n\n        Assert.IsType<Test11>(inst.Test1);\n        Assert.IsType<Test11>(inst.Test2);\n        Assert.IsType<Test11>(inst.Test3);\n\n    }\n\n    [Fact]\n    public void DependencyBindingTests_Bind_To_Different_Types()\n    {\n        var inst = new StashboxContainer()\n            .Register<ITest1, Test1>(\"test1\")\n            .Register<ITest1, Test11>(\"test2\")\n            .Register<ITest1, Test12>(\"test3\")\n            .Register<Test>(ctx => ctx\n                .WithDependencyBinding(\"test1\", \"test1\")\n                .WithDependencyBinding(\"test2\", \"test2\")\n                .WithDependencyBinding(\"test3\", \"test3\"))\n            .Resolve<Test>();\n\n        Assert.IsType<Test1>(inst.Test1);\n        Assert.IsType<Test11>(inst.Test2);\n        Assert.IsType<Test12>(inst.Test3);\n\n    }\n\n    [Fact]\n    public void DependencyBindingTests_Override_Typed_Bindings()\n    {\n        var inst = new StashboxContainer()\n            .Register<ITest1, Test1>(\"test1\")\n            .Register<ITest1, Test11>(\"test2\")\n            .Register<ITest1, Test12>(\"test3\")\n            .Register<Test>(ctx => ctx\n                .WithDependencyBinding(\"test3\", \"test3\")\n                .WithDependencyBinding<ITest1>(\"test2\"))\n            .Resolve<Test>();\n\n        Assert.IsType<Test11>(inst.Test1);\n        Assert.IsType<Test11>(inst.Test2);\n        Assert.IsType<Test12>(inst.Test3);\n\n    }\n\n    [Fact]\n    public void DependencyBindingTests_Override_Typed_Bindings_Injection_Method()\n    {\n        var inst = new StashboxContainer()\n            .Register<ITest1, Test1>(\"test1\")\n            .Register<ITest1, Test11>(\"test2\")\n            .Register<ITest1, Test12>(\"test3\")\n            .Register<TestMethodInjection>(ctx => ctx\n                .WithDependencyBinding(\"test3\", \"test3\")\n                .WithDependencyBinding<ITest1>(\"test2\"))\n            .Resolve<TestMethodInjection>();\n\n        Assert.IsType<Test11>(inst.Test1);\n        Assert.IsType<Test11>(inst.Test2);\n        Assert.IsType<Test12>(inst.Test3);\n\n    }\n\n    interface ITest1;\n\n    class Test1 : ITest1;\n\n    class Test11 : ITest1;\n\n    class Test12 : ITest1;\n\n    class Test\n    {\n        public ITest1 Test1 { get; }\n        public ITest1 Test2 { get; }\n        public ITest1 Test3 { get; }\n\n        public Test(ITest1 test1, ITest1 test2, ITest1 test3)\n        {\n            this.Test1 = test1;\n            this.Test2 = test2;\n            this.Test3 = test3;\n        }\n    }\n\n    class TestMethodInjection\n    {\n        public ITest1 Test1 { get; private set; }\n        public ITest1 Test2 { get; private set; }\n        public ITest1 Test3 { get; private set; }\n\n        [InjectionMethod]\n        public void Init(ITest1 test1, ITest1 test2, ITest1 test3)\n        {\n            this.Test1 = test1;\n            this.Test2 = test2;\n            this.Test3 = test3;\n        }\n    }\n}"
  },
  {
    "path": "test/DisposeOrderTests.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing Xunit;\n\nnamespace Stashbox.Tests;\n\npublic class DisposeOrderTests\n{\n    [Fact]\n    public void Ensure_Services_Are_Disposed_In_The_Right_Order()\n    {\n        var disposables = new List<IDisposable>();\n        using (var container = new StashboxContainer(config => config.WithDisposableTransientTracking()))\n        {\n            var obj = container.Register<DisposableObj1>()\n                .Register<DisposableObj2>()\n                .Register<DisposableObj3>()\n                .Resolve<DisposableObj3>(dependencyOverrides: [disposables]);\n\n            Assert.NotNull(obj);\n        }\n\n        Assert.IsType<DisposableObj3>(disposables[0]);\n        Assert.IsType<DisposableObj1>(disposables[1]);\n        Assert.IsType<DisposableObj2>(disposables[2]);\n        Assert.IsType<DisposableObj1>(disposables[3]);\n    }\n\n    [Fact]\n    public void Ensure_Services_Are_Disposed_In_The_Right_Order_InScope()\n    {\n        var disposables = new List<IDisposable>();\n        using (var container = new StashboxContainer(config => config.WithDisposableTransientTracking()))\n        {\n            container.Register<DisposableObj1>()\n                .Register<DisposableObj2>()\n                .Register<DisposableObj3>();\n\n            using var scope = container.BeginScope();\n            var obj = scope.Resolve<DisposableObj3>(dependencyOverrides: [disposables]);\n            Assert.NotNull(obj);\n        }\n\n        Assert.IsType<DisposableObj3>(disposables[0]);\n        Assert.IsType<DisposableObj1>(disposables[1]);\n        Assert.IsType<DisposableObj2>(disposables[2]);\n        Assert.IsType<DisposableObj1>(disposables[3]);\n    }\n\n\n    private class DisposableObj1 : IDisposable\n    {\n        private readonly IList<IDisposable> disposables;\n\n        public DisposableObj1(IList<IDisposable> disposables)\n        {\n            this.disposables = disposables;\n        }\n\n        public void Dispose()\n        {\n            this.disposables.Add(this);\n        }\n    }\n\n    private class DisposableObj2 : IDisposable\n    {\n        private readonly IList<IDisposable> disposables;\n        private readonly DisposableObj1 dObj;\n\n        public DisposableObj2(IList<IDisposable> disposables, DisposableObj1 dObj)\n        {\n            this.disposables = disposables;\n            this.dObj = dObj;\n        }\n\n        public void Dispose()\n        {\n            this.disposables.Add(this);\n        }\n    }\n\n    private class DisposableObj3 : IDisposable\n    {\n        private readonly IList<IDisposable> disposables;\n        private readonly DisposableObj2 dObj;\n        private readonly DisposableObj1 dObj1;\n\n        public DisposableObj3(IList<IDisposable> disposables, DisposableObj2 dObj, DisposableObj1 dObj1)\n        {\n            this.disposables = disposables;\n            this.dObj = dObj;\n            this.dObj1 = dObj1;\n        }\n\n        public void Dispose()\n        {\n            this.disposables.Add(this);\n        }\n    }\n}"
  },
  {
    "path": "test/DisposeTests.cs",
    "content": "﻿using Stashbox.Attributes;\nusing System;\nusing System.Collections.Generic;\nusing System.Reflection;\nusing Xunit;\n\nnamespace Stashbox.Tests;\n\npublic class DisposeTests\n{\n    [Fact]\n    public void DisposeTests_Singleton()\n    {\n        ITest1 test;\n        ITest2 test2;\n        Test3 test3;\n        using (IStashboxContainer container = new StashboxContainer())\n        {\n            container.Register<ITest2, Test2>();\n            container.Register<Test3>();\n            container.RegisterSingleton<ITest1, Test1>();\n            test = container.Resolve<ITest1>();\n            test2 = container.Resolve<ITest2>();\n            test3 = container.Resolve<Test3>();\n        }\n\n        Assert.True(test.Disposed);\n        Assert.True(test2.Test1.Disposed);\n        Assert.True(test3.Test1.Disposed);\n    }\n\n    [Fact]\n    public void DisposeTests_Singleton_WithoutDisposal()\n    {\n        ITest1 test;\n        ITest2 test2;\n        Test3 test3;\n        using (IStashboxContainer container = new StashboxContainer())\n        {\n            container.Register<ITest2, Test2>();\n            container.Register<Test3>();\n            container.Register<ITest1, Test1>(context => context.WithSingletonLifetime().WithoutDisposalTracking());\n            test = container.Resolve<ITest1>();\n            test2 = container.Resolve<ITest2>();\n            test3 = container.Resolve<Test3>();\n        }\n\n        Assert.False(test.Disposed);\n        Assert.False(test2.Test1.Disposed);\n        Assert.False(test3.Test1.Disposed);\n    }\n\n    [Fact]\n    public void DisposeTests_Instance()\n    {\n        ITest1 test = new Test1();\n        ITest2 test2;\n        Test3 test3;\n        using (IStashboxContainer container = new StashboxContainer())\n        {\n            container.Register<ITest2, Test2>();\n            container.Register<Test3>();\n            container.RegisterInstance(test);\n            test2 = container.Resolve<ITest2>();\n            test3 = container.Resolve<Test3>();\n        }\n\n        Assert.True(test.Disposed);\n        Assert.True(test2.Test1.Disposed);\n        Assert.True(test3.Test1.Disposed);\n    }\n\n    [Fact]\n    public void DisposeTests_Instance_WithoutDisposal()\n    {\n        ITest1 test = new Test1();\n        ITest2 test2;\n        Test3 test3;\n        using (IStashboxContainer container = new StashboxContainer())\n        {\n            container.Register<ITest2, Test2>();\n            container.Register<Test3>();\n            container.RegisterInstance(test, withoutDisposalTracking: true);\n            test2 = container.Resolve<ITest2>();\n            test3 = container.Resolve<Test3>();\n        }\n\n        Assert.False(test.Disposed);\n        Assert.False(test2.Test1.Disposed);\n        Assert.False(test3.Test1.Disposed);\n    }\n\n    [Fact]\n    public void DisposeTests_Instance_AsObject_WithoutDisposal()\n    {\n        object test = new Test1();\n        ITest2 test2;\n        Test3 test3;\n        using (IStashboxContainer container = new StashboxContainer())\n        {\n            container.Register<ITest2, Test2>();\n            container.Register<Test3>();\n            container.RegisterInstance(test, typeof(ITest1), withoutDisposalTracking: true);\n            test2 = container.Resolve<ITest2>();\n            test3 = container.Resolve<Test3>();\n        }\n\n        Assert.False(((ITest1)test).Disposed);\n        Assert.False(test2.Test1.Disposed);\n        Assert.False(test3.Test1.Disposed);\n    }\n\n    [Fact]\n    public void DisposeTests_Instance_WithoutDisposal_Fluent()\n    {\n        ITest1 test = new Test1();\n        ITest2 test2;\n        Test3 test3;\n        using (IStashboxContainer container = new StashboxContainer())\n        {\n            container.Register<ITest2, Test2>();\n            container.Register<Test3>();\n            container.Register<ITest1>(context => context.WithInstance(test).WithoutDisposalTracking());\n            test2 = container.Resolve<ITest2>();\n            test3 = container.Resolve<Test3>();\n        }\n\n        Assert.False(test.Disposed);\n        Assert.False(test2.Test1.Disposed);\n        Assert.False(test3.Test1.Disposed);\n    }\n\n    [Fact]\n    public void DisposeTests_WireUp()\n    {\n        ITest1 test = new Test1();\n        ITest2 test2;\n        Test3 test3;\n        using (IStashboxContainer container = new StashboxContainer())\n        {\n            container.Register<ITest2, Test2>();\n            container.Register<Test3>();\n            container.WireUp(test);\n            test2 = container.Resolve<ITest2>();\n            test3 = container.Resolve<Test3>();\n        }\n\n        Assert.True(test.Disposed);\n        Assert.True(test2.Test1.Disposed);\n        Assert.True(test3.Test1.Disposed);\n    }\n\n    [Fact]\n    public void DisposeTests_TrackTransientDisposal()\n    {\n        ITest1 test;\n        ITest2 test2;\n        Test3 test3;\n        using (IStashboxContainer container = new StashboxContainer(config => config.WithDisposableTransientTracking()))\n        {\n            container.Register<ITest2, Test2>();\n            container.Register<Test3>();\n            container.Register<ITest1, Test1>();\n            test = container.Resolve<ITest1>();\n            test2 = container.Resolve<ITest2>();\n            test3 = container.Resolve<Test3>();\n        }\n\n        Assert.True(test.Disposed);\n        Assert.True(test2.Test1.Disposed);\n        Assert.True(test3.Test1.Disposed);\n    }\n\n    [Fact]\n    public void DisposeTests_Scoped()\n    {\n        ITest1 test;\n        ITest2 test2;\n        Test3 test3;\n        using (IStashboxContainer container = new StashboxContainer())\n        {\n            ITest1 test4;\n            ITest2 test5;\n            Test3 test6;\n\n            container.RegisterScoped<ITest2, Test2>();\n            container.RegisterScoped<Test3>();\n            container.RegisterScoped<ITest1, Test1>();\n            container.RegisterScoped<ITest11, Test4>();\n            container.RegisterScoped<ITest1, Test1>(\"test\");\n            container.RegisterScoped<ITest11, Test4>(\"test2\");\n\n            using var scope = container.BeginScope();\n            test = scope.Resolve<ITest1>();\n            var a = scope.Resolve<ITest11>();\n            test2 = scope.Resolve<ITest2>();\n            test3 = scope.Resolve<Test3>();\n\n            using (var child = container.BeginScope())\n            {\n                test4 = (ITest1)child.Resolve(typeof(ITest1), \"test\");\n                test5 = child.Resolve<ITest2>();\n                test6 = child.Resolve<Test3>();\n            }\n\n            Assert.True(test4.Disposed);\n            Assert.True(test5.Test1.Disposed);\n            Assert.True(test6.Test1.Disposed);\n        }\n\n        Assert.True(test.Disposed);\n        Assert.True(test2.Test1.Disposed);\n        Assert.True(test3.Test1.Disposed);\n    }\n\n    [Fact]\n    public void DisposeTests_PutInScope_RootScope()\n    {\n        var test = new Test1();\n        using (IStashboxContainer container = new StashboxContainer())\n        {\n            container.Register<ITest2, Test2>();\n            container.Register<Test3>();\n\n            container.PutInstanceInScope<ITest1>(test);\n\n            var test1 = container.Resolve<ITest1>();\n            var test2 = container.Resolve(typeof(ITest2));\n            var test3 = container.Resolve<Test3>();\n\n            Assert.Same(test, test1);\n            Assert.Same(test, ((ITest2)test2).Test1);\n            Assert.Same(test, test3.Test1);\n        }\n\n        Assert.True(test.Disposed);\n    }\n\n    [Fact]\n    public void DisposeTests_PutInScope_RootScope_WithoutDispose()\n    {\n        var test = new Test1();\n        using (IStashboxContainer container = new StashboxContainer())\n        {\n            container.Register<ITest2, Test2>();\n            container.Register<Test3>();\n\n            container.PutInstanceInScope<ITest1>(test, withoutDisposalTracking: true);\n\n            var test1 = container.Resolve<ITest1>();\n            var test2 = container.Resolve(typeof(ITest2));\n            var test3 = container.Resolve<Test3>();\n\n            Assert.Same(test, test1);\n            Assert.Same(test, ((ITest2)test2).Test1);\n            Assert.Same(test, test3.Test1);\n        }\n\n        Assert.False(test.Disposed);\n    }\n\n    [Fact]\n    public void DisposeTests_PutInScope_Scoped()\n    {\n        using IStashboxContainer container = new StashboxContainer();\n        container.RegisterScoped<ITest2, Test2>();\n        container.RegisterScoped<Test3>();\n\n        var test = new Test1();\n\n        using (var child = container.BeginScope())\n        {\n            child.PutInstanceInScope<ITest1>(test);\n\n            var test1 = child.Resolve<ITest1>();\n            var test2 = child.Resolve<ITest2>();\n            var test3 = child.Resolve<Test3>();\n\n            Assert.Same(test, test1);\n            Assert.Same(test, test2.Test1);\n            Assert.Same(test, test3.Test1);\n\n            Assert.False(test.Disposed);\n        }\n\n        Assert.True(test.Disposed);\n\n        var test4 = new Test1();\n\n        using (var child = container.BeginScope())\n        {\n            child.PutInstanceInScope<ITest1>(test4);\n\n            var test1 = child.Resolve<ITest1>();\n            var test2 = child.Resolve<ITest2>();\n            var test3 = child.Resolve<Test3>();\n\n            Assert.Same(test4, test1);\n            Assert.Same(test4, test2.Test1);\n            Assert.Same(test4, test3.Test1);\n\n            Assert.NotSame(test, test1);\n            Assert.NotSame(test, test2.Test1);\n            Assert.NotSame(test, test3.Test1);\n\n            Assert.False(test4.Disposed);\n        }\n\n        Assert.True(test4.Disposed);\n    }\n\n    [Fact]\n    public void DisposeTests_PutInScope_WithoutDispose()\n    {\n        using IStashboxContainer container = new StashboxContainer();\n        container.Register<ITest2, Test2>();\n        container.Register<Test3>();\n\n        var test = new Test1();\n\n        using (var child = container.BeginScope())\n        {\n            child.PutInstanceInScope<ITest1>(test, withoutDisposalTracking: true);\n\n            var test1 = child.Resolve<ITest1>();\n            var test2 = child.Resolve<ITest2>();\n            var test3 = child.Resolve<Test3>();\n\n            Assert.Same(test, test1);\n            Assert.Same(test, test2.Test1);\n            Assert.Same(test, test3.Test1);\n        }\n\n        Assert.False(test.Disposed);\n    }\n\n    [Fact]\n    public void DisposeTests_PutInScope_Named()\n    {\n        using IStashboxContainer container = new StashboxContainer();\n        container.Register<Test5>();\n\n        var dummy1 = new Test1();\n        var dummy2 = new Test1();\n\n        using (var child = container.BeginScope())\n        {\n            child.PutInstanceInScope<ITest1>(dummy1, true, \"d1\");\n            child.PutInstanceInScope<ITest1>(dummy2, true, \"d2\");\n\n            var test1 = child.Resolve<ITest1>(\"d2\");\n            var test2 = child.Resolve<Test5>();\n\n            Assert.Same(dummy2, test1);\n            Assert.Same(dummy2, test2.Test1);\n        }\n\n        Assert.False(dummy1.Disposed);\n        Assert.False(dummy2.Disposed);\n    }\n\n    [Fact]\n    public void DisposeTests_Scoped_Factory()\n    {\n        ITest1 test;\n        ITest2 test2;\n        Test3 test3;\n        using (IStashboxContainer container = new StashboxContainer())\n        {\n            ITest1 test4;\n            ITest2 test5;\n            Test3 test6;\n\n            container.RegisterScoped<ITest2, Test2>();\n            container.RegisterScoped<Test3>();\n            container.RegisterScoped<ITest1, Test1>();\n\n            using var scope = container.BeginScope();\n\n            test = scope.Resolve<Func<ITest1>>()();\n            test2 = scope.Resolve<Func<ITest2>>()();\n            test3 = scope.Resolve<Func<Test3>>()();\n\n            using (var child = scope.BeginScope())\n            {\n                test4 = child.Resolve<Func<ITest1>>()();\n                test5 = child.Resolve<Func<ITest2>>()();\n                test6 = child.Resolve<Func<Test3>>()();\n            }\n\n            Assert.True(test4.Disposed);\n            Assert.True(test5.Test1.Disposed);\n            Assert.True(test6.Test1.Disposed);\n        }\n\n        Assert.True(test.Disposed);\n        Assert.True(test2.Test1.Disposed);\n        Assert.True(test3.Test1.Disposed);\n    }\n\n    [Fact]\n    public void DisposeTests_Scoped_WithoutDisposal()\n    {\n        ITest1 test;\n        ITest2 test2;\n        Test3 test3;\n        using (IStashboxContainer container = new StashboxContainer())\n        {\n            ITest1 test4;\n            ITest2 test5;\n            Test3 test6;\n\n            container.Register<ITest2, Test2>(context => context.WithScopedLifetime().WithoutDisposalTracking());\n            container.Register<Test3>(context => context.WithScopedLifetime().WithoutDisposalTracking());\n            container.Register<ITest1, Test1>(context => context.WithScopedLifetime().WithoutDisposalTracking());\n\n            using var scope = container.BeginScope();\n\n            test = scope.Resolve<ITest1>();\n            test2 = scope.Resolve<ITest2>();\n            test3 = scope.Resolve<Test3>();\n\n            using (var child = container.BeginScope())\n            {\n                test4 = child.Resolve<ITest1>();\n                test5 = child.Resolve<ITest2>();\n                test6 = child.Resolve<Test3>();\n            }\n\n            Assert.False(test4.Disposed);\n            Assert.False(test5.Test1.Disposed);\n            Assert.False(test6.Test1.Disposed);\n        }\n\n        Assert.False(test.Disposed);\n        Assert.False(test2.Test1.Disposed);\n        Assert.False(test3.Test1.Disposed);\n    }\n\n    [Fact]\n    public void DisposeTests_TrackTransientDisposal_Scoped_Transient()\n    {\n        ITest1 test;\n        ITest2 test2;\n        Test3 test3;\n        using (IStashboxContainer container = new StashboxContainer(config => config.WithDisposableTransientTracking()))\n        {\n            ITest1 test4;\n            ITest2 test5;\n            Test3 test6;\n\n            container.Register<ITest2, Test2>();\n            container.Register<Test3>();\n            container.Register<ITest1, Test1>();\n\n            test = container.Resolve<ITest1>();\n            test2 = container.Resolve<ITest2>();\n            test3 = container.Resolve<Test3>();\n\n            using (var child = container.BeginScope())\n            {\n                test4 = child.Resolve<ITest1>();\n                test5 = child.Resolve<ITest2>();\n                test6 = child.Resolve<Test3>();\n            }\n\n            Assert.True(test4.Disposed);\n            Assert.True(test5.Test1.Disposed);\n            Assert.True(test6.Test1.Disposed);\n        }\n\n        Assert.True(test.Disposed);\n        Assert.True(test2.Test1.Disposed);\n        Assert.True(test3.Test1.Disposed);\n    }\n\n    [Fact]\n    public void DisposeTests_TrackTransientDisposal_Scoped_Transient_Factory()\n    {\n        ITest1 test;\n        ITest2 test2;\n        Test3 test3;\n        using (IStashboxContainer container = new StashboxContainer(config => config.WithDisposableTransientTracking()))\n        {\n            ITest1 test4;\n            ITest2 test5;\n            Test3 test6;\n\n            container.Register<ITest2, Test2>();\n            container.Register<Test3>();\n            container.Register<ITest1, Test1>();\n\n            test = container.Resolve<Func<ITest1>>()();\n            test2 = container.Resolve<Func<ITest2>>()();\n            test3 = container.Resolve<Func<Test3>>()();\n\n            using (var child = container.BeginScope())\n            {\n                test4 = child.Resolve<Func<ITest1>>()();\n                test5 = child.Resolve<Func<ITest2>>()();\n                test6 = child.Resolve<Func<Test3>>()();\n            }\n\n            Assert.True(test4.Disposed);\n            Assert.True(test5.Test1.Disposed);\n            Assert.True(test6.Test1.Disposed);\n        }\n\n        Assert.True(test.Disposed);\n        Assert.True(test2.Test1.Disposed);\n        Assert.True(test3.Test1.Disposed);\n    }\n\n    [Fact]\n    public void DisposeTests_TrackTransientDisposal_Scoped_Transient_TrackingDisabled()\n    {\n        ITest1 test;\n        ITest2 test2;\n        Test3 test3;\n        using (IStashboxContainer container = new StashboxContainer(config => config.WithDisposableTransientTracking()))\n        {\n            ITest1 test4;\n            ITest2 test5;\n            Test3 test6;\n\n            container.Register<ITest2, Test2>();\n            container.Register<Test3>();\n            container.Register<ITest1, Test1>(context => context.WithoutDisposalTracking());\n\n            test = container.Resolve<ITest1>();\n            test2 = container.Resolve<ITest2>();\n            test3 = container.Resolve<Test3>();\n\n            using (var child = container.BeginScope())\n            {\n                test4 = child.Resolve<ITest1>();\n                test5 = child.Resolve<ITest2>();\n                test6 = child.Resolve<Test3>();\n            }\n\n            Assert.False(test4.Disposed);\n            Assert.False(test5.Test1.Disposed);\n            Assert.False(test6.Test1.Disposed);\n        }\n\n        Assert.False(test.Disposed);\n        Assert.False(test2.Test1.Disposed);\n        Assert.False(test3.Test1.Disposed);\n    }\n\n    [Fact]\n    public void DisposeTests_TrackTransientDisposal_ScopeOfScope_Transient()\n    {\n        using IStashboxContainer container = new StashboxContainer(config => config.WithDisposableTransientTracking());\n        container.Register<ITest2, Test2>();\n        container.Register<Test3>();\n        container.Register<ITest1, Test1>();\n\n        ITest1 test;\n        ITest2 test2;\n        Test3 test3;\n\n        using (var scope = container.BeginScope())\n        {\n            test = scope.Resolve<ITest1>();\n            test2 = scope.Resolve<ITest2>();\n            test3 = scope.Resolve<Test3>();\n\n            ITest1 test4;\n            ITest2 test5;\n            Test3 test6;\n\n            using (var scope2 = scope.BeginScope())\n            {\n                test4 = scope2.Resolve<ITest1>();\n                test5 = scope2.Resolve<ITest2>();\n                test6 = scope2.Resolve<Test3>();\n            }\n\n            Assert.True(test4.Disposed);\n            Assert.True(test5.Test1.Disposed);\n            Assert.True(test6.Test1.Disposed);\n\n            Assert.False(test.Disposed);\n            Assert.False(test2.Test1.Disposed);\n            Assert.False(test3.Test1.Disposed);\n        }\n\n        Assert.True(test.Disposed);\n        Assert.True(test2.Test1.Disposed);\n        Assert.True(test3.Test1.Disposed);\n    }\n\n    [Fact]\n    public void DisposeTests_TrackTransientDisposal_Scoped_Transient_ChildContainer()\n    {\n        IStashboxContainer container = new StashboxContainer(config => config.WithDisposableTransientTracking());\n        ITest1 test4;\n        ITest2 test5;\n        Test3 test6;\n\n        container.Register<ITest2, Test2>();\n        container.Register<Test3>();\n        container.Register<ITest1, Test1>();\n\n        using (var child = container.CreateChildContainer())\n        using (var scope = child.BeginScope())\n        {\n            test4 = scope.Resolve<ITest1>();\n            test5 = scope.Resolve<ITest2>();\n            test6 = scope.Resolve<Test3>();\n        }\n\n        Assert.True(test4.Disposed);\n        Assert.True(test5.Test1.Disposed);\n        Assert.True(test6.Test1.Disposed);\n    }\n\n    [Fact]\n    public void DisposeTests_TrackTransientDisposal_Scoped_Transient_Singleton()\n    {\n        var container = new StashboxContainer(config => config.WithDisposableTransientTracking());\n\n\n        container.Register<ITest2, Test2>();\n        container.Register<Test3>();\n        container.RegisterSingleton<ITest1, Test1>();\n\n        ITest1 test4;\n        ITest2 test5;\n        Test3 test6;\n\n        using (var child = container.BeginScope())\n        {\n            test4 = child.Resolve<ITest1>();\n            test5 = child.Resolve<ITest2>();\n            test6 = child.Resolve<Test3>();\n\n            Assert.False(test4.Disposed);\n            Assert.False(test5.Test1.Disposed);\n            Assert.False(test6.Test1.Disposed);\n        }\n\n        Assert.False(test4.Disposed);\n        Assert.False(test5.Test1.Disposed);\n        Assert.False(test6.Test1.Disposed);\n\n        container.Dispose();\n\n        Assert.True(test4.Disposed);\n        Assert.True(test5.Test1.Disposed);\n        Assert.True(test6.Test1.Disposed);\n    }\n\n    [Fact]\n    public void DisposeTests_TrackTransientDisposal_Implementation_Has_Disposable()\n    {\n        IStashboxContainer container = new StashboxContainer(config => config.WithDisposableTransientTracking());\n        ITest11 test1;\n\n        container.Register<ITest11, Test4>();\n\n        using (var child = container.BeginScope())\n        {\n            test1 = (ITest11)child.Resolve(typeof(ITest11));\n        }\n\n        Assert.True(((Test4)test1).Disposed);\n    }\n\n    [Fact]\n    public void DisposeTests_Instance_TrackTransient()\n    {\n        var test = new Test1();\n        using (var container = new StashboxContainer(config => config.WithDisposableTransientTracking()))\n        {\n            container.RegisterInstance<ITest1>(test);\n\n            Assert.Same(test, container.Resolve<ITest1>());\n        }\n\n        Assert.True(test.Disposed);\n    }\n\n    [Fact]\n    public void DisposeTests_WireUp_TrackTransient()\n    {\n        ITest1 test = new Test1();\n        using (var container = new StashboxContainer(config => config.WithDisposableTransientTracking()))\n        {\n            container.WireUp(test);\n\n            Assert.Same(test, container.Resolve<ITest1>());\n        }\n\n        Assert.True(test.Disposed);\n    }\n\n    [Fact]\n    public void DisposeTests_WireUp_TrackTransient_WithoutDisposal()\n    {\n        ITest1 test = new Test1();\n        using (var container = new StashboxContainer(config => config.WithDisposableTransientTracking()))\n        {\n            container.WireUp(test, withoutDisposalTracking: true);\n\n            Assert.Same(test, container.Resolve<ITest1>());\n        }\n\n        Assert.False(test.Disposed);\n    }\n\n    [Fact]\n    public void DisposeTests_Factory()\n    {\n        ITest1 test;\n        using (var container = new StashboxContainer())\n        {\n            container.Register<ITest1, Test1>(context => context.WithFactory(() => new Test1()));\n            test = container.Resolve<ITest1>();\n        }\n\n        Assert.False(test.Disposed);\n    }\n\n    [Fact]\n    public void DisposeTests_Factory_TrackTransient()\n    {\n        ITest1 test;\n        using (var container = new StashboxContainer(config => config.WithDisposableTransientTracking()))\n        {\n            container.Register<ITest1, Test1>(context => context.WithFactory(() => new Test1()));\n            test = container.Resolve<ITest1>();\n        }\n\n        Assert.True(test.Disposed);\n    }\n\n    [Fact]\n    public void DisposeTests_Factory_Scoped()\n    {\n        ITest1 test;\n        using var container = new StashboxContainer()\n            .Register<ITest1, Test1>(context => context.WithScopedLifetime().WithFactory(() => new Test1()));\n\n        {\n            using var scope = container.BeginScope();\n            test = scope.Resolve<ITest1>();\n        }\n\n        Assert.True(test.Disposed);\n    }\n\n    [Fact]\n    public void DisposeTests_Factory_Scoped_WithoutTracking()\n    {\n        ITest1 test;\n        using var container = new StashboxContainer()\n            .Register<ITest1, Test1>(context =>\n                context.WithScopedLifetime()\n                    .WithFactory(() => new Test1())\n                    .WithoutDisposalTracking());\n\n        {\n            using var scope = container.BeginScope();\n            test = scope.Resolve<ITest1>();\n        }\n\n        Assert.False(test.Disposed);\n    }\n\n    [Fact]\n    public void DisposeTests_Multiple_Dispose_Call()\n    {\n        var container = new StashboxContainer();\n        container.RegisterSingleton<ITest1, Test1>();\n        var test = container.Resolve<ITest1>();\n\n        container.Dispose();\n        container.Dispose();\n\n        Assert.True(test.Disposed);\n    }\n\n    [Fact]\n    public void DisposeTests_Scoped_Multiple_Dispose_Call()\n    {\n        var container = new StashboxContainer();\n        container.RegisterScoped<ITest1, Test1>();\n        var scope = container.BeginScope();\n        var test = scope.Resolve<ITest1>();\n\n        scope.Dispose();\n        scope.Dispose();\n\n        Assert.True(test.Disposed);\n    }\n    \n    [Fact]\n    public void DisposeTests_Scope_Removed_From_Parent()\n    {\n        var container = new StashboxContainer();\n        container.RegisterScoped<Test1>();\n\n        var scope = container.BeginScope();\n        var sub1 = scope.BeginScope(attachToParent: true);\n        var sub2 = sub1.BeginScope(attachToParent: true);\n\n        var type = scope.GetType();\n        var childScopesField = type.GetField(\"childScopes\", BindingFlags.Instance | BindingFlags.NonPublic);\n        var childScopesValue = childScopesField.GetValue(scope);\n        var children = (IEnumerable<IResolutionScope>)childScopesValue.GetType().GetMethod(\"Walk\").Invoke(childScopesValue, null);\n        \n        Assert.Single(children);\n        \n        var t1 = sub1.Resolve<Test1>();\n        var t2 = sub2.Resolve<Test1>();\n        \n        sub1.Dispose();\n        \n        Assert.True(t1.Disposed);\n        Assert.True(t2.Disposed);\n        \n        childScopesValue = childScopesField.GetValue(scope);\n        children = (IEnumerable<IResolutionScope>)childScopesValue.GetType().GetMethod(\"Walk\").Invoke(childScopesValue, null);\n        \n        Assert.Empty(children);\n    }\n\n    interface ITest11;\n\n    interface ITest12;\n\n    interface ITest1 : ITest11, ITest12, IDisposable { bool Disposed { get; } }\n\n    interface ITest2 { ITest1 Test1 { get; } }\n\n    class Test1 : ITest1\n    {\n        public bool Disposed { get; private set; }\n\n        public void Dispose()\n        {\n            if (this.Disposed)\n            {\n                throw new ObjectDisposedException(nameof(Test1));\n            }\n\n            this.Disposed = true;\n        }\n    }\n\n    class Test2 : ITest2\n    {\n        public ITest1 Test1 { get; private set; }\n\n        public Test2(ITest1 test1)\n        {\n            this.Test1 = test1;\n        }\n    }\n\n    class Test3\n    {\n        [Dependency]\n        public ITest1 Test1 { get; set; }\n    }\n\n    class Test4 : ITest11, IDisposable\n    {\n        public bool Disposed { get; private set; }\n\n        public void Dispose()\n        {\n            if (this.Disposed)\n            {\n                throw new ObjectDisposedException(nameof(Test4));\n            }\n\n            this.Disposed = true;\n        }\n    }\n    \n    class Test5\n    {\n        [Dependency(\"d2\")]\n        public ITest1 Test1 { get; set; }\n    }\n}"
  },
  {
    "path": "test/EnumerableTests.cs",
    "content": "﻿using Stashbox.Configuration;\nusing Stashbox.Utils;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing Xunit;\n\nnamespace Stashbox.Tests;\n\npublic class EnumerableTests\n{\n    [Fact]\n    public void EnumerableTests_Resolve_Array_PreserveOrder()\n    {\n        IStashboxContainer container = new StashboxContainer();\n        container.Register<ITest1, Test1>();\n        container.Register<ITest1, Test11>();\n        container.Register<ITest1, Test12>();\n\n        var all = container.Resolve<ITest1[]>();\n\n        Assert.Equal(3, all.Length);\n    }\n\n    [Fact]\n    public void EnumerableTests_Resolve_IList()\n    {\n        IStashboxContainer container = new StashboxContainer();\n        container.Register<ITest1, Test1>();\n        container.Register<ITest1, Test11>();\n        container.Register<ITest1, Test12>();\n\n        var all = container.Resolve<IList<ITest1>>();\n\n        Assert.Equal(3, all.Count);\n    }\n\n    [Fact]\n    public void EnumerableTests_Resolve_ICollection()\n    {\n        IStashboxContainer container = new StashboxContainer();\n        container.Register<ITest1, Test1>();\n        container.Register<ITest1, Test11>();\n        container.Register<ITest1, Test12>();\n\n        var all = container.Resolve<ICollection<ITest1>>();\n\n        Assert.Equal(3, all.Count);\n    }\n\n    [Fact]\n    public void EnumerableTests_Resolve_IReadonlyCollection()\n    {\n        IStashboxContainer container = new StashboxContainer();\n        container.Register<ITest1, Test1>();\n        container.Register<ITest1, Test11>();\n        container.Register<ITest1, Test12>();\n\n        var all = container.Resolve<IReadOnlyCollection<ITest1>>();\n\n        Assert.Equal(3, all.Count);\n    }\n\n    [Fact]\n    public void EnumerableTests_Resolve_IReadOnlyList()\n    {\n        IStashboxContainer container = new StashboxContainer();\n        container.Register<ITest1, Test1>();\n        container.Register<ITest1, Test11>();\n        container.Register<ITest1, Test12>();\n\n        var all = container.Resolve<IReadOnlyList<ITest1>>();\n\n        Assert.Equal(3, all.Count);\n    }\n\n    [Fact]\n    public void EnumerableTests_Resolve()\n    {\n        IStashboxContainer container = new StashboxContainer();\n        container.Register<ITest1, Test1>();\n        container.Register<ITest1, Test11>();\n        container.Register<ITest1, Test12>();\n        container.Register<ITest2, Test2>(context => context.WithName(\"enumerable\"));\n        container.Register<ITest2, Test22>(context => context.WithName(\"array\"));\n\n        container.Resolve<ITest2>(\"enumerable\");\n        container.Resolve<ITest2>(\"array\");\n\n        var all = container.Resolve<IEnumerable<ITest2>>();\n        var all2 = container.ResolveAll<ITest2>();\n\n        Assert.Equal(2, all.Count());\n        Assert.Equal(2, all2.Count());\n    }\n\n    [Fact]\n    public void EnumerableTests_Resolve_Null()\n    {\n        IStashboxContainer container = new StashboxContainer();\n\n        var all = container.Resolve<IEnumerable<ITest2>>();\n        var all2 = container.ResolveAll<ITest2>();\n\n        Assert.Empty(all);\n        Assert.Empty(all2);\n    }\n\n    [Fact]\n    public void EnumerableTests_Resolve_Scoped_Null()\n    {\n        IStashboxContainer container = new StashboxContainer();\n\n        var scope = container.BeginScope();\n\n        var all = scope.Resolve<IEnumerable<ITest2>>();\n        var all2 = scope.ResolveAll<ITest2>();\n\n        Assert.Empty(all);\n        Assert.Empty(all2);\n    }\n\n    [Fact]\n    public void EnumerableTests_Resolve_Scoped()\n    {\n        IStashboxContainer container = new StashboxContainer();\n        container.Register<ITest1, Test1>();\n        container.Register<ITest1, Test11>();\n        container.Register<ITest1, Test12>();\n\n        var child = container.BeginScope();\n\n        var all = child.Resolve<IEnumerable<ITest1>>();\n\n        Assert.Equal(3, all.Count());\n    }\n\n    [Fact]\n    public void EnumerableTests_Resolve_Parent()\n    {\n        IStashboxContainer container = new StashboxContainer();\n        container.Register<ITest1, Test1>();\n        container.Register<ITest1, Test11>();\n        container.Register<ITest1, Test12>();\n\n        var child = container.CreateChildContainer();\n\n        var all = child.Resolve<IEnumerable<ITest1>>();\n\n        Assert.Equal(3, all.Count());\n    }\n\n    [Fact]\n    public void EnumerableTests_Resolve_Parent_Null()\n    {\n        IStashboxContainer container = new StashboxContainer();\n\n        var child = container.CreateChildContainer();\n\n        var all = child.Resolve<IEnumerable<ITest1>>();\n\n        Assert.Empty(all);\n    }\n\n    [Fact]\n    public void EnumerableTests_Resolve_Scoped_Lazy()\n    {\n        IStashboxContainer container = new StashboxContainer();\n        container.Register<ITest1, Test1>();\n        container.Register<ITest1, Test11>();\n        container.Register<ITest1, Test12>();\n\n        var child = container.BeginScope();\n\n        var all = child.Resolve<IEnumerable<Lazy<ITest1>>>();\n\n        Assert.Equal(3, all.Count());\n    }\n\n    [Fact]\n    public void EnumerableTests_Resolve_Parent_Lazy()\n    {\n        IStashboxContainer container = new StashboxContainer();\n        container.Register<ITest1, Test1>();\n        container.Register<ITest1, Test11>();\n        container.Register<ITest1, Test12>();\n\n        var child = container.CreateChildContainer();\n\n        var all = child.Resolve<IEnumerable<Lazy<ITest1>>>();\n\n        Assert.Equal(3, all.Count());\n    }\n\n    [Fact]\n    public void EnumerableTests_Resolve_Scoped_Lazy_Null()\n    {\n        IStashboxContainer container = new StashboxContainer();\n\n        var child = container.BeginScope();\n\n        var all = child.Resolve<IEnumerable<Lazy<ITest1>>>();\n\n        Assert.Empty(all);\n    }\n\n    [Fact]\n    public void EnumerableTests_Resolve_Parent_Lazy_Null()\n    {\n        IStashboxContainer container = new StashboxContainer();\n\n        var child = container.CreateChildContainer();\n\n        var all = child.Resolve<IEnumerable<Lazy<ITest1>>>();\n\n        Assert.Empty(all);\n    }\n\n    [Fact]\n    public void EnumerableTests_Resolve_Scoped_Func()\n    {\n        IStashboxContainer container = new StashboxContainer();\n        container.Register<ITest1, Test1>();\n        container.Register<ITest1, Test11>();\n        container.Register<ITest1, Test12>();\n\n        var child = container.BeginScope();\n\n        var all = child.Resolve<IEnumerable<Func<ITest1>>>();\n\n        Assert.Equal(3, all.Count());\n    }\n\n    [Fact]\n    public void EnumerableTests_Resolve_Parent_Func()\n    {\n        IStashboxContainer container = new StashboxContainer();\n        container.Register<ITest1, Test1>();\n        container.Register<ITest1, Test11>();\n        container.Register<ITest1, Test12>();\n\n        var child = container.CreateChildContainer();\n\n        var all = child.Resolve<IEnumerable<Func<ITest1>>>();\n\n        Assert.Equal(3, all.Count());\n    }\n\n    [Fact]\n    public void EnumerableTests_Resolve_Scoped_Func_Null()\n    {\n        IStashboxContainer container = new StashboxContainer();\n\n        var child = container.BeginScope();\n\n        var all = child.Resolve<IEnumerable<Func<ITest1>>>();\n\n        Assert.Empty(all);\n    }\n\n    [Fact]\n    public void EnumerableTests_Resolve_Parent_Func_Null()\n    {\n        IStashboxContainer container = new StashboxContainer();\n\n        var child = container.CreateChildContainer();\n\n        var all = child.Resolve<IEnumerable<Func<ITest1>>>();\n\n        Assert.Empty(all);\n    }\n\n    [Fact]\n    public void EnumerableTests_Resolve_Lazy()\n    {\n        IStashboxContainer container = new StashboxContainer();\n        container.Register<ITest1, Test1>();\n        container.Register<ITest1, Test11>();\n        container.Register<ITest1, Test12>();\n\n        var all = container.Resolve<IEnumerable<Lazy<ITest1>>>();\n\n        Assert.Equal(3, all.Count());\n    }\n\n    [Fact]\n    public void EnumerableTests_Resolve_Lazy_Null()\n    {\n        IStashboxContainer container = new StashboxContainer();\n\n        var all = container.Resolve<IEnumerable<Lazy<ITest1>>>();\n\n        Assert.Empty(all);\n    }\n\n    [Fact]\n    public void EnumerableTests_Resolve_Func()\n    {\n        IStashboxContainer container = new StashboxContainer();\n        container.Register<ITest1, Test1>();\n        container.Register<ITest1, Test11>();\n        container.Register<ITest1, Test12>();\n\n        var all = container.Resolve<IEnumerable<Func<ITest1>>>();\n\n        Assert.Equal(3, all.Count());\n    }\n\n    [Fact]\n    public void EnumerableTests_Resolve_Func_Null()\n    {\n        IStashboxContainer container = new StashboxContainer();\n\n        var all = container.Resolve<IEnumerable<Func<ITest1>>>();\n\n        Assert.Empty(all);\n    }\n\n    [Fact]\n    public void EnumerableTests_ResolveNonGeneric()\n    {\n        IStashboxContainer container = new StashboxContainer();\n        container.Register<ITest1, Test1>();\n        container.Register<ITest1, Test11>();\n        container.Register<ITest1, Test12>();\n        container.Register<ITest2, Test2>(context => context.WithName(\"enumerable\"));\n        container.Register<ITest2, Test22>(context => context.WithName(\"array\"));\n\n        container.Resolve<ITest2>(\"enumerable\");\n        container.Resolve<ITest2>(\"array\");\n\n        var all = container.Resolve<IEnumerable<ITest2>>();\n        var all2 = (IEnumerable<ITest2>)container.ResolveAll(typeof(ITest2));\n        var all3 = container.ResolveAll(typeof(ITest2));\n\n        Assert.Equal(2, all.Count());\n        Assert.Equal(2, all2.Count());\n        Assert.Equal(2, all3.Count());\n    }\n\n    [Fact]\n    public void EnumerableTests_ResolveNonGeneric_Scoped()\n    {\n        IStashboxContainer container = new StashboxContainer();\n        container.Register<ITest1, Test1>();\n        container.Register<ITest1, Test11>();\n        container.Register<ITest1, Test12>();\n        container.Register<ITest2, Test2>(context => context.WithName(\"enumerable\"));\n        container.Register<ITest2, Test22>(context => context.WithName(\"array\"));\n\n        var scope = container.BeginScope();\n\n        scope.Resolve<ITest2>(\"enumerable\");\n        scope.Resolve<ITest2>(\"array\");\n\n        var all = scope.Resolve<IEnumerable<ITest2>>();\n        var all2 = (IEnumerable<ITest2>)scope.ResolveAll(typeof(ITest2));\n        var all3 = scope.ResolveAll(typeof(ITest2));\n\n        Assert.Equal(2, all.Count());\n        Assert.Equal(2, all2.Count());\n        Assert.Equal(2, all3.Count());\n    }\n\n    [Fact]\n    public void EnumerableTests_Parallel_Resolve()\n    {\n        IStashboxContainer container = new StashboxContainer();\n        container.Register<ITest1, Test1>();\n        container.Register<ITest1, Test11>();\n        container.Register<ITest1, Test12>();\n        container.Register<ITest2, Test2>(context => context.WithName(\"enumerable\"));\n        container.Register<ITest2, Test22>(context => context.WithName(\"array\"));\n\n        Parallel.For(0, 10000, (i) =>\n        {\n            container.Resolve<ITest2>(\"enumerable\");\n            container.Resolve<ITest2>(\"array\");\n            var all = container.Resolve<IEnumerable<ITest2>>();\n\n            Assert.Equal(2, all.Count());\n        });\n    }\n\n    [Fact]\n    public void EnumerableTests_Parallel_Resolve_NonGeneric()\n    {\n        IStashboxContainer container = new StashboxContainer();\n        container.Register<ITest1, Test1>();\n        container.Register<ITest1, Test11>();\n        container.Register<ITest1, Test12>();\n        container.Register<ITest2, Test2>(context => context.WithName(\"enumerable\"));\n        container.Register<ITest2, Test22>(context => context.WithName(\"array\"));\n\n        Parallel.For(0, 10000, (i) =>\n        {\n            container.Resolve<ITest2>(\"enumerable\");\n            container.Resolve<ITest2>(\"array\");\n\n            var all = container.Resolve<IEnumerable<ITest2>>();\n            var all2 = (IEnumerable<ITest2>)container.ResolveAll(typeof(ITest2));\n\n            Assert.Equal(2, all2.Count());\n            Assert.Equal(2, all.Count());\n        });\n    }\n\n    [Fact]\n    public void EnumerableTests_Resolve_PreserveOrder()\n    {\n        IStashboxContainer container = new StashboxContainer();\n        container.Register<ITest1, Test1>();\n        container.Register<ITest1, Test11>();\n        container.Register<ITest1, Test12>();\n\n        var services = container.Resolve<IEnumerable<ITest1>>().ToArray();\n\n        Assert.IsType<Test1>(services[0]);\n        Assert.IsType<Test11>(services[1]);\n        Assert.IsType<Test12>(services[2]);\n    }\n\n    [Fact]\n    public void EnumerableTests_ResolveAll_PreserveOrder()\n    {\n        IStashboxContainer container = new StashboxContainer();\n        container.Register<ITest1, Test1>();\n        container.Register<ITest1, Test11>();\n        container.Register<ITest1, Test12>();\n\n        var services = container.ResolveAll<ITest1>().ToArray();\n\n        Assert.IsType<Test1>(services[0]);\n        Assert.IsType<Test11>(services[1]);\n        Assert.IsType<Test12>(services[2]);\n    }\n\n    [Fact]\n    public void EnumerableTests_Resolve_PreserveOrder_Scoped()\n    {\n        IStashboxContainer container = new StashboxContainer();\n\n        container.Register<ITest1, Test1>();\n        container.Register<ITest1, Test11>();\n        container.Register<ITest1, Test12>();\n\n        var child = container.BeginScope();\n\n        var services = child.Resolve<IEnumerable<ITest1>>().ToArray();\n\n        Assert.IsType<Test1>(services[0]);\n        Assert.IsType<Test11>(services[1]);\n        Assert.IsType<Test12>(services[2]);\n    }\n\n    [Fact]\n    public void EnumerableTests_Resolve_PreserveOrder_Parent()\n    {\n        IStashboxContainer container = new StashboxContainer();\n\n        container.Register<ITest1, Test1>();\n        container.Register<ITest1, Test11>();\n        container.Register<ITest1, Test12>();\n\n        var child = container.CreateChildContainer();\n\n        var services = child.Resolve<IEnumerable<ITest1>>().ToArray();\n\n        Assert.IsType<Test1>(services[0]);\n        Assert.IsType<Test11>(services[1]);\n        Assert.IsType<Test12>(services[2]);\n    }\n\n    [Fact]\n    public void EnumerableTests_Resolve_PreserveOrder_Scoped_Lazy()\n    {\n        IStashboxContainer container = new StashboxContainer();\n\n        container.Register<ITest1, Test1>();\n        container.Register<ITest1, Test11>();\n        container.Register<ITest1, Test12>();\n\n        var child = container.BeginScope();\n\n        var services = child.Resolve<IEnumerable<Lazy<ITest1>>>().ToArray();\n\n        Assert.IsType<Test1>(services[0].Value);\n        Assert.IsType<Test11>(services[1].Value);\n        Assert.IsType<Test12>(services[2].Value);\n    }\n\n    [Fact]\n    public void EnumerableTests_Resolve_PreserveOrder_Parent_Lazy()\n    {\n        IStashboxContainer container = new StashboxContainer();\n\n        container.Register<ITest1, Test1>();\n        container.Register<ITest1, Test11>();\n        container.Register<ITest1, Test12>();\n\n        var child = container.CreateChildContainer();\n\n        var services = child.Resolve<IEnumerable<Lazy<ITest1>>>().ToArray();\n\n        Assert.IsType<Test1>(services[0].Value);\n        Assert.IsType<Test11>(services[1].Value);\n        Assert.IsType<Test12>(services[2].Value);\n    }\n\n    [Fact]\n    public void EnumerableTests_Resolve_PreserveOrder_Scoped_Func()\n    {\n        IStashboxContainer container = new StashboxContainer();\n\n        container.Register<ITest1, Test1>();\n        container.Register<ITest1, Test11>();\n        container.Register<ITest1, Test12>();\n\n        var child = container.BeginScope();\n\n        var services = child.Resolve<IEnumerable<Func<ITest1>>>().ToArray();\n\n        Assert.IsType<Test1>(services[0]());\n        Assert.IsType<Test11>(services[1]());\n        Assert.IsType<Test12>(services[2]());\n    }\n\n    [Fact]\n    public void EnumerableTests_Resolve_PreserveOrder_Parent_Func()\n    {\n        IStashboxContainer container = new StashboxContainer();\n\n        container.Register<ITest1, Test1>();\n        container.Register<ITest1, Test11>();\n        container.Register<ITest1, Test12>();\n\n        var child = container.CreateChildContainer();\n\n        var services = child.Resolve<IEnumerable<Func<ITest1>>>().ToArray();\n\n        Assert.IsType<Test1>(services[0]());\n        Assert.IsType<Test11>(services[1]());\n        Assert.IsType<Test12>(services[2]());\n    }\n\n    [Fact]\n    public void EnumerableTests_Resolve_PreserveOrder_Lazy()\n    {\n        IStashboxContainer container = new StashboxContainer();\n        container.Register<ITest1, Test1>();\n        container.Register<ITest1, Test11>();\n        container.Register<ITest1, Test12>();\n\n        var services = container.Resolve<IEnumerable<Lazy<ITest1>>>().ToArray();\n\n        Assert.IsType<Test1>(services[0].Value);\n        Assert.IsType<Test11>(services[1].Value);\n        Assert.IsType<Test12>(services[2].Value);\n    }\n\n    [Fact]\n    public void EnumerableTests_Resolve_PreserveOrder_Func()\n    {\n        IStashboxContainer container = new StashboxContainer();\n        container.Register<ITest1, Test1>();\n        container.Register<ITest1, Test11>();\n        container.Register<ITest1, Test12>();\n\n        var services = container.Resolve<IEnumerable<Func<ITest1>>>().ToArray();\n\n        Assert.IsType<Test1>(services[0]());\n        Assert.IsType<Test11>(services[1]());\n        Assert.IsType<Test12>(services[2]());\n    }\n\n    [Fact]\n    public void EnumerableTests_Resolve_UniqueIds()\n    {\n        IStashboxContainer container = new StashboxContainer(config => config\n            .WithRegistrationBehavior(Rules.RegistrationBehavior.PreserveDuplications));\n        container.Register<ITest1, Test1>();\n        container.Register<ITest1, Test1>();\n        container.Register<ITest1, Test1>();\n\n        Assert.Equal(3, container.Resolve<IEnumerable<ITest1>>().Count());\n    }\n\n    [Fact]\n    public void EnumerableTests_Resolve_WithName()\n    {\n        IStashboxContainer container = new StashboxContainer();\n        container.Register<ITest1, Test1>(\"t\");\n        container.Register<ITest1, Test11>(\"t\");\n        container.Register<ITest1, Test12>();\n\n        var instances = container.Resolve<IEnumerable<ITest1>>(\"t\").ToArray();\n\n        Assert.Equal(2, instances.Length);\n        Assert.IsType<Test1>(instances[0]);\n        Assert.IsType<Test11>(instances[1]);\n    }\n\n    [Fact]\n    public void EnumerableTests_Resolve_WithName_Single()\n    {\n        IStashboxContainer container = new StashboxContainer();\n        container.Register<ITest1, Test1>(\"t1\");\n        container.Register<ITest1, Test11>(\"t2\");\n        container.Register<ITest1, Test12>();\n\n        Assert.Single(container.Resolve<IEnumerable<ITest1>>(\"t1\"));\n    }\n\n    [Fact]\n    public void EnumerableTests_Resolve_WithName_FromCache()\n    {\n        IStashboxContainer container = new StashboxContainer();\n        container.Register<ITest1, Test1>(\"t\");\n        container.Register<ITest1, Test11>(\"t\");\n        container.Register<ITest1, Test12>();\n\n        var instances = container.Resolve<IEnumerable<ITest1>>(\"t\").ToArray();\n\n        Assert.Equal(2, instances.Length);\n        Assert.IsType<Test1>(instances[0]);\n        Assert.IsType<Test11>(instances[1]);\n\n        var instances2 = container.Resolve<IEnumerable<ITest1>>(\"t\").ToArray();\n\n        Assert.Equal(2, instances2.Length);\n        Assert.IsType<Test1>(instances2[0]);\n        Assert.IsType<Test11>(instances2[1]);\n    }\n\n    [Fact]\n    public void EnumerableTests_ResolveAll_Generic_WithName()\n    {\n        IStashboxContainer container = new StashboxContainer();\n        container.Register<ITest1, Test1>(\"t\");\n        container.Register<ITest1, Test11>(\"t\");\n        container.Register<ITest1, Test12>();\n\n        var instances = container.ResolveAll<ITest1>(\"t\").ToArray();\n\n        Assert.Equal(2, instances.Length);\n        Assert.IsType<Test1>(instances[0]);\n        Assert.IsType<Test11>(instances[1]);\n    }\n\n    [Fact]\n    public void EnumerableTests_ResolveAll_Generic_WithName_FromCache()\n    {\n        IStashboxContainer container = new StashboxContainer();\n        container.Register<ITest1, Test1>(\"t\");\n        container.Register<ITest1, Test11>(\"t\");\n        container.Register<ITest1, Test12>();\n\n        var instances = container.ResolveAll<ITest1>(\"t\").ToArray();\n\n        Assert.Equal(2, instances.Length);\n        Assert.IsType<Test1>(instances[0]);\n        Assert.IsType<Test11>(instances[1]);\n\n        var instances2 = container.ResolveAll<ITest1>(\"t\").ToArray();\n\n        Assert.Equal(2, instances2.Length);\n        Assert.IsType<Test1>(instances2[0]);\n        Assert.IsType<Test11>(instances2[1]);\n    }\n\n    [Fact]\n    public void EnumerableTests_ResolveAll_WithName()\n    {\n        IStashboxContainer container = new StashboxContainer();\n        container.Register<ITest1, Test1>(\"t\");\n        container.Register<ITest1, Test11>(\"t\");\n        container.Register<ITest1, Test12>();\n\n        var instances = container.ResolveAll(typeof(ITest1), \"t\").ToArray();\n\n        Assert.Equal(2, instances.Length);\n        Assert.IsType<Test1>(instances[0]);\n        Assert.IsType<Test11>(instances[1]);\n    }\n\n    [Fact]\n    public void EnumerableTests_ResolveAll_WithName_FromCache()\n    {\n        IStashboxContainer container = new StashboxContainer();\n        container.Register<ITest1, Test1>(\"t\");\n        container.Register<ITest1, Test11>(\"t\");\n        container.Register<ITest1, Test12>();\n\n        var instances = container.ResolveAll(typeof(ITest1), \"t\").ToArray();\n\n        Assert.Equal(2, instances.Length);\n        Assert.IsType<Test1>(instances[0]);\n        Assert.IsType<Test11>(instances[1]);\n\n        var instances2 = container.ResolveAll(typeof(ITest1), \"t\").ToArray();\n\n        Assert.Equal(2, instances2.Length);\n        Assert.IsType<Test1>(instances2[0]);\n        Assert.IsType<Test11>(instances2[1]);\n    }\n\n    [Fact]\n    public void EnumerableTests_ResolveAll_PerRequest_WithName()\n    {\n        IStashboxContainer container = new StashboxContainer();\n        container.Register<ITest1, Test1>(c => c.WithName(\"t\").WithPerRequestLifetime());\n        container.Register<ITest1, Test11>(\"t\");\n        container.Register<ITest1, Test12>();\n\n        var instances = container.ResolveAll(typeof(ITest1), \"t\").ToArray();\n\n        Assert.Equal(2, instances.Length);\n        Assert.IsType<Test1>(instances[0]);\n        Assert.IsType<Test11>(instances[1]);\n    }\n\n    [Fact]\n    public void EnumerableTests_Scope_Resolve_WithName()\n    {\n        IStashboxContainer container = new StashboxContainer();\n        container.Register<ITest1, Test1>(\"t\");\n        container.Register<ITest1, Test11>(\"t\");\n        container.Register<ITest1, Test12>();\n\n        var instances = container.BeginScope().Resolve<IEnumerable<ITest1>>(\"t\").ToArray();\n\n        Assert.Equal(2, instances.Length);\n        Assert.IsType<Test1>(instances[0]);\n        Assert.IsType<Test11>(instances[1]);\n    }\n\n    [Fact]\n    public void EnumerableTests_Scope_Resolve_WithName_FromCache()\n    {\n        IStashboxContainer container = new StashboxContainer();\n        container.Register<ITest1, Test1>(\"t\");\n        container.Register<ITest1, Test11>(\"t\");\n        container.Register<ITest1, Test12>();\n\n        var instances = container.BeginScope().Resolve<IEnumerable<ITest1>>(\"t\").ToArray();\n\n        Assert.Equal(2, instances.Length);\n        Assert.IsType<Test1>(instances[0]);\n        Assert.IsType<Test11>(instances[1]); \n            \n        var instances2 = container.BeginScope().Resolve<IEnumerable<ITest1>>(\"t\").ToArray();\n\n        Assert.Equal(2, instances2.Length);\n        Assert.IsType<Test1>(instances2[0]);\n        Assert.IsType<Test11>(instances2[1]);\n    }\n\n    [Fact]\n    public void EnumerableTests_Scope_ResolveAll_Generic_WithName()\n    {\n        IStashboxContainer container = new StashboxContainer();\n        container.Register<ITest1, Test1>(\"t\");\n        container.Register<ITest1, Test11>(\"t\");\n        container.Register<ITest1, Test12>();\n\n        var instances = container.BeginScope().ResolveAll<ITest1>(\"t\").ToArray();\n\n        Assert.Equal(2, instances.Length);\n        Assert.IsType<Test1>(instances[0]);\n        Assert.IsType<Test11>(instances[1]);\n    }\n\n    [Fact]\n    public void EnumerableTests_Scope_ResolveAll_Generic_WithName_FromCache()\n    {\n        IStashboxContainer container = new StashboxContainer();\n        container.Register<ITest1, Test1>(\"t\");\n        container.Register<ITest1, Test11>(\"t\");\n        container.Register<ITest1, Test12>();\n\n        var instances = container.BeginScope().ResolveAll<ITest1>(\"t\").ToArray();\n\n        Assert.Equal(2, instances.Length);\n        Assert.IsType<Test1>(instances[0]);\n        Assert.IsType<Test11>(instances[1]);\n\n        var instances2 = container.BeginScope().ResolveAll<ITest1>(\"t\").ToArray();\n\n        Assert.Equal(2, instances2.Length);\n        Assert.IsType<Test1>(instances2[0]);\n        Assert.IsType<Test11>(instances2[1]);\n    }\n\n    [Fact]\n    public void EnumerableTests_Scope_ResolveAll_WithName()\n    {\n        IStashboxContainer container = new StashboxContainer();\n        container.Register<ITest1, Test1>(\"t\");\n        container.Register<ITest1, Test11>(\"t\");\n        container.Register<ITest1, Test12>();\n\n        var instances = container.BeginScope().ResolveAll(typeof(ITest1), \"t\").ToArray();\n\n        Assert.Equal(2, instances.Length);\n        Assert.IsType<Test1>(instances[0]);\n        Assert.IsType<Test11>(instances[1]);\n    }\n\n    [Fact]\n    public void EnumerableTests_Scope_ResolveAll_WithName_FromCache()\n    {\n        IStashboxContainer container = new StashboxContainer();\n        container.Register<ITest1, Test1>(\"t\");\n        container.Register<ITest1, Test11>(\"t\");\n        container.Register<ITest1, Test12>();\n\n        var instances = container.BeginScope().ResolveAll(typeof(ITest1), \"t\").ToArray();\n\n        Assert.Equal(2, instances.Length);\n        Assert.IsType<Test1>(instances[0]);\n        Assert.IsType<Test11>(instances[1]);\n\n        var instances2 = container.BeginScope().ResolveAll(typeof(ITest1), \"t\").ToArray();\n\n        Assert.Equal(2, instances2.Length);\n        Assert.IsType<Test1>(instances2[0]);\n        Assert.IsType<Test11>(instances2[1]);\n    }\n\n    [Fact]\n    public void EnumerableTests_Scope_ResolveAll_PerRequest_WithName()\n    {\n        IStashboxContainer container = new StashboxContainer();\n        container.Register<ITest1, Test1>(c => c.WithName(\"t\").WithPerRequestLifetime());\n        container.Register<ITest1, Test11>(\"t\");\n        container.Register<ITest1, Test12>();\n\n        var instances = container.BeginScope().ResolveAll(typeof(ITest1), \"t\").ToArray();\n\n        Assert.Equal(2, instances.Length);\n        Assert.IsType<Test1>(instances[0]);\n        Assert.IsType<Test11>(instances[1]);\n    }\n\n    [Fact]\n    public void EnumerableTests_ResolveAll_WithName_WithOverrides()\n    {\n        IStashboxContainer container = new StashboxContainer();\n        container.Register<ITest3, Test31>(\"t\");\n        container.Register<ITest3, Test32>(\"t\");\n        container.Register<ITest3, Test33>();\n\n        var inst = container.ResolveAll(typeof(ITest3), \"t\", [new Test1()]).OfType<ITest3>().ToArray();\n        Assert.Equal(2, inst.Length);\n        Assert.IsType<Test1>(inst[0].Test);\n        Assert.IsType<Test1>(inst[1].Test);\n    }\n\n    [Fact]\n    public void EnumerableTests_ResolveAll_Generic_WithName_WithOverrides()\n    {\n        IStashboxContainer container = new StashboxContainer();\n        container.Register<ITest3, Test31>(\"t\");\n        container.Register<ITest3, Test32>(\"t\");\n        container.Register<ITest3, Test33>();\n\n        var inst = container.ResolveAll<ITest3>(\"t\", [new Test1()]).ToArray();\n        Assert.Equal(2, inst.Length);\n        Assert.IsType<Test1>(inst[0].Test);\n        Assert.IsType<Test1>(inst[1].Test);\n    }\n\n    interface ITest1;\n\n    interface ITest2;\n\n    interface ITest3 { ITest1 Test { get; } }\n\n    class Test1 : ITest1;\n\n    class Test11 : ITest1;\n\n    class Test12 : ITest1;\n\n    class Test2 : ITest2\n    {\n        public Test2(IEnumerable<ITest1> tests)\n        {\n            Shield.EnsureNotNull(tests, nameof(tests));\n            Assert.Equal(3, tests.Count());\n        }\n    }\n\n    class Test22 : ITest2\n    {\n        public Test22(ITest1[] tests)\n        {\n            Shield.EnsureNotNull(tests, nameof(tests));\n            Assert.Equal(3, tests.Length);\n        }\n    }\n\n    class Test31 : ITest3\n    {\n        public ITest1 Test { get; }\n\n        public Test31(ITest1 test)\n        {\n            this.Test = test;\n        }\n    }\n\n    class Test32 : ITest3\n    {\n        public ITest1 Test { get; }\n\n        public Test32(ITest1 test)\n        {\n            this.Test = test;\n        }\n    }\n\n    class Test33 : ITest3\n    {\n        public ITest1 Test { get; }\n\n        public Test33(ITest1 test)\n        {\n            this.Test = test;\n        }\n    }\n}"
  },
  {
    "path": "test/FactoryTests.cs",
    "content": "﻿using Stashbox.Attributes;\nusing Stashbox.Configuration;\nusing Stashbox.Exceptions;\nusing Stashbox.Resolution;\nusing Stashbox.Tests.Utils;\nusing System;\nusing Xunit;\n\nnamespace Stashbox.Tests;\n\npublic class FactoryTests\n{\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void FactoryTests_DependencyResolve(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<ITest, Test>(context => context.WithFactory(() => new Test(\"test\")));\n        container.Register<ITest1, Test12>();\n\n        var inst = container.Resolve<ITest1>();\n\n        Assert.IsType<Test>(inst.Test);\n        Assert.Equal(\"test\", inst.Test.Name);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void FactoryTests_DependencyResolve_ServiceUpdated(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<ITest, Test>(context => context.WithFactory(() => new Test(\"test\")));\n        container.Register<ITest2, Test2>();\n        container.ReMap<ITest, Test>(context => context.WithFactory(() => new Test(\"test1\")));\n        var inst = container.Resolve<ITest2>();\n\n        Assert.IsType<Test>(inst.Test);\n        Assert.Equal(\"test1\", inst.Test.Name);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void FactoryTests_Resolve(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<ITest, Test>(context => context.WithFactory(() => new Test(\"test\")));\n        container.Register<ITest1, Test1>();\n\n        var inst = container.Resolve<ITest1>();\n\n        Assert.IsType<Test>(inst.Test);\n        Assert.Equal(\"test\", inst.Test.Name);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void FactoryTests_Resolve_NotSame(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<ITest, Test>(context =>\n            context.WithInjectionParameter(\"name\", \"test\"));\n        container.Register<ITest1>(context => context.WithFactory(cont =>\n        {\n            var test1 = cont.Resolve<ITest>();\n            return new Test12(test1);\n        }));\n\n        var inst1 = container.Resolve<ITest1>();\n        var inst2 = container.Resolve<ITest1>();\n\n        Assert.NotSame(inst1.Test, inst2.Test);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void FactoryTests_Resolve_ContainerFactory(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<Test3>();\n        container.Register<ITest>(context => context.WithFactory(c => c.Resolve<Test3>()));\n\n        var inst = container.Resolve<ITest>();\n\n        Assert.IsType<Test3>(inst);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void FactoryTests_Resolve_ContainerFactory_Constructor(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<Test3>();\n        container.Register<ITest1, Test12>();\n        container.Register(typeof(ITest), context => context.WithFactory(() => new Test3()));\n\n        var test1 = container.Resolve<ITest1>();\n        Assert.IsType<Test3>(test1.Test);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void FactoryTests_Resolve_ContainerFactory_Initializer(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<ITest4>(context =>\n            context.WithFactory(() => new Test4()).WithInitializer((t, r) => t.Init(\"Test\")));\n\n        var test1 = container.Resolve<ITest4>();\n        Assert.Equal(\"Test\", test1.Name);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void FactoryTests_Resolve_Gets_The_Proper_Scope(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<Test5>(context =>\n            context.WithFactory(resolver => new Test5(resolver)));\n\n        using var scope = container.BeginScope();\n        var t = scope.Resolve<Test5>();\n\n        Assert.Same(scope, t.DependencyResolver);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void FactoryTests_Resolve_With_Param1(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<TComp>(c => c.AsImplementedTypes());\n        container.Register<Dummy>(context =>\n            context.WithFactory<IT1>(t1 =>\n            {\n                Assert.IsType<TComp>(t1);\n                return new Dummy();\n            }));\n\n        container.Resolve<Dummy>();\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void FactoryTests_Resolve_With_Param2(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<TComp>(c => c.AsImplementedTypes());\n        container.Register<Dummy>(context =>\n            context.WithFactory<IT1, IT2>((t1, t2) =>\n            {\n                Assert.IsType<TComp>(t1);\n                Assert.IsType<TComp>(t2);\n                return new Dummy();\n            }));\n\n        container.Resolve<Dummy>();\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void FactoryTests_Resolve_With_Param3(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<TComp>(c => c.AsImplementedTypes());\n        container.Register<Dummy>(context =>\n            context.WithFactory<IT1, IT2, IT3>((t1, t2, t3) =>\n            {\n                Assert.IsType<TComp>(t1);\n                Assert.IsType<TComp>(t2);\n                Assert.IsType<TComp>(t3);\n                return new Dummy();\n            }));\n\n        container.Resolve<Dummy>();\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void FactoryTests_Resolve_With_Param4(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<TComp>(c => c.AsImplementedTypes());\n        container.Register<Dummy>(context =>\n            context.WithFactory<IT1, IT2, IT3, IT4>((t1, t2, t3, t4) =>\n            {\n                Assert.IsType<TComp>(t1);\n                Assert.IsType<TComp>(t2);\n                Assert.IsType<TComp>(t3);\n                Assert.IsType<TComp>(t4);\n                return new Dummy();\n            }));\n\n        container.Resolve<Dummy>();\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void FactoryTests_Resolve_With_Param5(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<TComp>(c => c.AsImplementedTypes());\n        container.Register<Dummy>(context =>\n            context.WithFactory<IT1, IT2, IT3, IT4, IT5>((t1, t2, t3, t4, t5) =>\n            {\n                Assert.IsType<TComp>(t1);\n                Assert.IsType<TComp>(t2);\n                Assert.IsType<TComp>(t3);\n                Assert.IsType<TComp>(t4);\n                Assert.IsType<TComp>(t5);\n                return new Dummy();\n            }));\n\n        container.Resolve<Dummy>();\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void FactoryTests_Resolve_With_Param_With_Resolver(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<Test5>(context =>\n            context.WithFactory<IDependencyResolver>(resolver =>\n            {\n                return new Test5(resolver);\n            }));\n\n        using var scope = container.BeginScope();\n        var inst = scope.Resolve<Test5>();\n\n        Assert.Same(scope, inst.DependencyResolver);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void FactoryTests_NonGeneric_Resolve_Gets_The_Proper_Scope(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register(typeof(Test5), context =>\n            context.WithFactory(resolver => new Test5(resolver)));\n\n        using var scope = container.BeginScope();\n        var t = scope.Resolve<Test5>();\n\n        Assert.Same(scope, t.DependencyResolver);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void FactoryTests_NonGeneric_Resolve_With_Param1(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<TComp>(c => c.AsImplementedTypes());\n        container.Register(typeof(Dummy), context =>\n            context.WithFactory<IT1>(t1 =>\n            {\n                Assert.IsType<TComp>(t1);\n                return new Dummy();\n            }));\n\n        container.Resolve<Dummy>();\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void FactoryTests_NonGeneric_Resolve_With_Param2(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<TComp>(c => c.AsImplementedTypes());\n        container.Register(typeof(Dummy), context =>\n            context.WithFactory<IT1, IT2>((t1, t2) =>\n            {\n                Assert.IsType<TComp>(t1);\n                Assert.IsType<TComp>(t2);\n                return new Dummy();\n            }));\n\n        container.Resolve<Dummy>();\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void FactoryTests_NonGeneric_Resolve_With_Param3(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<TComp>(c => c.AsImplementedTypes());\n        container.Register(typeof(Dummy), context =>\n            context.WithFactory<IT1, IT2, IT3>((t1, t2, t3) =>\n            {\n                Assert.IsType<TComp>(t1);\n                Assert.IsType<TComp>(t2);\n                Assert.IsType<TComp>(t3);\n                return new Dummy();\n            }));\n\n        container.Resolve<Dummy>();\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void FactoryTests_NonGeneric_Resolve_With_Param4(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<TComp>(c => c.AsImplementedTypes());\n        container.Register(typeof(Dummy), context =>\n            context.WithFactory<IT1, IT2, IT3, IT4>((t1, t2, t3, t4) =>\n            {\n                Assert.IsType<TComp>(t1);\n                Assert.IsType<TComp>(t2);\n                Assert.IsType<TComp>(t3);\n                Assert.IsType<TComp>(t4);\n                return new Dummy();\n            }));\n\n        container.Resolve<Dummy>();\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void FactoryTests_NonGeneric_Resolve_With_Param5(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<TComp>(c => c.AsImplementedTypes());\n        container.Register(typeof(Dummy), context =>\n            context.WithFactory<IT1, IT2, IT3, IT4, IT5>((t1, t2, t3, t4, t5) =>\n            {\n                Assert.IsType<TComp>(t1);\n                Assert.IsType<TComp>(t2);\n                Assert.IsType<TComp>(t3);\n                Assert.IsType<TComp>(t4);\n                Assert.IsType<TComp>(t5);\n                return new Dummy();\n            }));\n\n        container.Resolve<Dummy>();\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void FactoryTests_NonGeneric_Resolve_With_Param_With_Resolver(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register(typeof(Test5), context =>\n            context.WithFactory<IDependencyResolver>(resolver =>\n            {\n                return new Test5(resolver);\n            }));\n\n        using var scope = container.BeginScope();\n        var inst = scope.Resolve<Test5>();\n\n        Assert.Same(scope, inst.DependencyResolver);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void FactoryTests_Ensure_Exclude_Works(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType).WithDisposableTransientTracking());\n        var disposable = new Disposable();\n        Disposable second;\n        bool shouldSkip = true;\n        container.Register<Disposable>(context => context\n            .WithFactory<IRequestContext>(requestContext =>\n            {\n                if (shouldSkip)\n                {\n                    shouldSkip = false;\n                    return requestContext.ExcludeFromTracking(disposable);\n                }\n\n                return new Disposable();\n            }));\n\n        {\n            using var scope = container.BeginScope();\n            var inst = scope.Resolve<Disposable>();\n\n            Assert.Same(disposable, inst);\n\n            second = scope.Resolve<Disposable>();\n\n            Assert.NotSame(disposable, second);\n        }\n\n        Assert.True(second.IsDisposed);\n        Assert.False(disposable.IsDisposed);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void FactoryTests_Ensure_Exclude_Works_Scoped(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        var disposable = new Disposable();\n        Disposable second;\n        bool shouldSkip = true;\n        container.Register<Disposable>(context => context\n            .WithScopedLifetime()\n            .WithFactory<IRequestContext>(requestContext =>\n            {\n                if (shouldSkip)\n                {\n                    shouldSkip = false;\n                    return requestContext.ExcludeFromTracking(disposable);\n                }\n\n                return new Disposable();\n            }));\n\n        {\n            using var scope1 = container.BeginScope();\n            var inst = scope1.Resolve<Disposable>();\n\n            Assert.Same(disposable, inst);\n\n            using var scope2 = container.BeginScope();\n            second = scope2.Resolve<Disposable>();\n\n            Assert.NotSame(disposable, second);\n        }\n\n        Assert.True(second.IsDisposed);\n        Assert.False(disposable.IsDisposed);\n    }\n\n    private delegate object Factory(Type serviceType);\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void FactoryTests_Resolve_Factory_Type(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType))\n            .Register<Test3>()\n            .Register<Factory>(c => c.WithFactory(r => r.Resolve));\n\n        var factory = container.Resolve<Factory>();\n        var inst = factory(typeof(Test3));\n\n        Assert.NotNull(inst);\n        Assert.IsType<Test3>(inst);\n    }\n\n    private delegate ITest TestFactory(string s);\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void FactoryTests_Resolve_Factory_Delegate(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType))\n            .Register<ITest, Test>();\n\n        var factory = container.Resolve<TestFactory>();\n        var inst = factory(\"test\");\n\n        Assert.NotNull(inst);\n        Assert.IsType<Test>(inst);\n        Assert.Equal(\"test\", inst.Name);\n    }\n\n    private delegate void TestAction(string s);\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void FactoryTests_Resolve_Action_Throws(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType))\n            .Register<ITest, Test>();\n\n        Assert.Throws<ResolutionFailedException>(() => container.Resolve<TestAction>());\n    }\n    \n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void FactoryTests_Resolve_Multiple(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType).WithDisposableTransientTracking())\n            .Register<IT1, TD>(c => c.WithFactory(() => new TD()).AsServiceAlso<IT2>().AsServiceAlso<IT3>().AsServiceAlso<IT4>())\n            .Register<TT>();\n\n        var inst = container.Resolve<TT>();\n        Assert.IsType<TD>(inst.T1);\n        Assert.IsType<TD>(inst.T2);\n        Assert.IsType<TD>(inst.T3);\n        Assert.IsType<TD>(inst.T4);\n    }\n    \n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void FactoryTests_Resolve_Multiple_All(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType).WithDisposableTransientTracking())\n            .Register<IT1, TD>(c => c.WithFactory(() => new TD()).AsImplementedTypes())\n            .Register<TT>();\n\n        var inst = container.Resolve<TT>();\n        Assert.IsType<TD>(inst.T1);\n        Assert.IsType<TD>(inst.T2);\n        Assert.IsType<TD>(inst.T3);\n        Assert.IsType<TD>(inst.T4);\n    }\n    \n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void FactoryTests_Resolve_Action_Without_Implementation(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType))\n            .Register<IT1>(c => c.WithFactory(() => new TD()));\n\n        Assert.NotNull(container.Resolve<IT1>());\n    }\n    \n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void FactoryTests_Resolve_Action_Without_Implementation_AsServiceAlso(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType))\n            .Register<IT1>(c => c.WithFactory(() => new TD()).AsServiceAlso<IT2>());\n\n        Assert.IsType<TD>(container.Resolve<IT1>());\n        Assert.IsType<TD>(container.Resolve<IT2>());\n    }\n    \n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void FactoryTests_Resolve_Action_Without_Implementation_DependencyResolver_AsServiceAlso(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType))\n            .Register<IT1>(c => c.WithFactory(r => new TD()).AsServiceAlso<IT2>());\n\n        Assert.IsType<TD>(container.Resolve<IT1>());\n        Assert.IsType<TD>(container.Resolve<IT2>());\n    }\n    \n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void FactoryTests_Resolve_Action_Without_Implementation_AsImplementedTypes(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType))\n            .Register<IT1>(c => c.WithFactory(() => new TD()).AsImplementedTypes());\n\n        Assert.IsType<TD>(container.Resolve<IT1>());\n        Assert.IsType<TD>(container.Resolve<IT2>());\n    }\n    \n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void FactoryTests_Resolve_Action_Without_Implementation_DependencyResolver_AsImplementedTypes(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType))\n            .Register<IT1>(c => c.WithFactory(r => new TD()).AsImplementedTypes());\n\n        Assert.IsType<TD>(container.Resolve<IT1>());\n        Assert.IsType<TD>(container.Resolve<IT2>());\n    }\n    \n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void FactoryTests_Resolve_Action_Without_Implementation_DependencyResolver_AsServiceAlso_Param(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType))\n            .Register<Dummy>()\n            .Register<IT1>(c => c.WithFactory<Dummy>(_ => new TD()).AsServiceAlso<IT2>());\n\n        Assert.IsType<TD>(container.Resolve<IT1>());\n        Assert.IsType<TD>(container.Resolve<IT2>());\n    }\n    \n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void FactoryTests_Resolve_Action_Without_Implementation_DependencyResolver_AsImplementedTypes_Param(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType))\n            .Register<Dummy>()\n            .Register<IT1>(c => c.WithFactory<Dummy>(_ => new TD()).AsImplementedTypes());\n\n        Assert.IsType<TD>(container.Resolve<IT1>());\n        Assert.Throws<ResolutionFailedException>(() => container.Resolve<IT2>());\n    }\n    \n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void FactoryTests_Resolve_Action_Without_Implementation_AsServiceAlso_Interface(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType))\n            .Register<IT1>(c => c.WithFactory(() => (IT1)new TD()).AsServiceAlso<IT2>());\n\n        Assert.IsType<TD>(container.Resolve<IT1>());\n        Assert.IsType<TD>(container.Resolve<IT2>());\n    }\n    \n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void FactoryTests_Resolve_Action_Without_Implementation_AsImplementedTypes_Interface(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType))\n            .Register<IT1>(c => c.WithFactory(() => (IT1)new TD()).AsImplementedTypes());\n\n        Assert.IsType<TD>(container.Resolve<IT1>());\n        Assert.Throws<ResolutionFailedException>(() => container.Resolve<IT2>());\n    }\n    \n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void FactoryTests_Resolve_Action_Without_Implementation_Unknown(CompilerType compilerType)\n    {\n        using var container1 = new StashboxContainer().Register<IT1, TD>();\n        \n        using var container2 = new StashboxContainer(c => c.WithCompiler(compilerType)\n            .WithUnknownTypeResolution(opts =>\n            {\n                if (opts.ServiceType == typeof(IT1))\n                    opts.WithFactory(() => container1.Resolve(opts.ServiceType)).AsServiceAlso<IT2>();\n            }));\n\n        Assert.IsType<TD>(container2.Resolve<IT1>());\n        Assert.IsType<TD>(container2.Resolve<IT2>());\n    }\n    \n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void FactoryTests_Resolve_Action_Without_Implementation_Unknown_Open_Generic(CompilerType compilerType)\n    {\n        using var container1 = new StashboxContainer().Register(typeof(ITG<>), typeof(TG<>));\n        \n        using var container2 = new StashboxContainer(c => c.WithCompiler(compilerType)\n            .WithUnknownTypeResolution(opts =>\n            {\n                opts.WithFactory(() => container1.Resolve(opts.ServiceType));\n            }));\n\n        Assert.IsType<TG<int>>(container2.Resolve<ITG<int>>());\n        Assert.IsType<TG<string>>(container2.Resolve<ITG<string>>());\n    }\n    \n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void FactoryTests_Resolve_Action_Without_Implementation_Open_Generic(CompilerType compilerType)\n    {\n        using var container1 = new StashboxContainer().Register(typeof(ITG<>), typeof(TG<>));\n        \n        using var container2 = new StashboxContainer(c => c.WithCompiler(compilerType))\n            .Register(typeof(ITG<>), c => c.WithFactory<TypeInformation>(t => container1.Resolve(t.Type)));\n\n        Assert.IsType<TG<int>>(container2.Resolve<ITG<int>>());\n        Assert.IsType<TG<string>>(container2.Resolve<ITG<string>>());\n    }\n\n    interface ITG<T>;\n    \n    class TG<T> : ITG<T>;\n    \n    interface ITest { string Name { get; } }\n\n    interface ITest1 { ITest Test { get; } }\n\n    interface ITest2 { ITest Test { get; } }\n\n    class Test3 : ITest\n    {\n        public string Name { get; }\n    }\n\n    class Test : ITest\n    {\n        public string Name { get; }\n\n        public Test(string name)\n        {\n            this.Name = name;\n        }\n    }\n\n    class Test2 : ITest2\n    {\n        [Dependency]\n        public ITest Test { get; set; }\n    }\n\n    class Test1 : ITest1\n    {\n        public ITest Test { get; set; }\n\n        [InjectionMethod]\n        public void Init(ITest test)\n        {\n            this.Test = test;\n        }\n    }\n\n    class Test12 : ITest1\n    {\n        public ITest Test { get; private set; }\n\n        public Test12(ITest test)\n        {\n            this.Test = test;\n        }\n    }\n\n    interface ITest4 : ITest\n    {\n        void Init(string name);\n    }\n\n    class Test4 : ITest4\n    {\n        public string Name { get; private set; }\n\n        public void Init(string name) => Name = name;\n    }\n\n    class Test5\n    {\n        public IDependencyResolver DependencyResolver { get; }\n\n        public Test5(IDependencyResolver dependencyResolver)\n        {\n            DependencyResolver = dependencyResolver;\n        }\n    }\n\n    interface IT1;\n\n    interface IT2;\n\n    interface IT3;\n\n    interface IT4;\n\n    interface IT5;\n\n    class TComp : IT1, IT2, IT3, IT4, IT5;\n\n    class Dummy;\n\n    class Disposable : IDisposable\n    {\n        public bool IsDisposed { get; set; }\n        public void Dispose()\n        {\n            if (this.IsDisposed)\n                throw new ObjectDisposedException(nameof(Disposable));\n\n            this.IsDisposed = true;\n        }\n    }\n\n    class TD : IT1, IT2, IT3, IT4, IT5\n    {\n        [InjectionMethod]\n        public void Init() {}\n    }\n    \n    class TT\n    {\n        public IT1 T1 { get; }\n        public IT2 T2 { get; }\n        public IT3 T3 { get; }\n        public IT4 T4 { get; }\n\n        public TT(IT1 t1, IT2 t2, IT3 t3, IT4 t4)\n        {\n            T1 = t1;\n            T2 = t2;\n            T3 = t3;\n            T4 = t4;\n        }\n    }\n}"
  },
  {
    "path": "test/FuncTests.cs",
    "content": "﻿using Stashbox.Attributes;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Linq.Expressions;\nusing System.Threading.Tasks;\nusing Xunit;\n\nnamespace Stashbox.Tests;\n\npublic class FuncTests\n{\n    [Fact]\n    public void FuncTests_Resolve()\n    {\n        var container = new StashboxContainer();\n        container.Register<ITest, Test>();\n        var inst = container.Resolve<Func<ITest>>();\n\n        Assert.NotNull(inst);\n        Assert.IsType<Func<ITest>>(inst);\n        Assert.IsType<Test>(inst());\n    }\n\n    [Fact]\n    public void FuncTests_Resolve_AssignableFrom()\n    {\n        var container = new StashboxContainer();\n        container.Register<ITest, Test>();\n        var inst = container.Resolve<Func<ITest>>();\n\n        Assert.NotNull(inst);\n        Assert.IsAssignableFrom<Func<ITest>>(inst);\n        Assert.IsType<Test>(inst());\n    }\n\n    [Fact]\n    public void FuncTests_Resolve_Choose_Last()\n    {\n        var inst = new StashboxContainer()\n            .Register<ITest, Test>()\n            .Register<ITest, Test1>()\n            .Resolve<Func<ITest>>();\n\n        Assert.NotNull(inst);\n        Assert.IsType<Func<ITest>>(inst);\n        Assert.IsType<Test1>(inst());\n    }\n\n    [Fact]\n    public void FuncTests_Resolve_Scoped()\n    {\n        var container = new StashboxContainer()\n            .RegisterScoped<ITest, Test>();\n\n        using var scope = container.BeginScope();\n        var factory = scope.Resolve<Func<ITest>>();\n        var inst1 = factory();\n        var inst2 = factory();\n\n        Assert.Same(inst1, inst2);\n\n        using var scope2 = scope.BeginScope();\n        var factory1 = scope2.Resolve<Func<ITest>>();\n        var inst3 = factory1();\n        var inst4 = factory1();\n\n        Assert.Same(inst3, inst4);\n        Assert.NotSame(inst1, inst3);\n    }\n\n    [Fact]\n    public void FuncTests_Resolve_Null()\n    {\n        var container = new StashboxContainer();\n        var inst = container.ResolveOrDefault<Func<ITest>>();\n\n        Assert.Null(inst);\n    }\n\n    [Fact]\n    public void FuncTests_Resolve_Lazy()\n    {\n        var container = new StashboxContainer();\n        container.Register<ITest, Test>();\n        var inst = container.Resolve<Func<Lazy<ITest>>>();\n\n        Assert.NotNull(inst);\n        Assert.IsType<Func<Lazy<ITest>>>(inst);\n        Assert.IsType<Test>(inst().Value);\n    }\n\n    [Fact]\n    public void FuncTests_Resolve_Lazy_Null()\n    {\n        var container = new StashboxContainer();\n        var inst = container.ResolveOrDefault<Func<Lazy<ITest>>>();\n\n        Assert.Null(inst);\n    }\n\n    [Fact]\n    public void FuncTests_Resolve_Enumerable()\n    {\n        var container = new StashboxContainer();\n        container.Register<ITest, Test>();\n        var inst = container.Resolve<Func<IEnumerable<ITest>>>();\n\n        Assert.NotNull(inst);\n        Assert.IsType<Func<IEnumerable<ITest>>>(inst);\n        Assert.IsType<Test>(inst().First());\n    }\n\n    [Fact]\n    public void FuncTests_Resolve_Enumerable_Null()\n    {\n        var container = new StashboxContainer();\n        var inst = container.Resolve<Func<IEnumerable<ITest>>>();\n\n        Assert.Empty(inst());\n    }\n\n    [Fact]\n    public void FuncTests_Resolve_ConstructorDependency()\n    {\n        var container = new StashboxContainer();\n        container.Register<ITest, Test>();\n        container.Register<Test2>();\n        var inst = container.Resolve<Test2>();\n\n        Assert.NotNull(inst.Test);\n        Assert.IsType<Func<ITest>>(inst.Test);\n        Assert.IsType<Test>(inst.Test());\n    }\n\n    [Fact]\n    public void FuncTests_Resolve_ConstructorDependency_Null()\n    {\n        var container = new StashboxContainer();\n        container.Register<Test2>();\n        var inst = container.ResolveOrDefault<Test2>();\n\n        Assert.Null(inst);\n    }\n\n    [Fact]\n    public void FuncTests_Resolve_ParameterInjection()\n    {\n        var container = new StashboxContainer();\n        container.Register<IFTest1, FTest1>();\n        var inst = container.Resolve<Func<ITest, IFTest1>>();\n\n        var t = new Test();\n        var r = inst(t);\n\n        Assert.Same(t, r.Test);\n    }\n\n    [Fact]\n    public void FuncTests_Resolve_ParameterInjection_2Params()\n    {\n        var container = new StashboxContainer();\n        container.Register<IFTest2, FTest2>();\n        var inst = container.Resolve<Func<ITest, IFTest1, IFTest2>>();\n\n        var t = new Test();\n        var t1 = new FTest1();\n        var r = inst(t, t1);\n\n        Assert.Same(t, r.Test);\n        Assert.Same(t1, r.Test1);\n    }\n\n    [Fact]\n    public void FuncTests_Resolve_ParameterInjection_3Params()\n    {\n        var container = new StashboxContainer();\n        container.Register<IFTest3, FTest3>();\n        var inst = container.Resolve<Func<ITest, IFTest1, IFTest2, IFTest3>>();\n\n        var t = new Test();\n        var t1 = new FTest1();\n        var t2 = new FTest2(null);\n        var r = inst(t, t1, t2);\n\n        Assert.Same(t, r.Test);\n        Assert.Same(t1, r.Test1);\n        Assert.Same(t2, r.Test2);\n    }\n\n    [Fact]\n    public void FuncTests_Resolve_ParameterInjection_SubDependency()\n    {\n        var container = new StashboxContainer();\n        container.Register<FunctTest2>();\n        container.Register<FuncTest>();\n        var inst = container.Resolve<Func<ITest, FuncTest>>();\n\n        var t = new Test();\n        var r = inst(t);\n\n        Assert.Same(t, r.Func2.Test);\n    }\n\n    [Fact]\n    public void FuncTests_Resolve_ParameterInjection_Mixed()\n    {\n        var container = new StashboxContainer();\n        container.Register<FuncTest3>();\n        container.Register<FuncTest4>();\n        container.Register<Dep2>();\n        container.Register<Dep4>();\n        var inst = container.Resolve<FuncTest3>();\n\n        var d1 = new Dep1();\n        var d3 = new Dep3();\n\n        var d = inst.Dep(d1, d3);\n\n        var d12 = new Dep1();\n\n        Assert.NotSame(d1, d.Dep(d12).Dep);\n        Assert.Same(d12, d.Dep(d12).Dep);\n    }\n\n    [Fact]\n    public void FuncTests_Resolve_ParameterInjection_Mixed2()\n    {\n        var container = new StashboxContainer();\n        container.Register<FuncTest5>();\n        container.Register<FuncTest6>();\n        container.Register<Dep2>();\n        container.Register<Dep4>();\n        var inst = container.Resolve<FuncTest5>();\n\n        var d3 = new Dep3();\n\n        var d = inst.Dep(d3);\n\n        var d32 = new Dep3();\n\n        Assert.NotNull(d.Dep(d32).Dep);\n        Assert.NotSame(d3, d.Dep(d32).Dep);\n        Assert.Same(d3, d.Dep1);\n    }\n\n    [Fact]\n    public void FuncTests_Register_FuncDelegate()\n    {\n        var container = new StashboxContainer();\n        container.RegisterFunc<string, RegisteredFuncTest>((name, resolver) =>\n        {\n            Assert.NotNull(name);\n            Assert.NotNull(resolver);\n            return new RegisteredFuncTest(name);\n        });\n\n        var test = container.Resolve<Func<string, RegisteredFuncTest>>()(\"test\");\n\n        Assert.Equal(\"test\", test.Name);\n    }\n\n    [Fact]\n    public void FuncTests_Register_FuncDelegate_Lazy()\n    {\n        var container = new StashboxContainer();\n        container.RegisterFunc<string, RegisteredFuncTest>((name, resolver) =>\n        {\n            Assert.NotNull(name);\n            Assert.NotNull(resolver);\n            return new RegisteredFuncTest(name);\n        });\n\n        var test = container.Resolve<Lazy<Func<string, RegisteredFuncTest>>>().Value(\"test\");\n\n        Assert.Equal(\"test\", test.Name);\n    }\n\n    [Fact]\n    public void FuncTests_Register_FuncDelegate_Resolver()\n    {\n        var container = new StashboxContainer();\n        var test1 = new Test();\n        container.RegisterInstance<ITest>(test1);\n        container.RegisterFunc<string, RegisteredFuncTest2>((name, resolver) => new RegisteredFuncTest2(name, resolver.Resolve<ITest>()));\n\n        var test = container.Resolve<Func<string, RegisteredFuncTest2>>()(\"test\");\n\n        Assert.Same(test1, test.Test1);\n        Assert.Equal(\"test\", test.Name);\n    }\n\n    [Fact]\n    public void FuncTests_Register_FuncDelegate_TwoParams()\n    {\n        var container = new StashboxContainer();\n        var t1 = new Test();\n        var t2 = new Test();\n        container.RegisterFunc<ITest, ITest, RegisteredFuncTest3>((test1, test2, resolver) => new RegisteredFuncTest3(test1, test2));\n\n        var test = container.Resolve<Func<ITest, ITest, RegisteredFuncTest3>>()(t1, t2);\n\n        Assert.Same(t1, test.Test1);\n        Assert.Same(t2, test.Test2);\n    }\n\n    [Fact]\n    public void FuncTests_Register_FuncDelegate_ThreeParams()\n    {\n        var container = new StashboxContainer();\n        var t1 = new Test();\n        var t2 = new Test();\n        var t3 = new Test();\n        container.RegisterFunc<ITest, ITest, ITest, RegisteredFuncTest4>((test1, test2, test3, resolver) => new RegisteredFuncTest4(test1, test2, test3));\n\n        var test = container.Resolve<Func<ITest, ITest, ITest, RegisteredFuncTest4>>()(t1, t2, t3);\n\n        Assert.Same(t1, test.Test1);\n        Assert.Same(t2, test.Test2);\n        Assert.Same(t3, test.Test3);\n    }\n\n    [Fact]\n    public void FuncTests_Register_FuncDelegate_FourParams()\n    {\n        var container = new StashboxContainer();\n        var t1 = new Test();\n        var t2 = new Test();\n        var t3 = new Test();\n        var t4 = new Test();\n        container.RegisterFunc<ITest, ITest, ITest, ITest, RegisteredFuncTest5>((test1, test2, test3, test4, resolver) => new RegisteredFuncTest5(test1, test2, test3, test4));\n\n        var test = container.Resolve<Func<ITest, ITest, ITest, ITest, RegisteredFuncTest5>>()(t1, t2, t3, t4);\n\n        Assert.Same(t1, test.Test1);\n        Assert.Same(t2, test.Test2);\n        Assert.Same(t3, test.Test3);\n        Assert.Same(t4, test.Test4);\n    }\n\n    [Fact]\n    public async Task FuncTests_Register_FuncDelegate_Async()\n    {\n        var container = new StashboxContainer();\n        var test = new Test();\n        container.RegisterInstance(test);\n        container.RegisterFunc(async resolver => await Task.FromResult(resolver.Resolve<Test>()));\n\n        var inst = await container.Resolve<Func<Task<Test>>>()();\n        var inst2 = await container.Resolve<Func<Task<Test>>>()();\n\n        Assert.Same(test, inst);\n        Assert.Same(inst, inst2);\n    }\n\n    [Fact]\n    public async Task FuncTests_Register_FuncDelegate_Async_Longrun()\n    {\n        var container = new StashboxContainer();\n        var test = new Test();\n        container.RegisterInstance(test);\n        container.RegisterFunc(async resolver =>\n        {\n            await Task.Delay(1000);\n            return resolver.Resolve<Test>();\n        });\n\n        var inst = await container.Resolve<Func<Task<Test>>>()();\n\n        Assert.Same(test, inst);\n    }\n\n    [Fact]\n    public void FuncTests_Register_Named()\n    {\n        var container = new StashboxContainer();\n\n        container.RegisterFunc<ITest>(resolver => new Test(), \"test\");\n\n        var test = container.Resolve<Func<ITest>>(\"test\")();\n\n        Assert.NotNull(test);\n    }\n\n    [Fact]\n    public void FuncTests_Register_Multiple()\n    {\n        var container = new StashboxContainer();\n\n        container.RegisterFunc<ITest>(resolver => new Test());\n        container.RegisterFunc(resolver => new Dep1());\n\n        Assert.IsAssignableFrom<ITest>(container.Resolve<Func<ITest>>()());\n        Assert.IsAssignableFrom<Dep1>(container.Resolve<Func<Dep1>>()());\n    }\n\n    [Fact]\n    public void FuncTests_Register_Multiple_ReMap()\n    {\n        var container = new StashboxContainer();\n\n        container.Register<ITest, Test>();\n        container.RegisterFunc(resolver => resolver.Resolve<ITest>());\n\n        Assert.NotNull(container.Resolve<Func<ITest>>()());\n\n        container.ReMap<ITest, Test>();\n\n        Assert.NotNull(container.Resolve<Func<ITest>>()());\n    }\n\n    [Fact]\n    public void FuncTests_Register_Parallel()\n    {\n        var container = new StashboxContainer();\n\n        Parallel.For(0, 2000, i =>\n        {\n            container.RegisterFunc<ITest>(resolver => new Test(), i.ToString());\n\n            var test = container.Resolve<Func<ITest>>(i.ToString())();\n\n            Assert.NotNull(test);\n        });\n    }\n\n    [Fact]\n    public void FuncTests_Register_Compiled_Lambda()\n    {\n        var inst = new StashboxContainer()\n            .RegisterFunc(typeof(Test)\n                .GetConstructor(Type.EmptyTypes)\n                .MakeNew()\n                .AsLambda<Func<IDependencyResolver, ITest>>(typeof(IDependencyResolver).AsParameter())\n                .Compile())\n            .Resolve<Func<ITest>>()();\n\n        Assert.NotNull(inst);\n    }\n\n    [Fact]\n    public void FuncTests_Register_Static_Factory()\n    {\n        var inst = new StashboxContainer()\n            .RegisterFunc(Create)\n            .Resolve<Func<ITest>>()();\n\n        Assert.NotNull(inst);\n    }\n\n    [Fact]\n    public void FuncTests_Register_Does_Not_Resolve_Same_As_Param()\n    {\n        var preInst = new Test();\n        var inst = new StashboxContainer()\n            .RegisterInstance<ITest>(preInst)\n            .Register<FunctTest2>()\n            .Register<SameAsParamFuncTest>()\n            .Resolve<SameAsParamFuncTest>();\n\n        Assert.NotSame(inst.Factory(new Test()).Test, preInst);\n        Assert.Same(inst.Factory(preInst).Test, preInst);\n        Assert.Same(inst.Test, preInst);\n    }\n\n    static ITest Create(IDependencyResolver resolver) =>\n        new Test();\n\n    class RegisteredFuncTest\n    {\n        public string Name { get; }\n\n        public RegisteredFuncTest(string name)\n        {\n            this.Name = name;\n        }\n    }\n\n    class RegisteredFuncTest2\n    {\n        public string Name { get; }\n        public ITest Test1 { get; }\n\n        public RegisteredFuncTest2(string name, ITest test1)\n        {\n            this.Name = name;\n            this.Test1 = test1;\n        }\n    }\n\n    class RegisteredFuncTest3\n    {\n        public ITest Test1 { get; }\n        public ITest Test2 { get; }\n\n        public RegisteredFuncTest3(ITest test1, ITest test2)\n        {\n            this.Test1 = test1;\n            this.Test2 = test2;\n        }\n    }\n\n    class RegisteredFuncTest4\n    {\n        public ITest Test1 { get; }\n        public ITest Test2 { get; }\n        public ITest Test3 { get; }\n\n        public RegisteredFuncTest4(ITest test1, ITest test2, ITest test3)\n        {\n            this.Test1 = test1;\n            this.Test2 = test2;\n            this.Test3 = test3;\n        }\n    }\n\n    class RegisteredFuncTest5\n    {\n        public ITest Test1 { get; }\n        public ITest Test2 { get; }\n        public ITest Test3 { get; }\n        public ITest Test4 { get; }\n\n        public RegisteredFuncTest5(ITest test1, ITest test2, ITest test3, ITest test4)\n        {\n            this.Test1 = test1;\n            this.Test2 = test2;\n            this.Test3 = test3;\n            this.Test4 = test4;\n        }\n    }\n\n    class SameAsParamFuncTest\n    {\n        public Func<ITest, FunctTest2> Factory { get; }\n        public ITest Test { get; }\n\n        public SameAsParamFuncTest(Func<ITest, FunctTest2> factory, ITest test)\n        {\n            this.Factory = factory;\n            this.Test = test;\n        }\n    }\n\n    class FuncTest\n    {\n        public FunctTest2 Func2 { get; set; }\n\n        public FuncTest(FunctTest2 func2)\n        {\n            this.Func2 = func2;\n        }\n    }\n\n    class FunctTest2\n    {\n        public ITest Test { get; set; }\n\n        public FunctTest2(ITest test)\n        {\n            this.Test = test;\n        }\n    }\n\n    class FuncTest3\n    {\n        public Func<Dep1, Dep3, FuncTest4> Dep { get; set; }\n\n        public FuncTest3(Func<Dep1, Dep3, FuncTest4> dep)\n        {\n            Dep = dep;\n        }\n    }\n\n    class FuncTest4\n    {\n        public Func<Dep1, Dep2> Dep { get; set; }\n        public Func<Dep3, Dep4> Dep1 { get; set; }\n\n        public FuncTest4(Func<Dep1, Dep2> dep, Func<Dep3, Dep4> dep1)\n        {\n            Dep = dep;\n            Dep1 = dep1;\n        }\n    }\n\n    class FuncTest5\n    {\n        public Func<Dep3, FuncTest6> Dep { get; set; }\n\n        public FuncTest5(Func<Dep3, FuncTest6> dep)\n        {\n            Dep = dep;\n        }\n    }\n\n    class FuncTest6\n    {\n        public Dep3 Dep1 { get; set; }\n        public Func<Dep3, Dep4> Dep { get; set; }\n\n        public FuncTest6(Dep3 dep1, Func<Dep3, Dep4> dep)\n        {\n            Dep1 = dep1;\n            Dep = dep;\n        }\n    }\n\n    class Dep1;\n\n    class Dep2\n    {\n        public Dep1 Dep { get; set; }\n\n        public Dep2(Dep1 dep)\n        {\n            Dep = dep;\n        }\n    }\n\n    class Dep3;\n\n    class Dep4\n    {\n        public Dep3 Dep { get; set; }\n\n        public Dep4(Dep3 dep)\n        {\n            Dep = dep;\n        }\n    }\n\n    interface ITest;\n\n    interface IFTest1\n    {\n        ITest Test { get; set; }\n    }\n\n    interface IFTest2\n    {\n        IFTest1 Test1 { get; set; }\n\n        ITest Test { get; set; }\n    }\n\n    interface IFTest3\n    {\n        IFTest2 Test2 { get; set; }\n\n        IFTest1 Test1 { get; set; }\n\n        ITest Test { get; set; }\n    }\n\n    class FTest1 : IFTest1\n    {\n        public ITest Test { get; set; }\n\n        [InjectionMethod]\n        public void Init(ITest test)\n        {\n            this.Test = test;\n        }\n    }\n\n    class FTest2 : IFTest2\n    {\n        [Dependency]\n        public ITest Test { get; set; }\n\n        public IFTest1 Test1 { get; set; }\n\n        public FTest2(IFTest1 test1)\n        {\n            this.Test1 = test1;\n        }\n    }\n\n    class FTest3 : IFTest3\n    {\n        [Dependency]\n        public IFTest2 Test2 { get; set; }\n\n        public IFTest1 Test1 { get; set; }\n\n        public ITest Test { get; set; }\n\n        [InjectionMethod]\n        public void Init(ITest test)\n        {\n            this.Test = test;\n        }\n\n        public FTest3(IFTest1 test1)\n        {\n            this.Test1 = test1;\n        }\n    }\n\n    class Test : ITest;\n\n    class Test1 : ITest;\n\n    class Test2\n    {\n        public Func<ITest> Test { get; private set; }\n\n        public Test2(Func<ITest> test)\n        {\n            this.Test = test;\n        }\n    }\n}"
  },
  {
    "path": "test/GenericTests.cs",
    "content": "﻿using Stashbox.Attributes;\nusing Stashbox.Configuration;\nusing Stashbox.Exceptions;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing Xunit;\n\nnamespace Stashbox.Tests;\n\npublic class GenericTests\n{\n    [Fact]\n    public void GenericTests_Resolve()\n    {\n        using var container = new StashboxContainer();\n        container.Register(typeof(ITest1<,>), typeof(Test1<,>));\n        var inst = container.Resolve<ITest1<int, string>>();\n\n        Assert.NotNull(inst);\n        Assert.IsType<Test1<int, string>>(inst);\n    }\n\n    [Fact]\n    public void GenericTests_Resolve_Singleton()\n    {\n        using var container = new StashboxContainer();\n        container.RegisterSingleton(typeof(ITest1<,>), typeof(Test1<,>));\n        var en = container.Resolve<IEnumerable<ITest1<int, string>>>();\n        var inst = container.Resolve<ITest1<int, string>>();\n\n        Assert.Same(inst, en.ToArray()[0]);\n    }\n\n    [Fact]\n    public void GenericTests_Resolve_Singleton_Many()\n    {\n        using var container = new StashboxContainer(config => config\n            .WithRegistrationBehavior(Rules.RegistrationBehavior.PreserveDuplications));\n        container.RegisterSingleton(typeof(ITest1<,>), typeof(Test1<,>));\n        container.RegisterSingleton(typeof(ITest1<,>), typeof(Test1<,>));\n        var en = container.Resolve<IEnumerable<ITest1<int, string>>>();\n        var inst = container.Resolve<ITest1<int, string>>();\n\n        Assert.Same(inst, en.ToArray()[1]);\n    }\n\n    [Fact]\n    public void GenericTests_Resolve_Singleton_Many_Mixed()\n    {\n        using var container = new StashboxContainer(config => config\n            .WithRegistrationBehavior(Rules.RegistrationBehavior.PreserveDuplications));\n        var inst = new Test1<int, string>();\n        container.RegisterSingleton(typeof(ITest1<int, string>), typeof(Test1<int, string>));\n        container.RegisterSingleton(typeof(ITest1<,>), typeof(Test1<,>));\n        container.Register(typeof(ITest1<int, string>), typeof(Test1<int, string>), config => config.WithInstance(inst));\n        var en = container.Resolve<IEnumerable<ITest1<int, string>>>().ToArray();\n\n        Assert.Equal(3, en.Length);\n        Assert.Same(inst, en[2]);\n    }\n\n    [Fact]\n    public void GenericTests_Resolve_SameTime_DifferentParameter()\n    {\n        using var container = new StashboxContainer();\n        container.Register(typeof(ITest1<,>), typeof(Test1<,>));\n        var inst = container.Resolve<ITest1<int, string>>();\n        var inst2 = container.Resolve<ITest1<int, int>>();\n\n        Assert.NotNull(inst);\n        Assert.IsType<Test1<int, string>>(inst);\n\n        Assert.NotNull(inst2);\n        Assert.IsType<Test1<int, int>>(inst2);\n    }\n\n    [Fact]\n    public void GenericTests_Resolve_SameTime_DifferentParameter_Singleton()\n    {\n        using var container = new StashboxContainer();\n        container.RegisterSingleton(typeof(ITest1<,>), typeof(Test1<,>));\n        var inst = container.Resolve<ITest1<int, string>>();\n        var inst2 = container.Resolve<ITest1<int, int>>();\n\n        Assert.NotNull(inst);\n        Assert.IsType<Test1<int, string>>(inst);\n\n        Assert.NotNull(inst2);\n        Assert.IsType<Test1<int, int>>(inst2);\n    }\n\n    [Fact]\n    public void GenericTests_CanResolve()\n    {\n        using var container = new StashboxContainer();\n        container.Register(typeof(ITest1<,>), typeof(Test1<,>));\n        Assert.False(container.CanResolve(typeof(ITest1<,>)));\n        Assert.True(container.CanResolve(typeof(ITest1<int, int>)));\n    }\n\n    [Fact]\n    public void GenericTests_Named()\n    {\n        using var container = new StashboxContainer();\n        container.Register(typeof(ITest1<,>), typeof(Test1<,>), config => config.WithName(\"G1\"));\n        container.Register(typeof(ITest1<,>), typeof(Test12<,>), config => config.WithName(\"G2\"));\n\n        Assert.IsType<Test1<int, string>>(container.Resolve<ITest1<int, string>>(\"G1\"));\n        Assert.IsType<Test12<int, double>>(container.Resolve<ITest1<int, double>>(\"G2\"));\n    }\n\n    [Fact]\n    public void GenericTests_DependencyResolve()\n    {\n        using var container = new StashboxContainer();\n        container.Register(typeof(ITest1<,>), typeof(Test1<,>));\n        container.Register(typeof(ITest2<,>), typeof(Test2<,>));\n        var inst = container.Resolve<ITest2<int, string>>();\n\n        Assert.NotNull(inst.Test);\n        Assert.IsType<Test1<int, string>>(inst.Test);\n    }\n\n    [Fact]\n    public void GenericTests_Resolve_Fluent()\n    {\n        using var container = new StashboxContainer();\n        container.Register(typeof(ITest1<,>), typeof(Test1<,>));\n        var inst = container.Resolve<ITest1<int, string>>();\n\n        Assert.NotNull(inst);\n        Assert.IsType<Test1<int, string>>(inst);\n    }\n\n    [Fact]\n    public void GenericTests_Resolve_ReMap()\n    {\n        using var container = new StashboxContainer();\n        container.Register(typeof(ITest1<,>), typeof(Test1<,>));\n        container.ReMap(typeof(ITest1<,>), typeof(Test12<,>));\n        var inst = container.Resolve<ITest1<int, string>>();\n\n        Assert.NotNull(inst);\n        Assert.IsType<Test12<int, string>>(inst);\n    }\n\n    [Fact]\n    public void GenericTests_Resolve_ReMap_Fluent()\n    {\n        using var container = new StashboxContainer();\n        container.Register(typeof(ITest1<,>), typeof(Test1<,>));\n        container.ReMap(typeof(ITest1<,>), typeof(Test12<,>));\n        var inst = container.Resolve<ITest1<int, string>>();\n\n        Assert.NotNull(inst);\n        Assert.IsType<Test12<int, string>>(inst);\n    }\n\n    [Fact]\n    public void GenericTests_Resolve_Parallel()\n    {\n        using var container = new StashboxContainer();\n        container.Register(typeof(ITest1<,>), typeof(Test1<,>));\n\n        Parallel.For(0, 50000, (i) =>\n        {\n            var inst = container.Resolve<ITest1<int, string>>();\n\n            Assert.NotNull(inst);\n            Assert.IsType<Test1<int, string>>(inst);\n        });\n    }\n\n    [Fact]\n    public void GenericTests_Resolve_Constraint_Array()\n    {\n        using var container = new StashboxContainer();\n        container.Register(typeof(IConstraintTest<>), typeof(ConstraintTest<>));\n        container.Register(typeof(IConstraintTest<>), typeof(ConstraintTest2<>));\n\n        var inst = container.ResolveAll<IConstraintTest<ConstraintArgument>>().ToArray();\n        Assert.Single(inst);\n    }\n\n    [Fact]\n    public void GenericTests_Resolve_Constraint_Multiple()\n    {\n        using var container = new StashboxContainer();\n        container.Register(typeof(IConstraintTest<>), typeof(ConstraintTest2<>));\n        container.Register(typeof(IConstraintTest<>), typeof(ConstraintTest<>));\n\n        var inst = container.Resolve<IConstraintTest<ConstraintArgument>>();\n        Assert.IsType<ConstraintTest<ConstraintArgument>>(inst);\n    }\n\n    [Fact]\n    public void GenericTests_Resolve_Constraint()\n    {\n        using var container = new StashboxContainer();\n        container.Register(typeof(IConstraintTest<>), typeof(ConstraintTest2<>));\n        Assert.Throws<ResolutionFailedException>(() => container.Resolve<IConstraintTest<ConstraintArgument>>());\n    }\n\n    [Fact]\n    public void GenericTests_Resolve_Constraint_Constructor()\n    {\n        using var container = new StashboxContainer();\n        container.Register(typeof(IConstraintTest<>), typeof(ConstraintTest<>));\n        container.Register(typeof(IConstraintTest<>), typeof(ConstraintTest2<>));\n        container.Register<ConstraintTest3>();\n        var inst = container.Resolve<ConstraintTest3>();\n\n        Assert.IsType<ConstraintTest<ConstraintArgument>>(inst.Test);\n    }\n\n    [Fact]\n    public void GenericTests_Resolve_Constraint_Pick_RightImpl()\n    {\n        using var container = new StashboxContainer();\n        container.Register(typeof(IConstraintTest<>), typeof(ConstraintTest2<>));\n        container.Register(typeof(IConstraintTest<>), typeof(ConstraintTest3<>));\n\n        var inst = container.Resolve<IConstraintTest<ConstraintArgument1>>();\n        Assert.IsType<ConstraintTest3<ConstraintArgument1>>(inst);\n    }\n\n    [Fact]\n    public void GenericTests_Resolve_Constraint_Pick_RightImpl_Decorator()\n    {\n        using var container = new StashboxContainer();\n        container.Register(typeof(IConstraintTest<>), typeof(ConstraintTest2<>));\n        container.Register(typeof(IConstraintTest<>), typeof(ConstraintTest3<>));\n        container.RegisterDecorator(typeof(IConstraintTest<>), typeof(ConstraintDecorator<>));\n        container.RegisterDecorator(typeof(IConstraintTest<>), typeof(ConstraintDecorator2<>));\n\n        var inst = (ConstraintDecorator2<ConstraintArgument1>)container.Resolve<IConstraintTest<ConstraintArgument1>>();\n        Assert.IsType<ConstraintTest3<ConstraintArgument1>>(inst.ConstraintTest);\n    }\n\n    [Fact]\n    public void GenericTests_Resolve_Prefer_Open_Generic_In_Named_Scope()\n    {\n        var container = new StashboxContainer(config => config\n                .WithRegistrationBehavior(Rules.RegistrationBehavior.PreserveDuplications))\n            .Register<ITest1<int, string>, Test1<int, string>>()\n            .Register(typeof(ITest1<,>), typeof(Test1<,>), config => config.InNamedScope(\"A\"));\n\n        container.BeginScope(\"A\").Resolve<ITest1<int, string>>();\n\n        Assert.Equal(2, container.ContainerContext.RegistrationRepository.GetRegistrationMappings().Count());\n    }\n\n    [Fact]\n    public void GenericTests_Resolve_Prefer_Open_Generic_Enumerable_In_Named_Scope()\n    {\n        var container = new StashboxContainer(config => config\n                .WithRegistrationBehavior(Rules.RegistrationBehavior.PreserveDuplications))\n            .Register<ITest1<int, string>, Test1<int, string>>(config => config.InNamedScope(\"A\"))\n            .Register(typeof(ITest1<,>), typeof(Test1<,>), config => config.InNamedScope(\"A\"));\n\n        var res = container.BeginScope(\"A\").Resolve<IEnumerable<ITest1<int, string>>>();\n\n        Assert.Equal(2, res.Count());\n    }\n\n    [Fact]\n    public void GenericTests_Resolve_Prefer_Valid_Constraint_In_Named_Scope()\n    {\n        var inst = new StashboxContainer()\n            .Register(typeof(IConstraintTest<>), typeof(ConstraintTest3<>), config => config.InNamedScope(\"A\"))\n            .Register(typeof(IConstraintTest<>), typeof(ConstraintTest2<>), config => config.InNamedScope(\"A\"))\n            .BeginScope(\"A\")\n            .Resolve<IConstraintTest<ConstraintArgument1>>();\n\n        Assert.IsType<ConstraintTest3<ConstraintArgument1>>(inst);\n    }\n\n    [Fact]\n    public void GenericTests_Resolve_Prefer_Valid_Constraint_In_Named_Scope_Enumerable()\n    {\n        var inst = new StashboxContainer()\n            .Register(typeof(IConstraintTest<>), typeof(ConstraintTest3<>), config => config.InNamedScope(\"A\"))\n            .Register(typeof(IConstraintTest<>), typeof(ConstraintTest2<>), config => config.InNamedScope(\"A\"))\n            .BeginScope(\"A\")\n            .ResolveAll<IConstraintTest<ConstraintArgument1>>();\n\n        Assert.Single(inst);\n    }\n\n    [Fact]\n    public void GenericTests_Nested_Generics()\n    {\n        var inst = new StashboxContainer()\n            .Register(typeof(IGen1<>), typeof(Gen1<>))\n            .Register(typeof(IGen2<>), typeof(Gen2<>))\n            .Register<ConstraintArgument>()\n            .Resolve<IGen2<IGen1<ConstraintArgument>>>();\n\n        Assert.NotNull(inst.Value);\n        Assert.IsType<Gen1<ConstraintArgument>>(inst.Value);\n\n        Assert.NotNull(inst.Value.Value);\n        Assert.IsType<ConstraintArgument>(inst.Value.Value);\n    }\n\n    [Fact]\n    public void GenericTests_Nested_Generics_Decorator()\n    {\n        var inst = new StashboxContainer()\n            .Register(typeof(IGen3<>), typeof(Gen3<>))\n            .RegisterDecorator(typeof(IGen3<>), typeof(Gen3Decorator<>))\n            .Register<ConstraintArgument>()\n            .Resolve<IGen3<ConstraintArgument>>();\n\n        Assert.NotNull(inst.Value);\n        Assert.IsType<ConstraintArgument>(inst.Value);\n\n        var decorator = (Gen3Decorator<ConstraintArgument>)inst;\n\n        Assert.NotNull(decorator.Decorated);\n        Assert.IsType<Gen3<ConstraintArgument>>(decorator.Decorated);\n    }\n\n    [Fact]\n    public void GenericTests_Nested_Within_Same_Request()\n    {\n        var inst = new StashboxContainer()\n            .Register<Gen>()\n            .Register(typeof(IGen<>), typeof(Gen<>))\n            .Resolve<Gen>();\n\n        Assert.NotNull(inst);\n    }\n\n    [Fact]\n    public void GenericTests_Constraint_Contravariant()\n    {\n        using var container = new StashboxContainer()\n            .Register<IContravariant<IConstraint1>, ConstraintTest4>();\n\n        var service = container.Resolve<IContravariant<ConstraintArgument1>>();\n\n        Assert.IsType<ConstraintTest4>(service);\n    }\n\n    [Fact]\n    public void GenericTests_Constraint_Contravariant_Returns_Original()\n    {\n        using var container = new StashboxContainer()\n            .Register<IContravariant<IConstraint1>, ConstraintTest4>();\n\n        Assert.IsType<ConstraintTest4>(container.Resolve<IContravariant<IConstraint1>>());\n    }\n\n    [Fact]\n    public void GenericTests_Constraint_Contravariant_Collection()\n    {\n        using var container = new StashboxContainer()\n            .Register<IContravariant<IConstraint1>, ConstraintTest4>()\n            .Register<IContravariant<ConstraintArgument1>, ConstraintTest5>();\n\n        var services = container.ResolveAll<IContravariant<ConstraintArgument1>>().ToList();\n\n        Assert.Equal(2, services.Count);\n    }\n\n    [Fact]\n    public void GenericTests_Constraint_Contravariant_Collection_Covariant()\n    {\n        using var container = new StashboxContainer()\n            .Register<IContravariant<IConstraint1>, ConstraintTest4>()\n            .Register<IContravariant<ConstraintArgument1>, ConstraintTest5>();\n\n        var services = container.ResolveAll<IContravariant<IConstraint1>>().ToList();\n\n        Assert.Single(services);\n    }\n\n    [Fact]\n    public void GenericTests_Constraint_Covariant()\n    {\n        using var container = new StashboxContainer()\n            .Register<ICovariant<ConstraintArgument1>, ConstraintTest7>();\n\n        var service = container.Resolve<ICovariant<IConstraint1>>();\n\n        Assert.IsType<ConstraintTest7>(service);\n    }\n\n    [Fact]\n    public void GenericTests_Constraint_Covariant_Returns_Original()\n    {\n        using var container = new StashboxContainer()\n            .Register<ICovariant<ConstraintArgument1>, ConstraintTest7>();\n\n        Assert.IsType<ConstraintTest7>(container.Resolve<ICovariant<ConstraintArgument1>>());\n    }\n\n    [Fact]\n    public void GenericTests_Constraint_Covariant_Collection()\n    {\n        using var container = new StashboxContainer()\n            .Register<ICovariant<IConstraint1>, ConstraintTest6>()\n            .Register<ICovariant<ConstraintArgument1>, ConstraintTest7>();\n\n        var services = container.ResolveAll<ICovariant<IConstraint1>>().ToList();\n\n        Assert.Equal(2, services.Count);\n    }\n\n    [Fact]\n    public void GenericTests_Constraint_Covariant_Collection_Contravariant()\n    {\n        using var container = new StashboxContainer()\n            .Register<ICovariant<IConstraint1>, ConstraintTest6>()\n            .Register<ICovariant<ConstraintArgument1>, ConstraintTest7>();\n\n        var services = container.ResolveAll<ICovariant<ConstraintArgument1>>().ToList();\n\n        Assert.Single(services);\n    }\n\n    [Fact]\n    public void Ensure_Open_Generic_Options_Are_Not_Ignored()\n    {\n        using var container = new StashboxContainer()\n            .Register(typeof(B<>), c => c.WithMetadata(\"A\"))\n            .Register<A>();\n\n        var inst = container.Resolve<A>();\n\n        Assert.NotNull(inst);\n        Assert.Equal(\"A\", inst.Name);\n    }\n\n    class A\n    {\n        public object Name { get; set; }\n\n        public A(Tuple<B<int>, object> b)\n        {\n            this.Name = b.Item2;\n        }\n    }\n\n    class B<T>;\n\n    interface IConstraint;\n\n    interface IConstraint1;\n\n    interface IConstraintTest<T>;\n\n    interface IContravariant<in T>;\n\n    interface ICovariant<out T>;\n\n    class ConstraintTest<T> : IConstraintTest<T>;\n\n    class ConstraintTest2<T> : IConstraintTest<T> where T : IConstraint;\n\n    class ConstraintTest3<T> : IConstraintTest<T> where T : IConstraint1;\n\n    class ConstraintTest4 : IContravariant<IConstraint1>;\n\n    class ConstraintTest5 : IContravariant<ConstraintArgument1>;\n\n    class ConstraintTest6 : ICovariant<IConstraint1>;\n\n    class ConstraintTest7 : ICovariant<ConstraintArgument1>;\n\n    class ConstraintDecorator<T> : IConstraintTest<T> where T : IConstraint\n    {\n        [Dependency]\n        public IConstraintTest<T> ConstraintTest { get; set; }\n    }\n\n    class ConstraintDecorator2<T> : IConstraintTest<T> where T : IConstraint1\n    {\n        [Dependency]\n        public IConstraintTest<T> ConstraintTest { get; set; }\n    }\n\n    class ConstraintArgument;\n\n    class ConstraintArgument1 : IConstraint1;\n\n    class ConstraintTest3\n    {\n        public IConstraintTest<ConstraintArgument> Test { get; set; }\n\n        public ConstraintTest3(IConstraintTest<ConstraintArgument> test)\n        {\n            this.Test = test;\n        }\n    }\n\n    interface ITest1<I, K>\n    {\n        I IProp { get; }\n        K KProp { get; }\n    }\n\n    interface ITest2<I, K>\n    {\n        ITest1<I, K> Test { get; }\n    }\n\n    class Test1<I, K> : ITest1<I, K>\n    {\n        public I IProp { get; }\n        public K KProp { get; }\n    }\n\n    class Test12<I, K> : ITest1<I, K>\n    {\n        public I IProp { get; }\n        public K KProp { get; }\n    }\n\n    class Test2<I, K> : ITest2<I, K>\n    {\n        public ITest1<I, K> Test { get; private set; }\n\n        public Test2(ITest1<I, K> test1, ITest1<I, K> test2)\n        {\n            Test = test1;\n        }\n    }\n\n    interface IGen1<T> { T Value { get; } }\n\n    interface IGen2<T> { T Value { get; } }\n\n    interface IGen3<T> { T Value { get; } }\n\n    class Gen1<T> : IGen1<T>\n    {\n        public Gen1(T value)\n        {\n            this.Value = value;\n        }\n\n        public T Value { get; }\n    }\n\n    class Gen2<T> : IGen2<T>\n    {\n        public Gen2(T value)\n        {\n            this.Value = value;\n        }\n\n        public T Value { get; }\n    }\n\n    class Gen3<T> : IGen3<T>\n    {\n        public Gen3(T value)\n        {\n            this.Value = value;\n        }\n\n        public T Value { get; }\n    }\n\n    class Gen3Decorator<T> : IGen3<T>\n    {\n        public IGen3<T> Decorated { get; }\n\n        public Gen3Decorator(IGen3<T> value)\n        {\n            this.Decorated = value;\n            this.Value = value.Value;\n        }\n\n        public T Value { get; }\n    }\n\n    class Stub;\n    class Stub1;\n\n    interface IGen<T>;\n\n    class Gen<T> : IGen<T>;\n\n    class Gen\n    {\n        public Gen(IGen<Stub> stub, IGen<Stub1> stub1)\n        { }\n    }\n}"
  },
  {
    "path": "test/HierarchyTests.cs",
    "content": "﻿using Xunit;\n\nnamespace Stashbox.Tests;\n\npublic class HierarchyTests\n{\n    [Fact]\n    public void NamedScope_Hierarchy_Respected()\n    {\n        var container = new StashboxContainer(c => c\n                .WithAutoMemberInjection())\n            .Register<ITest, Test>(c => c.DefinesScope(\"root\").WithName(\"root\"))\n            .Register<ITest, Test1>(c => c.InNamedScope(\"root\").DefinesScope(\"A\"))\n            .Register<ITest, Test2>(c => c.InNamedScope(\"root\").DefinesScope(\"B\"))\n            .Register<ITest, Test3>(c => c.InNamedScope(\"A\"))\n            .Register<ITest, Test4>(c => c.InNamedScope(\"A\"))\n            .Register<ITest, Test5>(c => c.InNamedScope(\"B\"))\n            .Register<ITest, Test6>(c => c.InNamedScope(\"B\"));\n\n        var r = container.Resolve<ITest>(\"root\");\n\n        Assert.IsType<Test1>(((Test)r).Subs[0]);\n        Assert.IsType<Test2>(((Test)r).Subs[1]);\n        Assert.IsType<Test3>(((Test1)((Test)r).Subs[0]).Subs[0]);\n        Assert.IsType<Test4>(((Test1)((Test)r).Subs[0]).Subs[1]);\n        Assert.IsType<Test5>(((Test2)((Test)r).Subs[1]).Subs[0]);\n        Assert.IsType<Test6>(((Test2)((Test)r).Subs[1]).Subs[1]);\n    }\n\n    [Fact]\n    public void NamedScope_Hierarchy_Respected_WithoutNames()\n    {\n        var container = new StashboxContainer(c => c\n                .WithAutoMemberInjection())\n            .Register<ITest, Test>(c => c.DefinesScope().WithName(\"root\"))\n            .Register<ITest, Test1>(c => c.InScopeDefinedBy<Test>().DefinesScope())\n            .Register<ITest, Test2>(c => c.InScopeDefinedBy<Test>().DefinesScope())\n            .Register<ITest, Test3>(c => c.InScopeDefinedBy(typeof(Test1)))\n            .Register<ITest, Test4>(c => c.InScopeDefinedBy(typeof(Test1)))\n            .Register<ITest, Test5>(c => c.InScopeDefinedBy<Test2>())\n            .Register<ITest, Test6>(c => c.InScopeDefinedBy<Test2>());\n\n        var r = container.Resolve<ITest>(\"root\");\n\n        Assert.IsType<Test1>(((Test)r).Subs[0]);\n        Assert.IsType<Test2>(((Test)r).Subs[1]);\n        Assert.IsType<Test3>(((Test1)((Test)r).Subs[0]).Subs[0]);\n        Assert.IsType<Test4>(((Test1)((Test)r).Subs[0]).Subs[1]);\n        Assert.IsType<Test5>(((Test2)((Test)r).Subs[1]).Subs[0]);\n        Assert.IsType<Test6>(((Test2)((Test)r).Subs[1]).Subs[1]);\n    }\n\n    [Fact]\n    public void Conditional_Hierarchy_Respected()\n    {\n        var container = new StashboxContainer(c => c\n                .WithAutoMemberInjection())\n            .Register<R>(c => c.WithName(\"root\"))\n            .Register<ITest, Test1>(c => c.WhenDependantIs<R>())\n            .Register<ITest, Test2>(c => c.WhenDependantIs<R>())\n            .Register<ITest, Test3>(c => c.WhenDependantIs(typeof(Test1)))\n            .Register<ITest, Test4>(c => c.WhenDependantIs(typeof(Test1)))\n            .Register<ITest, Test5>(c => c.WhenDependantIs<Test2>())\n            .Register<ITest, Test6>(c => c.WhenDependantIs<Test2>());\n\n        var r = container.Resolve<R>(\"root\");\n\n        Assert.IsType<Test1>(r.Subs[0]);\n        Assert.IsType<Test2>(r.Subs[1]);\n        Assert.IsType<Test3>(((Test1)r.Subs[0]).Subs[0]);\n        Assert.IsType<Test4>(((Test1)r.Subs[0]).Subs[1]);\n        Assert.IsType<Test5>(((Test2)r.Subs[1]).Subs[0]);\n        Assert.IsType<Test6>(((Test2)r.Subs[1]).Subs[1]);\n    }\n\n    interface ITest;\n\n    class R\n    {\n        public ITest[] Subs { get; set; }\n    }\n\n    class Test : ITest\n    {\n        public ITest[] Subs { get; set; }\n    }\n\n    class Test1 : ITest\n    {\n        public ITest[] Subs { get; set; }\n    }\n\n    class Test2 : ITest\n    {\n        public ITest[] Subs { get; set; }\n    }\n\n    class Test3 : ITest;\n\n    class Test4 : ITest;\n\n    class Test5 : ITest;\n\n    class Test6 : ITest;\n}"
  },
  {
    "path": "test/InitializerFinalizerTests.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\nusing Xunit;\n\nnamespace Stashbox.Tests;\n\npublic class InitializerFinalizerTests\n{\n    [Fact]\n    public void InitializerTests_Interface_Method()\n    {\n        ITest test;\n        using (var container = new StashboxContainer())\n        {\n            container.Register<ITest, Test>(context => context.WithInitializer((t, resolver) => t.Method()));\n            test = container.Resolve<ITest>();\n        }\n\n        Assert.True(test.MethodCalled);\n    }\n\n    [Fact]\n    public void InitializerTests_ImplOnly_Method()\n    {\n        ITest test;\n        using (var container = new StashboxContainer())\n        {\n            container.Register<Test1>();\n            container.Register<ITest, Test>(context => context.WithInitializer((t, resolver) => t.ImplMethod(resolver.Resolve<Test1>())));\n            test = container.Resolve<ITest>();\n        }\n\n        Assert.True(test.MethodCalled);\n    }\n\n    [Fact]\n    public void FinalizerTests_Register()\n    {\n        ITest test;\n        using (var container = new StashboxContainer())\n        {\n            container.Register<ITest, Test>(context => context.WithFinalizer(t => t.Method()));\n            test = container.Resolve<ITest>();\n        }\n\n        Assert.True(test.MethodCalled);\n    }\n\n    [Fact]\n    public void FinalizerTests_Register_ByInterface()\n    {\n        ITest test;\n        using (var container = new StashboxContainer())\n        {\n            container.Register<ITest>(typeof(Test), context => context.WithFinalizer(t => t.Method()));\n            test = container.Resolve<ITest>();\n        }\n\n        Assert.True(test.MethodCalled);\n    }\n\n    [Fact]\n    public void FinalizerTests_Register_ByImplementation()\n    {\n        Test test;\n        using (var container = new StashboxContainer())\n        {\n            container.Register<Test>(context => context.WithFinalizer(t => t.Method()));\n            test = container.Resolve<Test>();\n        }\n\n        Assert.True(test.MethodCalled);\n    }\n\n    [Fact]\n    public void FinalizerTests_ReMap()\n    {\n        ITest test;\n        using (var container = new StashboxContainer())\n        {\n            container.Register<ITest, Test>(context => context.WithFinalizer(t => t.Method()));\n            container.ReMap<ITest, Test>(context => context.WithFinalizer(t => t.Method()));\n            test = container.Resolve<ITest>();\n        }\n\n        Assert.True(test.MethodCalled);\n    }\n\n    [Fact]\n    public void FinalizerTests_ReMap_ByInterface()\n    {\n        ITest test;\n        using (var container = new StashboxContainer())\n        {\n            container.Register<ITest>(typeof(Test), context => context.WithFinalizer(t => t.Method()));\n            container.ReMap<ITest>(typeof(Test), context => context.WithFinalizer(t => t.Method()));\n            test = container.Resolve<ITest>();\n        }\n\n        Assert.True(test.MethodCalled);\n    }\n\n    [Fact]\n    public void FinalizerTests_ReMap_ByImplementation()\n    {\n        Test test;\n        using (var container = new StashboxContainer())\n        {\n            container.Register<Test>(context => context.WithFinalizer(t => t.Method()));\n            container.ReMap<Test>(context => context.WithFinalizer(t => t.Method()));\n            test = container.Resolve<Test>();\n        }\n\n        Assert.True(test.MethodCalled);\n    }\n\n    [Fact]\n    public void FinalizerTests_Instance_Interface()\n    {\n        var test = new Test();\n        using (var container = new StashboxContainer())\n        {\n            container.RegisterInstance<ITest>(test, finalizerDelegate: t => t.Method());\n            test = (Test)container.Resolve<ITest>();\n        }\n\n        Assert.True(test.MethodCalled);\n    }\n\n    [Fact]\n    public void FinalizerTests_Instance_Implementation()\n    {\n        var test = new Test();\n        using (var container = new StashboxContainer())\n        {\n            container.RegisterInstance(test, finalizerDelegate: t => t.Method());\n            test = container.Resolve<Test>();\n        }\n\n        Assert.True(test.MethodCalled);\n    }\n\n    [Fact]\n    public void FinalizerTests_WireUp_Interface()\n    {\n        var test = new Test();\n        using (var container = new StashboxContainer())\n        {\n            container.WireUp<ITest>(test, finalizerDelegate: t => t.Method());\n            test = (Test)container.Resolve<ITest>();\n        }\n\n        Assert.True(test.MethodCalled);\n    }\n\n    [Fact]\n    public void FinalizerTests_WireUp_Implementation()\n    {\n        var test = new Test();\n        using (var container = new StashboxContainer())\n        {\n            container.WireUp(test, finalizerDelegate: t => t.Method());\n            test = container.Resolve<Test>();\n        }\n\n        Assert.True(test.MethodCalled);\n    }\n\n    [Fact]\n    public void FinalizerTests_Register_Multiple_Shouldnt_Throw()\n    {\n        using var container = new StashboxContainer();\n        container.Register<ITest, Test>(context => context.WithFinalizer(t => t.Method()));\n        for (var i = 0; i < 10; i++)\n        {\n            var test = container.Resolve<ITest>();\n            Assert.False(test.MethodCalled);\n        }\n    }\n\n    [Fact]\n    public void FinalizerTests_Register_Singleton_Multiple_Shouldnt_Throw()\n    {\n        using var container = new StashboxContainer();\n        container.Register<ITest, Test>(context => context.WithFinalizer(t => t.Method()).WithSingletonLifetime());\n        for (var i = 0; i < 10; i++)\n        {\n            var test = container.Resolve<ITest>();\n            Assert.False(test.MethodCalled);\n        }\n    }\n\n    [Fact]\n    public void FinalizerTests_Register_Scoped_Multiple_Shouldnt_Throw()\n    {\n        using var container = new StashboxContainer();\n        container.Register<ITest, Test>(context => context.WithFinalizer(t => t.Method()).WithScopedLifetime());\n        for (var i = 0; i < 10; i++)\n        {\n            ITest test;\n            using (var scope = container.BeginScope())\n            {\n                test = scope.Resolve<ITest>();\n                Assert.False(test.MethodCalled);\n            }\n\n            Assert.True(test.MethodCalled);\n        }\n    }\n\n    [Fact]\n    public void FinalizerTests_Instance_Implementation_Multiple_Shouldnt_Throw()\n    {\n        var test = new Test();\n        using (var container = new StashboxContainer())\n        {\n            container.RegisterInstance(test, finalizerDelegate: t => t.Method());\n            for (var i = 0; i < 10; i++)\n            {\n                var test1 = container.Resolve<Test>();\n                Assert.False(test1.MethodCalled);\n                Assert.Same(test, test1);\n            }\n        }\n\n        Assert.True(test.MethodCalled);\n    }\n\n    [Fact]\n    public async Task AsyncInitializer_Ensure_Order_Singleton()\n    {\n        using var container = new StashboxContainer()\n            .Register<T1>(c => c.WithAsyncInitializer((t, r, c) => t.InitAsync()).WithSingletonLifetime())\n            .Register<T2>(c => c.WithAsyncInitializer((t, r, c) => t.InitAsync()))\n            .Register<T3>(c => c.WithAsyncInitializer((t, r, c) => t.InitAsync()));\n\n        var initializables = new List<IT>();\n\n        container.Resolve<T3>(dependencyOverrides: [initializables]);\n        await container.InvokeAsyncInitializers();\n\n        Assert.Equal(3, initializables.Count);\n\n        Assert.IsType<T3>(initializables[0]);\n        Assert.IsType<T2>(initializables[1]);\n        Assert.IsType<T1>(initializables[2]);\n    }\n\n    [Fact]\n    public async Task AsyncInitializer_Ensure_Order()\n    {\n        using var container = new StashboxContainer()\n            .Register<T1>(c => c.WithAsyncInitializer((t, r, c) => t.InitAsync()))\n            .Register<T2>(c => c.WithAsyncInitializer((t, r, c) => t.InitAsync()))\n            .Register<T3>(c => c.WithAsyncInitializer((t, r, c) => t.InitAsync()));\n\n        var initializables = new List<IT>();\n\n        container.Resolve<T3>(dependencyOverrides: [initializables]);\n        await container.InvokeAsyncInitializers();\n\n        Assert.Equal(4, initializables.Count);\n\n        Assert.IsType<T3>(initializables[0]);\n        Assert.IsType<T2>(initializables[1]);\n        Assert.IsType<T1>(initializables[2]);\n        Assert.IsType<T1>(initializables[3]);\n    }\n\n    [Fact]\n    public async Task AsyncInitializer_Scoped_Multiple()\n    {\n        using var container = new StashboxContainer()\n            .Register<T1>(c => c.WithAsyncInitializer((t, r, c) => t.InitAsync()).WithScopedLifetime())\n            .Register<T2>(c => c.WithAsyncInitializer((t, r, c) => t.InitAsync()).WithScopedLifetime())\n            .Register<T3>(c => c.WithAsyncInitializer((t, r, c) => t.InitAsync()).WithScopedLifetime());\n\n        var initializables = new List<IT>();\n\n        using var scope = container.BeginScope();\n\n        scope.Resolve<T3>(dependencyOverrides: [initializables]);\n        await scope.InvokeAsyncInitializers();\n\n        Assert.Equal(3, initializables.Count);\n\n        Assert.IsType<T3>(initializables[0]);\n        Assert.IsType<T2>(initializables[1]);\n        Assert.IsType<T1>(initializables[2]);\n\n        scope.Resolve<T3>(dependencyOverrides: [initializables]);\n        await scope.InvokeAsyncInitializers();\n        Assert.Equal(3, initializables.Count);\n    }\n\n    [Fact]\n    public async Task AsyncInitializer_Scoped_Singleton_Multiple()\n    {\n        using var container = new StashboxContainer()\n            .Register<T1>(c => c.WithAsyncInitializer((t, r, c) => t.InitAsync()).WithSingletonLifetime())\n            .Register<T2>(c => c.WithAsyncInitializer((t, r, c) => t.InitAsync()).WithScopedLifetime())\n            .Register<T3>(c => c.WithAsyncInitializer((t, r, c) => t.InitAsync()).WithScopedLifetime());\n\n        var initializables = new List<IT>();\n\n        using var scope1 = container.BeginScope();\n\n        scope1.Resolve<T3>(dependencyOverrides: [initializables]);\n        await scope1.InvokeAsyncInitializers();\n\n        Assert.Equal(3, initializables.Count);\n\n        Assert.IsType<T1>(initializables[0]);\n        Assert.IsType<T3>(initializables[1]);\n        Assert.IsType<T2>(initializables[2]);\n\n        using var scope2 = container.BeginScope();\n\n        scope2.Resolve<T3>(dependencyOverrides: [initializables]);\n        await scope2.InvokeAsyncInitializers();\n\n        Assert.Equal(5, initializables.Count);\n\n        Assert.IsType<T1>(initializables[0]);\n        Assert.IsType<T3>(initializables[1]);\n        Assert.IsType<T2>(initializables[2]);\n        Assert.IsType<T3>(initializables[3]);\n        Assert.IsType<T2>(initializables[4]);\n    }\n\n    [Fact]\n    public void Finalizers_Ensure_Order_Singleton()\n    {\n        var finalizables = new List<IT>();\n        {\n            using var container = new StashboxContainer()\n                .Register<F1>(c => c.WithFinalizer(t => t.Fin()).WithSingletonLifetime())\n                .Register<F2>(c => c.WithFinalizer(t => t.Fin()))\n                .Register<F3>(c => c.WithFinalizer(t => t.Fin()));\n\n\n            container.Resolve<F3>(dependencyOverrides: [finalizables]);\n        }\n\n        Assert.Equal(3, finalizables.Count);\n\n        Assert.IsType<F3>(finalizables[0]);\n        Assert.IsType<F2>(finalizables[1]);\n        Assert.IsType<F1>(finalizables[2]);\n    }\n\n    [Fact]\n    public void Finalizers_Ensure_Order()\n    {\n        var finalizables = new List<IT>();\n        {\n            using var container = new StashboxContainer()\n                .Register<F1>(c => c.WithFinalizer(t => t.Fin()))\n                .Register<F2>(c => c.WithFinalizer(t => t.Fin()))\n                .Register<F3>(c => c.WithFinalizer(t => t.Fin()));\n\n\n            container.Resolve<F3>(dependencyOverrides: [finalizables]);\n        }\n\n        Assert.Equal(4, finalizables.Count);\n\n        Assert.IsType<F3>(finalizables[0]);\n        Assert.IsType<F1>(finalizables[1]);\n        Assert.IsType<F2>(finalizables[2]);\n        Assert.IsType<F1>(finalizables[3]);\n    }\n\n    interface ITest\n    {\n        bool MethodCalled { get; }\n\n        void Method();\n    }\n\n    class Test1;\n\n    class Test : ITest\n    {\n        public void Method()\n        {\n            if (this.MethodCalled)\n                throw new Exception(\"Method called multiple times!\");\n\n            this.MethodCalled = true;\n        }\n\n        public void ImplMethod(Test1 t)\n        {\n            if (t == null)\n                throw new NullReferenceException();\n\n            if (this.MethodCalled)\n                throw new Exception(\"Method called multiple times!\");\n\n            this.MethodCalled = true;\n        }\n\n        public bool MethodCalled { get; private set; }\n    }\n\n    interface IT;\n\n    class T1 : IT\n    {\n        private readonly List<IT> initializables;\n\n        public T1(List<IT> initializables)\n        {\n            this.initializables = initializables;\n        }\n\n        public Task InitAsync()\n        {\n            this.initializables.Add(this);\n            return Task.FromResult(false);\n        }\n    }\n\n    class T2 : IT\n    {\n        private readonly List<IT> initializables;\n        private readonly T1 t1;\n\n        public T2(List<IT> initializables, T1 t1)\n        {\n            this.initializables = initializables;\n            this.t1 = t1;\n        }\n\n        public Task InitAsync()\n        {\n            this.initializables.Add(this);\n            return Task.FromResult(false);\n        }\n    }\n\n    class T3 : IT\n    {\n        private readonly List<IT> initializables;\n        private readonly T1 t1;\n        private readonly T2 t2;\n\n        public T3(List<IT> initializables, T1 t1, T2 t2)\n        {\n            this.initializables = initializables;\n            this.t1 = t1;\n            this.t2 = t2;\n        }\n\n        public Task InitAsync()\n        {\n            this.initializables.Add(this);\n            return Task.FromResult(false);\n        }\n    }\n\n    class F1 : IT\n    {\n        private readonly List<IT> finalizables;\n\n        public F1(List<IT> finalizables)\n        {\n            this.finalizables = finalizables;\n        }\n\n        public void Fin()\n        {\n            this.finalizables.Add(this);\n        }\n    }\n\n    class F2 : IT\n    {\n        private readonly List<IT> finalizables;\n        private readonly F1 f1;\n\n        public F2(List<IT> finalizables, F1 f1)\n        {\n            this.finalizables = finalizables;\n            this.f1 = f1;\n        }\n\n        public void Fin()\n        {\n            this.finalizables.Add(this);\n        }\n    }\n\n    class F3 : IT\n    {\n        private readonly List<IT> finalizables;\n        private readonly F1 f1;\n        private readonly F2 f2;\n\n        public F3(List<IT> finalizables, F2 f2, F1 f1)\n        {\n            this.finalizables = finalizables;\n            this.f1 = f1;\n            this.f2 = f2;\n        }\n\n        public void Fin()\n        {\n            this.finalizables.Add(this);\n        }\n    }\n}"
  },
  {
    "path": "test/InjectionMemberTests.cs",
    "content": "﻿using Stashbox.Attributes;\nusing Stashbox.Exceptions;\nusing System;\nusing System.Collections.Generic;\nusing Xunit;\n\nnamespace Stashbox.Tests;\n\npublic class InjectionMemberTests\n{\n    [Fact]\n    public void InjectionMemberTests_Resolve()\n    {\n        using var container = new StashboxContainer();\n        container.Register<ITest, Test>();\n        container.Register<ITest1, Test1>();\n\n        var inst = container.Resolve<ITest1>();\n\n        Assert.NotNull(inst);\n        Assert.NotNull(inst.Test);\n        Assert.IsType<Test1>(inst);\n        Assert.IsType<Test>(inst.Test);\n\n        Assert.NotNull(((Test1)inst).TestFieldProperty);\n        Assert.IsType<Test>(((Test1)inst).TestFieldProperty);\n    }\n\n    [Fact]\n    public void InjectionMemberTests_Resolve_WithoutRegistered()\n    {\n        using var container = new StashboxContainer();\n        var test1 = new Test1();\n        container.WireUp<ITest1>(test1);\n\n        Assert.Throws<ResolutionFailedException>(() => container.Resolve<ITest1>());\n    }\n\n    [Fact]\n    public void InjectionMemberTests_WireUp()\n    {\n        using var container = new StashboxContainer();\n        container.Register<ITest, Test>();\n\n        var test1 = new Test1();\n        container.WireUp<ITest1>(test1);\n\n        var inst = container.Resolve<ITest1>();\n\n        Assert.NotNull(inst);\n        Assert.NotNull(inst.Test);\n        Assert.IsType<Test1>(inst);\n        Assert.IsType<Test>(inst.Test);\n\n        Assert.NotNull(((Test1)inst).TestFieldProperty);\n        Assert.IsType<Test>(((Test1)inst).TestFieldProperty);\n    }\n\n    [Fact]\n    public void InjectionMemberTests_Resolve_InjectionParameter()\n    {\n        var container = new StashboxContainer();\n        container.Register<ITest2, Test2>(context =>\n            context.WithInjectionParameters(new KeyValuePair<string, object>(\"Name\", \"test\")));\n\n        var inst = container.Resolve<ITest2>();\n\n        Assert.NotNull(inst);\n        Assert.IsType<Test2>(inst);\n        Assert.Equal(\"test\", inst.Name);\n    }\n\n    [Fact]\n    public void InjectionMemberTests_Resolve_InjectionParameter_WithNull()\n    {\n        var container = new StashboxContainer(c => c.WithDefaultValueInjection());\n        container.Register<ITest2, Test2>();\n\n        var inst = container.Resolve<ITest2>();\n\n        Assert.NotNull(inst);\n        Assert.IsType<Test2>(inst);\n        Assert.Null(inst.Name);\n    }\n\n    [Fact]\n    public void InjectionMemberTests_Inject_With_Config()\n    {\n        var container = new StashboxContainer();\n        container.Register<Test3>(context => context.WithDependencyBinding(\"Test1\", \"test1\").WithDependencyBinding(\"test2\", \"test2\"))\n            .Register<ITest, TestM1>(context => context.WithName(\"test1\"))\n            .Register<ITest, TestM2>(context => context.WithName(\"test2\"));\n\n        var inst = container.Resolve<Test3>();\n\n        Assert.NotNull(inst.Test1);\n        Assert.NotNull(inst.Test2);\n        Assert.IsType<TestM1>(inst.Test1);\n        Assert.IsType<TestM2>(inst.Test2);\n    }\n\n    [Fact]\n    public void InjectionMemberTests_Inject_With_Invalid_Config()\n    {\n        var container = new StashboxContainer();\n        container.Register<Test3>(context => context.WithDependencyBinding(\"Test3\"));\n\n        var inst = container.Resolve<Test3>();\n\n        Assert.Null(inst.Test1);\n        Assert.Null(inst.Test2);\n    }\n\n    [Fact]\n    public void InjectionMemberTests_Inject_With_Config_Generic()\n    {\n        var container = new StashboxContainer();\n        container.Register<Test3>(context => context.WithDependencyBinding(x => x.Test1, \"test2\"))\n            .Register<ITest, TestM2>(context => context.WithName(\"test2\"));\n\n        var inst = container.Resolve<Test3>();\n\n        Assert.NotNull(inst.Test1);\n        Assert.Null(inst.Test2);\n        Assert.IsType<TestM2>(inst.Test1);\n    }\n\n    [Fact]\n    public void InjectionMemberTests_Inject_With_Config_Generic_Throws()\n    {\n        using var container = new StashboxContainer();\n        Assert.Throws<ArgumentException>(() => container.Register<Test3>(context => context.WithDependencyBinding(x => 50)));\n    }\n\n    [Fact]\n    public void InjectionMemberTests_Exclude_Globally()\n    {\n        var inst = new StashboxContainer(config =>\n                config.WithUnknownTypeResolution()\n                    .WithAutoMemberInjection(filter: info => info.Name != \"Test4\"))\n            .Activate<Test6>();\n\n        Assert.Null(inst.Test4);\n        Assert.NotNull(inst.Test5);\n    }\n\n    [Fact]\n    public void InjectionMemberTests_Exclude_PerReg()\n    {\n        var inst = new StashboxContainer(config =>\n                config.WithUnknownTypeResolution())\n            .Register<Test6>(config => config.WithAutoMemberInjection(filter: info => info.Name != \"Test4\"))\n            .Resolve<Test6>();\n\n        Assert.Null(inst.Test4);\n        Assert.NotNull(inst.Test5);\n    }\n\n    [Fact]\n    public void InjectionMemberTests_Throws_Field()\n    {\n        using var container = new StashboxContainer()\n            .Register<Test7>();\n\n        Assert.Throws<ResolutionFailedException>(() => container.Resolve<Test7>());\n    }\n    \n#if HAS_REQUIRED\n    [Fact]\n    public void InjectionMemberTests_AutoInject_Required()\n    {\n        using var container = new StashboxContainer()\n            .Register<Test8>()\n            .Register<Test5>()\n            .Register<Test4>();\n\n        var inst = container.Resolve<Test8>();\n        \n        Assert.NotNull(inst.Test4);\n        Assert.NotNull(inst.Test5);\n    }\n    \n    [Fact]\n    public void InjectionMemberTests_AutoInject_Required_Disabled_Global()\n    {\n        using var container = new StashboxContainer(c => c.WithRequiredMemberInjection(false))\n            .Register<Test8>()\n            .Register<Test5>()\n            .Register<Test4>();\n\n        var inst = container.Resolve<Test8>();\n        \n        Assert.Null(inst.Test4);\n        Assert.Null(inst.Test5);\n    }\n    \n    [Fact]\n    public void InjectionMemberTests_AutoInject_Required_Disabled_Reg()\n    {\n        using var container = new StashboxContainer()\n            .Register<Test8>(c => c.WithRequiredMemberInjection(false))\n            .Register<Test5>()\n            .Register<Test4>();\n\n        var inst = container.Resolve<Test8>();\n        \n        Assert.Null(inst.Test4);\n        Assert.Null(inst.Test5);\n    }\n    \n    [Fact]\n    public void InjectionMemberTests_AutoInject_Required_Disabled_Global_Enabled_Reg()\n    {\n        using var container = new StashboxContainer(c => c.WithRequiredMemberInjection(false))\n            .Register<Test8>(c => c.WithRequiredMemberInjection())\n            .Register<Test5>()\n            .Register<Test4>();\n\n        var inst = container.Resolve<Test8>();\n        \n        Assert.NotNull(inst.Test4);\n        Assert.NotNull(inst.Test5);\n    }\n#endif\n\n    interface ITest;\n\n    interface ITest1 { ITest Test { get; } }\n\n    class Test : ITest;\n\n    class TestM1 : ITest;\n\n    class TestM2 : ITest;\n\n    class Test1 : ITest1\n    {\n        [Dependency]\n        private ITest testField = null;\n\n        public ITest TestFieldProperty => this.testField;\n\n        [Dependency]\n        public ITest Test { get; set; }\n    }\n\n    interface ITest2 { string Name { get; set; } }\n\n    class Test2 : ITest2\n    {\n        [Dependency]\n        public string Name { get; set; }\n    }\n\n    class Test3\n    {\n        public ITest Test1 { get; set; }\n\n        private ITest test2 = null;\n\n        public ITest Test2 => this.test2;\n\n        public void Test() { }\n    }\n\n    class Test4;\n\n    class Test5;\n\n    class Test6\n    {\n        public Test4 Test4 { get; set; }\n\n        public Test5 Test5 { get; set; }\n    }\n\n    class Test7\n    {\n        [Dependency]\n#pragma warning disable 169\n        private Test4 test4;\n#pragma warning restore 169\n    }\n#if HAS_REQUIRED\n    class Test8\n    {\n        public required Test4 Test4 { get; init; }\n#pragma warning disable CS0649 // Field is never assigned to, and will always have its default value\n        public required Test5 Test5;\n#pragma warning restore CS0649 // Field is never assigned to, and will always have its default value\n    }    \n#endif\n}"
  },
  {
    "path": "test/InstanceBuilderTests.cs",
    "content": "﻿using Xunit;\n\nnamespace Stashbox.Tests;\n\npublic class InstanceBuilderTests\n{\n    [Fact]\n    public void InstanceBuilderTests_Resolve()\n    {\n        using var container = new StashboxContainer();\n        var dep = new Test();\n        container.RegisterInstance<ITest>(dep);\n        var inst = container.Resolve<ITest>();\n\n        Assert.Same(inst, dep);\n    }\n\n    [Fact]\n    public void InstanceBuilderTests_DependencyResolve()\n    {\n        using var container = new StashboxContainer();\n        var dep = new Test();\n        container.RegisterInstance<ITest>(dep);\n        container.Register<ITest1, Test1>();\n\n        var inst = container.Resolve<ITest1>();\n\n        Assert.Same(inst.Test, dep);\n    }\n\n    [Fact]\n    public void InstanceBuilderTests_Resolve_Fluent()\n    {\n        using var container = new StashboxContainer();\n        var dep = new Test();\n        container.Register<ITest>(context => context.WithInstance(dep));\n        var inst = container.Resolve<ITest>();\n\n        Assert.Same(inst, dep);\n    }\n\n    [Fact]\n    public void InstanceBuilderTests_Resolve_Fluent_ReMap()\n    {\n        using var container = new StashboxContainer();\n        var dep = new Test();\n        var dep1 = new Test();\n        container.Register<ITest>(context => context.WithInstance(dep));\n        container.ReMap<ITest>(context => context.WithInstance(dep1));\n        var inst = container.Resolve<ITest>();\n\n        Assert.Same(inst, dep1);\n    }\n\n    [Fact]\n    public void InstanceBuilderTests_Resolve_Fluent_ReMap_Self()\n    {\n        using var container = new StashboxContainer();\n        var dep = new Test();\n        var dep1 = new Test();\n        container.Register(dep.GetType(), context => context.WithInstance(dep));\n        container.ReMap(dep1.GetType(), context => context.WithInstance(dep1));\n        var inst = container.Resolve<Test>();\n\n        Assert.Same(inst, dep1);\n    }\n\n    [Fact]\n    public void InstanceBuilderTests_DependencyResolve_Fluent()\n    {\n        using var container = new StashboxContainer();\n        var dep = new Test();\n        container.Register<ITest>(context => context.WithInstance(dep));\n        container.Register<ITest1, Test1>();\n\n        var inst = container.Resolve<ITest1>();\n\n        Assert.Same(inst.Test, dep);\n    }\n\n    [Fact]\n    public void InstanceBuilderTests_Multiple()\n    {\n        using var container = new StashboxContainer();\n        var dep = new Test();\n        var dep2 = new Test1(new Test());\n        container.RegisterInstance(dep);\n        container.RegisterInstance(dep2);\n        container.Resolve<Test>();\n        var inst = container.Resolve<Test1>();\n\n        Assert.Same(inst, dep2);\n    }\n\n    interface ITest;\n\n    interface ITest1 { ITest Test { get; } }\n\n    class Test : ITest;\n\n    class Test1 : ITest1\n    {\n        public ITest Test { get; }\n        public Test1(ITest test)\n        {\n            this.Test = test;\n        }\n    }\n}"
  },
  {
    "path": "test/IssueTests/102_Resolving_Func_use_wrong_constructor.cs",
    "content": "﻿using Stashbox.Configuration;\nusing System;\nusing Xunit;\n\nnamespace Stashbox.Tests.IssueTests;\n\npublic class ResolvingFunUseWrongConstructor\n{\n    [Fact]\n    public void Ensure_Good_Constructor_Selected()\n    {\n        var container = new StashboxContainer();\n        container.RegisterAssemblyContaining<ClassA>();\n\n        var funcA = container.Resolve<Func<ClassA, InjectedClass>>();\n        var classA = container.Resolve<ClassA>();\n        var injectedA = funcA(classA);\n\n        var funcB = container.Resolve<Func<ClassB, InjectedClass>>();\n        var classB = container.Resolve<ClassB>();\n        var injectedB = funcB(classB);\n\n        Assert.Equal(classA, injectedA.ClassA);\n        Assert.Equal(classB, injectedB.ClassB);\n    }\n\n    class ClassA;\n\n    class ClassB;\n\n    class InjectedClass\n    {\n        public ClassA ClassA;\n        public ClassB ClassB;\n\n        public InjectedClass(ClassA classA)\n        {\n            ClassA = classA;\n        }\n\n        public InjectedClass(ClassB classB)\n        {\n            ClassB = classB;\n        }\n    }\n\n    [Fact]\n    public void Ensure_Good_Constructor_Selected_Deeper_In_The_Tree()\n    {\n        var container = new StashboxContainer();\n        container.Register<A>().Register<B>().Register<Subject1>().Register<Subject2>();\n\n        var fa = container.Resolve<Func<A, Subject2>>();\n        var a = container.Resolve<A>();\n        var instA = fa(a);\n\n        var fb = container.Resolve<Func<B, Subject2>>();\n        var b = container.Resolve<B>();\n        var instB = fb(b);\n\n        Assert.Equal(a, instA.Subject1.A);\n        Assert.Equal(b, instB.Subject1.B);\n    }\n\n    [Fact]\n    public void Ensure_Constructor_Most_Params_Selector_Respects_Func_Param()\n    {\n        var container = new StashboxContainer();\n        container.Register<A>().Register<B>().Register<Subject3>();\n\n        var fb = container.Resolve<Func<B, Subject3>>();\n        var b = container.Resolve<B>();\n        var instB = fb(b);\n\n        Assert.Equal(b, instB.B);\n        Assert.NotNull(instB.A);\n    }\n\n    [Fact]\n    public void Ensure_Constructor_Least_Params_Selector_Respects_Func_Param()\n    {\n        var container = new StashboxContainer();\n        container.Register<A>().Register<B>().Register<Subject3>(c => c.WithConstructorSelectionRule(Rules.ConstructorSelection.PreferLeastParameters));\n\n        var fb = container.Resolve<Func<B, Subject3>>();\n        var b = container.Resolve<B>();\n        var instB = fb(b);\n\n        Assert.Equal(b, instB.B);\n        Assert.Null(instB.A);\n    }\n\n    class A;\n\n    class B;\n\n    class Subject1\n    {\n        public Subject1(A a)\n        {\n            A = a;\n        }\n\n        public Subject1(B b)\n        {\n            B = b;\n        }\n\n        public A A { get; }\n        public B B { get; }\n    }\n\n    class Subject2\n    {\n        public Subject2(Subject1 subject1)\n        {\n            Subject1 = subject1;\n        }\n\n        public Subject1 Subject1 { get; }\n    }\n\n    class Subject3\n    {\n        public Subject3(A a)\n        {\n            A = a;\n        }\n\n        public Subject3(B b)\n        {\n            B = b;\n        }\n\n        public Subject3(B b, A a)\n        {\n            B = b;\n            A = a;\n        }\n\n        public B B { get; }\n        public A A { get; }\n    }\n}"
  },
  {
    "path": "test/IssueTests/103_Resolving_base_class_dependencies.cs",
    "content": "﻿using Stashbox.Attributes;\nusing Xunit;\n\nnamespace Stashbox.Tests.IssueTests;\n\npublic class A;\npublic class B;\n\npublic class BaseClass\n{\n    [Dependency]\n    public A A { get; set; }\n    public bool DoneA { get; set; }\n\n    [InjectionMethod]\n    public void InjectA()\n    {\n        DoneA = true;\n    }\n}\n\npublic class MainClass : BaseClass\n{\n    [Dependency]\n    public B B { get; set; }\n    public bool DoneB { get; set; }\n\n    [InjectionMethod]\n    public void InjectB()\n    {\n        DoneB = true;\n    }\n}\n\npublic class BaseClassMethod\n{\n    [Fact]\n    public void Test()\n    {\n        var container = new StashboxContainer();\n        container.Register<A>().Register<B>().Register<MainClass>();\n\n        var main = container.Resolve<MainClass>();\n\n        Assert.IsType<B>(main.B);\n        Assert.IsType<A>(main.A);\n\n        Assert.True(main.DoneA);\n        Assert.True(main.DoneB);\n    }\n}"
  },
  {
    "path": "test/IssueTests/105_Question_How_to_work_with_dependency_overrides_from_factory_method.cs",
    "content": "﻿using Stashbox.Exceptions;\nusing Stashbox.Resolution;\nusing Xunit;\n\nnamespace Stashbox.Tests.IssueTests;\n\npublic class QuestionHowTWorkWithDependencyOverridesFromFactoryMethod\n{\n    [Fact]\n    public void Ensure_Context_Available_In_Factory()\n    {\n        var fakeOverride = new object();\n        var dep2Override = new Dep2();\n        using var container = new StashboxContainer()\n            .Register<Test>(c => c.WithFactory<IRequestContext>(ctx =>\n            {\n                var d = ctx.GetDependencyOverrideOrDefault<Dep2>();\n                Assert.Same(dep2Override, d);\n                Assert.Equal([dep2Override, fakeOverride], ctx.GetOverrides());\n                return new Test(d);\n            }))\n            .Register<Dep1>();\n\n        var t = container.Resolve<Test>(dependencyOverrides: [dep2Override, fakeOverride]);\n        Assert.Same(dep2Override, t.Dep);\n    }\n\n    [Fact]\n    public void Returns_Null_When_No_Overrides_Passed()\n    {\n        using var container = new StashboxContainer()\n            .Register<Dep1>(c => c.WithFactory<IRequestContext>(ctx =>\n            {\n                var d = ctx.GetDependencyOverrideOrDefault<Dep2>();\n                Assert.Null(d);\n                Assert.Empty(ctx.GetOverrides());\n                return new Dep1();\n            }));\n\n        container.Resolve<Dep1>();\n    }\n\n    [Fact]\n    public void Ensure_Override_Doesnt_Trigger_Unknown()\n    {\n        var depOverride = new Dep2();\n        using var container = new StashboxContainer(c => c.WithUnknownTypeResolution(ctx =>\n            {\n                ctx.Skip();\n            }))\n            .Register<Test>();\n\n        var t = container.Resolve<Test>(dependencyOverrides: [depOverride]);\n        Assert.Same(depOverride, t.Dep);\n    }\n\n    [Fact]\n    public void Ensure_Skipping_Doesnt_Let_Uknown_Type_Be_Registered()\n    {\n        var depOverride = new Dep2();\n        using var container = new StashboxContainer(c => c.WithUnknownTypeResolution(ctx =>\n            {\n                if (ctx.ServiceType == typeof(IDep))\n                    ctx.Skip();\n            }))\n            .Register<Test>()\n            .Register<Test1>();\n\n        Assert.Throws<ResolutionFailedException>(() => container.Resolve<Test>());\n        Assert.NotNull(container.Resolve<Test1>());\n    }\n\n    class Test\n    {\n        public IDep Dep { get; set; }\n\n        public Test(IDep dep)\n        {\n            this.Dep = dep;\n        }\n    }\n\n    class Test1\n    {\n        public Dep1 Dep { get; set; }\n\n        public Test1(Dep1 dep)\n        {\n            this.Dep = dep;\n        }\n    }\n\n    interface IDep;\n\n    class Dep1 : IDep;\n\n    class Dep2 : IDep;\n}"
  },
  {
    "path": "test/IssueTests/114_Unable_to_resolve_IHubContext.cs",
    "content": "﻿using Xunit;\n\nnamespace Stashbox.Tests.IssueTests;\n\npublic class UnableToResolveIHubContext\n{\n    [Fact]\n    public void Ensure_Resolving_HubContext_Works()\n    {\n        using var container = new StashboxContainer()\n            .Register(typeof(IHubContext<,>), typeof(HubContext<,>))\n            .Register(typeof(HubLifetimeManager<>));\n\n        Assert.NotNull(container.Resolve<IHubContext<TestHub, ITest>>());\n    }\n\n    class Hub;\n\n    class Hub<T> : Hub\n        where T : class;\n\n    interface IHubContext<THub, T>\n        where THub : Hub<T>\n        where T : class;\n\n    class HubLifetimeManager<THub> where THub : Hub;\n\n    class HubContext<THub, T> : IHubContext<THub, T>\n        where THub : Hub<T>\n        where T : class\n    {\n        public HubContext(HubLifetimeManager<THub> lifetimeManager)\n        { }\n    }\n\n    interface ITest;\n\n    class TestHub : Hub<ITest>;\n}"
  },
  {
    "path": "test/IssueTests/116_Different_types_registered_with_the_same_name.cs",
    "content": "﻿using Xunit;\n\nnamespace Stashbox.Tests.IssueTests;\n\npublic class DifferentTypesRegisteredWithTheSameName\n{\n    [Fact]\n    public void Ensure_different_types_with_same_name_doesnt_throw_exception()\n    {\n        var container = new StashboxContainer();\n        container.Register<Foo>(options => options.WithName(Name1).WithSingletonLifetime())\n                 .Register<Bar>(options => options.WithName(Name2).WithSingletonLifetime().WithFactory(resolver => resolver.Resolve<Foo>(Name1).Bar));\n\n        Assert.NotNull(container.Resolve<Foo>(Name1));\n        Assert.NotNull(container.Resolve<Bar>(Name2));\n    }\n\n    [Fact]\n    public void Ensure_name_is_not_unique_between_types()\n    {\n        var container = new StashboxContainer();\n        container.Register<Foo>(options => options.WithName(Name1).WithSingletonLifetime())\n                 .Register<Bar>(options => options.WithName(Name2).WithSingletonLifetime().WithFactory(resolver => resolver.Resolve<Foo>(Name1).Bar));\n\n        Assert.NotNull(container.Resolve<Bar>(Name2));\n    }\n\n    const string Name1 = nameof(Name1);\n    const string Name2 = nameof(Name1);\n\n    sealed class Foo\n    {\n        public Bar Bar { get; }\n\n        public Foo()\n        {\n            this.Bar = new();\n        }\n    }\n\n    sealed class Bar;\n}\n"
  },
  {
    "path": "test/IssueTests/118_Named_resolution_using_ResolveAll_returns_all_named_and_unnamed_instanсes.cs",
    "content": "﻿using System.Collections.Generic;\nusing System.Linq;\nusing Xunit;\n\nnamespace Stashbox.Tests.IssueTests;\n\npublic class NamedResolutioUsingResolveAllReturnsAllNamedAndUnnameInstanсes\n{\n    [Fact]\n    public void Ensure_Named_ResolveAll_Works()\n    {\n        using var container = new StashboxContainer()\n            .Register<ITest, Test1>(\"test1\")\n            .Register<ITest, Test1>(\"test2\")\n            .Register<ITest, Test1>();\n\n        var inst = container.ResolveAll<ITest>(\"test1\").ToArray();\n        var nameLess = container.ResolveAll<ITest>().ToArray();\n\n        Assert.Single(inst);\n        Assert.Equal(3, nameLess.Length);\n    }\n\n    [Fact]\n    public void Ensure_Named_ResolveAll_Works_Injection()\n    {\n        using var container = new StashboxContainer()\n            .Register<ITest, Test1>(\"test1\")\n            .Register<ITest, Test1>(\"test2\")\n            .Register<ITest, Test1>()\n            .Register<Test2>(c => c.WithDependencyBinding<IEnumerable<ITest>>(\"test1\"))\n            .Register<Test2>(\"t2\");\n\n        var inst = container.Resolve<Test2>();\n        var nameLess = container.Resolve<Test2>(\"t2\");\n\n        Assert.Single(inst.Tests);\n        Assert.Equal(3, nameLess.Tests.Count());\n    }\n\n    [Fact]\n    public void Ensure_Named_ResolveAll_Works_Injection_Convention()\n    {\n        using var container = new StashboxContainer(c => c.TreatParameterAndMemberNameAsDependencyName())\n            .Register<ITest, Test1>(\"test1\")\n            .Register<ITest, Test1>(\"test2\")\n            .Register<ITest, Test1>()\n            .Register<Test2>();\n\n        var inst = container.Resolve<Test2>();\n\n        Assert.Single(inst.Tests);\n    }\n\n    interface ITest;\n\n    class Test1 : ITest;\n\n    class Test2\n    {\n        public Test2(IEnumerable<ITest> test1)\n        {\n            this.Tests = test1;\n        }\n\n        public IEnumerable<ITest> Tests { get; }\n    }\n}"
  },
  {
    "path": "test/IssueTests/119_generic_resolution_issue.cs",
    "content": "﻿using System.Linq;\nusing Xunit;\n\nnamespace Stashbox.Tests.IssueTests;\n\npublic class GenericResolutionIssue\n{\n    [Fact]\n    public void Ensure_AsServiceAlso_works()\n    {\n        using var container = new StashboxContainer();\n        container.Register<AT>(c => c.AsServiceAlso<IA<C>>().AsServiceAlso<IA<C, long>>().AsServiceAlso<IB<C>>().AsServiceAlso<IC<C, string>>());\n\n        var inst = container.Resolve<AT>();\n\n        Assert.NotNull(inst);\n\n        var mappings = container.GetRegistrationMappings();\n\n        Assert.Equal(5, mappings.Count());\n    }\n\n    class C;\n\n    class AT : IA<C>, IA<C, long>, IB<C>, IC<C, string>;\n\n    interface IA<T>;\n\n    interface IA<T, R>;\n\n    interface IB<T>;\n\n    interface IC<T, R>;\n\n    class B\n    {\n        public B(IA<C> c)\n        {\n\n        }\n    }\n}"
  },
  {
    "path": "test/IssueTests/129_Sharing_singleton_instances_between_Resolve_and_ResolveAll_and_subtypes.cs",
    "content": "﻿using TestAssembly;\nusing Xunit;\n\nnamespace Stashbox.Tests.IssueTests;\n\npublic class Issue129 \n{\n    [Fact]\n    public void ResolveAllResolvesExistingInstance()\n    {\n        using var container = new StashboxContainer();\n        container.RegisterAssemblyContaining<ITA_T1>(\n            type => typeof(ITA_T1).IsAssignableFrom(type),\n            configurator: opt => opt.WithSingletonLifetime()\n        );\n\n        var all = container.ResolveAll<ITA_T1>();\n        var instance = container.Resolve<TA_T1>();\n\n        Assert.Contains(all, it => it is TA_T1);\n        Assert.Contains(all, it => it == instance);\n    }\n    \n    [Fact]\n    public void ResolveAllResolvesExistingInstance_Ensure_AsImplementedTypes_Doesnt_Replace()\n    {\n        using var container = new StashboxContainer();\n        container.RegisterAssemblyContaining<ITA_T1>(\n            type => typeof(ITA_T1).IsAssignableFrom(type),\n            configurator: opt => opt.WithSingletonLifetime().AsImplementedTypes()\n        );\n\n        var all = container.ResolveAll<ITA_T1>();\n        var instance = container.Resolve<TA_T1>();\n\n        Assert.Contains(all, it => it is TA_T1);\n        Assert.Contains(all, it => it == instance);\n    }\n}"
  },
  {
    "path": "test/IssueTests/132_OpenGenericResolveIssue.cs",
    "content": "﻿using System;\nusing Microsoft.Win32;\nusing Xunit;\n\nnamespace Stashbox.Tests.IssueTests;\n\npublic class OpenGenericResolveIssue \n{\n    [Fact]\n    public void Ensure_Generic_Class_Constraint_Works_With_Interface()\n    {\n        using var container = new StashboxContainer();\n        container.Register(typeof(IA<,>), typeof(A<,>));\n        \n        Assert.NotNull(container.Resolve<IA<Type, IA>>());\n        Assert.NotNull(container.Resolve<IA<Type, B>>());\n        Assert.NotNull(container.Resolve<IA<Type, C>>());\n    }\n    \n    [Fact]\n    public void Ensure_Generic_Struct_Constraint_Works()\n    {\n        using var container = new StashboxContainer();\n        container.Register(typeof(IS<>), typeof(S<>));\n        \n        Assert.NotNull(container.Resolve<IS<D>>());\n    }\n\n    interface IA;\n    \n    class B;\n    \n    abstract class C;\n    \n    interface IA<TK, out TV> where TV : class;\n\n    class A<TK, TV> : IA<TK, TV> where TV : class;\n\n    interface IS<T> where T : struct;\n\n    class S<T> : IS<T> where T:struct;\n    \n    struct D;\n}"
  },
  {
    "path": "test/IssueTests/141_Decorator_and_ResolveAll.cs",
    "content": "﻿using System.Collections.Generic;\nusing System.Linq;\nusing Stashbox.Configuration;\nusing Xunit;\n\nnamespace Stashbox.Tests.IssueTests;\n\npublic class DecoratorAndResolveAll \n{\n    [Fact]\n    public void Ensure_DecoratorAndResolveAll_Works()\n    {\n        var container = new StashboxContainer(c =>\n        {\n            c.WithRegistrationBehavior(Rules.RegistrationBehavior.PreserveDuplications);\n        });\n\n        container.Register<AnimalRepository>(c => c.WithSingletonLifetime().AsImplementedTypes());\n        container.Register<CarRepository>(c => c.WithSingletonLifetime().AsImplementedTypes());\n        container.Register<PhoneRepository>(c => c.WithSingletonLifetime().AsImplementedTypes());\n        container.Register<HouseRepository>(c => c.WithSingletonLifetime().AsImplementedTypes());\n\n\n        container.RegisterDecorator<CachedAnimalRepository>(c => c.AsImplementedTypes());\n        container.RegisterDecorator<CachedCarRepository>(c => c.AsImplementedTypes());\n        container.RegisterDecorator<CachedPhoneRepository>(c => c.AsImplementedTypes());\n\n        container.Register<CollectionOfServices>();\n\n        var services = container.Resolve<CollectionOfServices>().Services.ToArray();\n        \n        Assert.Equal(4, services.Length);\n        Assert.IsType<CachedAnimalRepository>(services[0]);\n        Assert.IsType<AnimalRepository>(((CachedAnimalRepository)services[0]).Service);\n        Assert.IsType<CachedCarRepository>(services[1]);\n        Assert.IsType<CarRepository>(((CachedCarRepository)services[1]).Service);\n        Assert.IsType<CachedPhoneRepository>(services[2]);\n        Assert.IsType<PhoneRepository>(((CachedPhoneRepository)services[2]).Service);\n        Assert.IsType<HouseRepository>(services[3]);\n    }\n    \n    interface IDataRepository\n    {\n        void CommonMethod();\n    }\n    \n    interface IAnimalRepository : IDataRepository;\n\n    interface ICarRepository : IDataRepository;\n\n    interface IPhoneRepository : IDataRepository;\n\n    interface IHouseRepository : IDataRepository;\n\n    sealed class AnimalRepository : IAnimalRepository\n    {\n        public void CommonMethod() {}\n    }\n\n    sealed class CarRepository : ICarRepository\n    {\n        public void CommonMethod() {}\n    }\n\n    sealed class PhoneRepository : IPhoneRepository\n    {\n        public void CommonMethod() {}\n    }\n\n    sealed class HouseRepository : IHouseRepository\n    {\n        public void CommonMethod() {}\n    }\n\n    sealed class CachedAnimalRepository : IAnimalRepository\n    {\n        public IAnimalRepository Service { get; }\n\n        public CachedAnimalRepository(IAnimalRepository service)\n        {\n            Service = service;\n        }\n        \n        public void CommonMethod() {}\n    }\n\n    sealed class CachedCarRepository : ICarRepository\n    {\n        public ICarRepository Service { get; }\n\n        public CachedCarRepository(ICarRepository service)\n        {\n            Service = service;\n        }\n        \n        public void CommonMethod() {}\n    }\n\n    sealed class CachedPhoneRepository : IPhoneRepository\n    {\n        public IPhoneRepository Service { get; }\n\n        public CachedPhoneRepository(IPhoneRepository service)\n        {\n            Service = service;\n        }\n        \n        public void CommonMethod() {}\n    }\n\n    sealed class CollectionOfServices\n    {\n        public IEnumerable<IDataRepository> Services { get; }\n\n        public CollectionOfServices(IEnumerable<IDataRepository> services)\n        {\n            Services = services;\n        }\n    }\n}"
  },
  {
    "path": "test/IssueTests/144_Generic_decorators_broken.cs",
    "content": "﻿using Xunit;\n\nnamespace Stashbox.Tests.IssueTests;\n\npublic class GenericDecoratorsBroken \n{\n    [Fact]\n    public void Ensure_GenericDecorators_Working()\n    {\n        using var container = new StashboxContainer();\n        container.RegisterSingleton(typeof(ICommand<Context>), typeof(Command<Context>));\n        container.RegisterDecorator(typeof(ICommand<Context>), typeof(Decorator<Context>));\n\n        var decorator = container.Resolve<ICommand<Context>>();\n        \n        Assert.IsType<Decorator<Context>>(decorator);\n        Assert.IsType<Command<Context>>(((Decorator<Context>)decorator).Dep);\n    }\n    \n    [Fact]\n    public void Ensure_GenericDecorators_Working_Open()\n    {\n        using var container = new StashboxContainer();\n        container.RegisterSingleton(typeof(ICommand<Context>), typeof(Command<Context>));\n        container.RegisterDecorator(typeof(ICommand<>), typeof(Decorator<>));\n\n        var decorator = container.Resolve<ICommand<Context>>();\n        \n        Assert.IsType<Decorator<Context>>(decorator);\n        Assert.IsType<Command<Context>>(((Decorator<Context>)decorator).Dep);\n    }\n\n    interface ICommand<T>;\n    \n    class Command <T> : ICommand<T>;\n\n    class Decorator<T> : ICommand<T>\n    {\n        public ICommand<T> Dep { get; }\n\n        public Decorator(ICommand<T> dep)\n        {\n            Dep = dep;\n        }\n    }\n    \n    class Context;\n}"
  },
  {
    "path": "test/IssueTests/163_Last_write_win_problem_when_hash_collision_happens.cs",
    "content": "﻿using Stashbox.Tests.Utils;\nusing Xunit;\n\nnamespace Stashbox.Tests.IssueTests;\n\npublic class LastWriteWinProblemWhenHashCollisionHappens \n{\n    [Fact]\n    public void Ensure_Collision_Doesnt_Happen()\n    {\n        var (type1, type2) = TypeGen.GetCollidingTypes();\n        \n        var services = new StashboxContainer();\n        services.Register(type1);\n        services.Register(type2);\n        \n        Assert.NotNull(services.Resolve(type2));\n        Assert.NotNull(services.Resolve(type1));\n    }\n}"
  },
  {
    "path": "test/IssueTests/16_Extensions_Identity_OptionsMonitor.cs",
    "content": "﻿using System.Collections.Generic;\nusing Xunit;\n\nnamespace Stashbox.Tests.IssueTests;\n\npublic class ExtensionsIdentityOptionsMonitor \n{\n    [Fact]\n    public void ExtensionsIdentityOptionsMonitor_WithoutVariance()\n    {\n        using var container = new StashboxContainer(c => c.WithVariantGenericTypes(false));\n        container.Register<IOp<A>, Op<A>>();\n        container.Register<IOp<B>, Op<B>>();\n\n        Assert.Single(container.Resolve<IEnumerable<IOp<B>>>());\n    }\n\n    private interface IOp<in T>;\n\n    private class Op<T> : IOp<T>;\n\n    private class A;\n\n    private class B : A;\n}"
  },
  {
    "path": "test/IssueTests/213_Bug_Resolving_Lazy_Func.cs",
    "content": "﻿using System;\nusing Stashbox.Exceptions;\nusing Xunit;\n\nnamespace Stashbox.Tests.IssueTests;\n\npublic class BugResolvingLazyFunc\n{\n    [Fact]\n    public void ResolvingLazyWrapper_ShouldNotInstantiateService_Singleton()\n    {\n        using var container = new StashboxContainer();\n        container.RegisterSingleton<Service>();\n\n        var lazy = container.Resolve<Lazy<Service>>();\n        Assert.Throws<InvalidOperationException>(() => lazy.Value);\n    }\n    \n    [Fact]\n    public void ResolvingFuncWrapper_ShouldNotInstantiateService_Singleton()\n    {\n        using var container = new StashboxContainer();\n        container.RegisterSingleton<Service>();\n\n        var func = container.Resolve<Func<Service>>();\n        Assert.Throws<InvalidOperationException>(() => func());\n    }\n    \n    [Fact]\n    public void ResolvingLazyWrapper_ShouldNotInstantiateService_Scoped()\n    {\n        using var container = new StashboxContainer();\n        container.RegisterScoped<Service>();\n\n        var lazy = container.Resolve<Lazy<Service>>();\n        Assert.Throws<InvalidOperationException>(() => lazy.Value);\n        \n        var scope = container.BeginScope();\n        \n        lazy = scope.Resolve<Lazy<Service>>();\n        Assert.Throws<InvalidOperationException>(() => lazy.Value);\n    }\n    \n    [Fact]\n    public void ResolvingFuncWrapper_ShouldNotInstantiateService_Scoped()\n    {\n        using var container = new StashboxContainer();\n        container.RegisterScoped<Service>();\n\n        var func = container.Resolve<Func<Service>>();\n        Assert.Throws<InvalidOperationException>(() => func());\n        \n        var scope = container.BeginScope();\n        \n        func = scope.Resolve<Func<Service>>();\n        Assert.Throws<InvalidOperationException>(() => func());\n    }\n\n    private class Service\n    {\n        public Service()\n        {\n            throw new InvalidOperationException(\"Don't instantiate me yet!\");\n        }\n    }\n}"
  },
  {
    "path": "test/IssueTests/228_Stashbox_does_not_handle_Optional_correctly.cs",
    "content": "﻿#nullable enable\n\nusing System.Runtime.InteropServices;\nusing Xunit;\n\nnamespace Stashbox.Tests.IssueTests;\n\npublic class StashboxDoesNotHandleOptionalCorrectly \n{\n    [Fact]\n    public void Optional_Works()\n    {\n        using var container = new StashboxContainer();\n        container.Register<B>();\n        container.Register<C>();\n        container.Register<D>();\n\n        Assert.NotNull(container.Resolve<B>());\n        Assert.NotNull(container.Resolve<C>());\n        Assert.NotNull(container.Resolve<D>());\n    }\n    \n    [Fact]\n    public void Optional_Works_Unknown()\n    {\n        using var container = new StashboxContainer(c => c.WithUnknownTypeResolution());\n        container.Register<E>();\n\n        Assert.NotNull(container.Resolve<E>());\n    }\n    \n    private class A { }\n    \n    private class B([Optional] A? a) { }\n    \n    private class C([Optional] int? a) { }\n    \n    private class D([Optional] string? a) { }\n    \n    private class E([Optional] A a) { }\n}"
  },
  {
    "path": "test/IssueTests/33_ScopedLifetime_thread_safety.cs",
    "content": "﻿using System.Threading;\nusing System.Threading.Tasks;\nusing Xunit;\n\nnamespace Stashbox.Tests.IssueTests;\n\npublic class ScopedLifetimeThreadSafeTests\n{\n    [Fact]\n    public void ScopedLifetime_thread_safety()\n    {\n        using IStashboxContainer container = new StashboxContainer();\n        container.RegisterScoped<Test>();\n        for (var i = 0; i < 1000; i++)\n        {\n            using var scope = container.BeginScope();\n            Parallel.For(0, 50, _ =>\n            {\n                var inst = scope.Resolve<Test>();\n                Assert.Same(inst, scope.Resolve<Test>());\n            });\n        }\n    }\n\n    [Fact]\n    public void ScopedLifetime_thread_safety_count()\n    {\n        using IStashboxContainer container = new StashboxContainer();\n        container.RegisterScoped<TestC>();\n        for (var i = 0; i < 1000; i++)\n        {\n            using var scope = container.BeginScope();\n            Parallel.For(0, 50, _ =>\n            {\n                scope.Resolve<TestC>();\n            });\n        }\n\n        Assert.Equal(1000, TestC.Counter);\n    }\n\n    [Fact]\n    public void ScopedLifetime_thread_safety_generic()\n    {\n        using IStashboxContainer container = new StashboxContainer();\n        container.Register(typeof(TestG<>), c => c.WithScopedLifetime());\n        for (var i = 0; i < 1000; i++)\n        {\n            using var scope = container.BeginScope();\n            Parallel.For(0, 50, _ =>\n            {\n                var inst = scope.Resolve<TestG<int>>();\n                Assert.Same(inst, scope.Resolve<TestG<int>>());\n            });\n        }\n    }\n\n    class Test;\n\n    class TestG<T>;\n\n    class TestC\n    {\n        public static int Counter = 0;\n\n        public TestC()\n        {\n            Interlocked.Increment(ref Counter);\n        }\n    }\n}"
  },
  {
    "path": "test/IssueTests/34_Resolution_from_parent_container.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing Xunit;\n\nnamespace Stashbox.Tests.IssueTests;\n\npublic class ResolutionFromParentContainerTests\n{\n    [Fact]\n    public void ContainerTests_ChildContainer_Resolve_Dependency_From_Child()\n    {\n        var container = new StashboxContainer();\n        container.Register<ITest3, Test3>();\n\n        var child = container.CreateChildContainer();\n        child.Register<ITest1, Test1>();\n        child.Register<ITest2, Test2>();\n\n        var test3 = child.Resolve<ITest3>();\n\n        Assert.NotNull(test3);\n        Assert.IsType<Test3>(test3);\n        Assert.Same(container.ContainerContext, child.ContainerContext.ParentContext);\n    }\n\n    [Fact]\n    public void ContainerTests_ChildContainer_Resolve_Dependency_Across_Childs()\n    {\n        var container = new StashboxContainer();\n        container.Register<ITest3, Test3>();\n\n        var child = container.CreateChildContainer().CreateChildContainer();\n        child.Register<ITest1, Test1>();\n        child.Register<ITest2, Test2>();\n\n        var test3 = child.Resolve<ITest3>();\n\n        Assert.NotNull(test3);\n    }\n\n    [Fact]\n    public void ContainerTests_ChildContainer_Resolve_Dependency_Across_Childs_2()\n    {\n        var container = new StashboxContainer();\n        container.Register<ITest3, Test3>();\n\n        var child = container.CreateChildContainer();\n        child.Register<ITest1, Test1>();\n\n        var child2 = child.CreateChildContainer();\n        child2.Register<ITest2, Test2>();\n\n        var test3 = child2.Resolve<ITest3>();\n\n        Assert.NotNull(test3);\n    }\n\n    [Fact]\n    public void ContainerTests_ChildContainer_Resolve_Dependency_Across_Childs_3()\n    {\n        var container = new StashboxContainer();\n        container.Register<ITest3, Test3>();\n\n        var child = container.CreateChildContainer();\n        child.Register<ITest2, Test2>();\n\n        var child2 = child.CreateChildContainer();\n        child2.Register<ITest1, Test1>();\n\n        var test3 = child2.Resolve<ITest3>();\n\n        Assert.NotNull(test3);\n    }\n\n    [Fact]\n    public void ContainerTests_ChildContainer_Resolve_Dependency_Across_Childs_Wrapper()\n    {\n        var container = new StashboxContainer();\n        container.Register<ITest5, Test5>();\n\n        var child = container.CreateChildContainer();\n        child.Register<ITest2, Test2>(c => c.WithMetadata(new object()));\n\n        var child2 = child.CreateChildContainer();\n        child2.Register<ITest3, Test3>();\n\n        var child3 = child2.CreateChildContainer();\n        child3.Register<ITest1, Test1>();\n\n        var test3 = child3.Resolve<ITest5>();\n\n        Assert.NotNull(test3);\n        Assert.NotNull(test3.Func());\n        Assert.NotNull(test3.Lazy.Value);\n        Assert.NotNull(test3.Enumerable);\n        Assert.Single(test3.Enumerable);\n        Assert.NotNull(test3.Tuple.Item1);\n    }\n\n    interface ITest1;\n\n    interface ITest2;\n\n    interface ITest3;\n\n    interface ITest5\n    {\n        Func<ITest2> Func { get; }\n        Lazy<ITest2> Lazy { get; }\n        IEnumerable<ITest3> Enumerable { get; }\n        Tuple<ITest2, object> Tuple { get; }\n    }\n\n    class Test1 : ITest1;\n\n    class Test2 : ITest2\n    {\n        public Test2(ITest1 test1)\n        { }\n    }\n\n    class Test3 : ITest3\n    {\n        public Test3(ITest1 test1, ITest2 test2)\n        { }\n    }\n\n    class Test5 : ITest5\n    {\n        public Test5(Func<ITest2> func, Lazy<ITest2> lazy, IEnumerable<ITest3> enumerable, Tuple<ITest2, object> tuple)\n        {\n            Func = func;\n            Lazy = lazy;\n            Enumerable = enumerable;\n            Tuple = tuple;\n        }\n\n        public Func<ITest2> Func { get; }\n        public Lazy<ITest2> Lazy { get; }\n        public IEnumerable<ITest3> Enumerable { get; }\n        public Tuple<ITest2, object> Tuple { get; }\n    }\n\n}"
  },
  {
    "path": "test/IssueTests/35_Mixture_of_named_and_non_named_registrations_result_in_the_wrong_type_resolved.cs",
    "content": "﻿using Xunit;\n\nnamespace Stashbox.Tests.IssueTests;\n\npublic class MixtureOfNamedAndNonNamedRegistrationTests\n{\n    [Fact]\n    public void Mixture_of_named_and_non_named_registrations_result_in_the_wrong_type_resolved()\n    {\n        var sb = new StashboxContainer();\n\n        sb.RegisterSingleton(typeof(ITest), typeof(Test));\n        sb.RegisterSingleton(typeof(ITest), typeof(Test1), \"Test2\");\n        sb.RegisterSingleton(typeof(ITest), typeof(Test2), \"Test3\");\n        var test = sb.Resolve<ITest>();\n\n        Assert.NotNull(test);\n        Assert.IsType<Test>(test);\n    }\n\n    interface ITest;\n\n    class Test : ITest;\n\n    class Test1 : ITest;\n\n    class Test2 : ITest;\n}"
  },
  {
    "path": "test/IssueTests/37_Resolver_factory_invoke_doesnt_pass_different_parameters_given_when_theyre_the_same_type.cs",
    "content": "﻿using System;\nusing Xunit;\n\nnamespace Stashbox.Tests.IssueTests;\n\npublic class ResolverFactoryIssue\n{\n    [Fact]\n    public void Resolver_factory_invoke_doesnt_pass_different_parameters_given_when_theyre_the_same_type()\n    {\n        var factory = new StashboxContainer()\n            .Register<IFoo, Foobar>()\n            .ResolveFactory(typeof(IFoo), parameterTypes: [typeof(string), typeof(string)]);\n\n        Assert.Equal(\"foobar\", ((IFoo)factory.DynamicInvoke(\"foo\", \"bar\")).Result);\n    }\n\n    [Fact]\n    public void Resolver_factory_invoke_doesnt_pass_different_parameters_given_when_theyre_the_same_type_func()\n    {\n        var factory = new StashboxContainer()\n            .Register<IFoo, Foobar>()\n            .Resolve<Func<string, string, IFoo>>();\n\n        Assert.Equal(\"foobar\", factory(\"foo\", \"bar\").Result);\n    }\n\n    interface IFoo\n    {\n        string Result { get; set; }\n    }\n\n    class Foobar : IFoo\n    {\n        public Foobar(string x, string y)\n        {\n            this.Result = x + y;\n        }\n\n        public string Result { get; set; }\n    }\n}"
  },
  {
    "path": "test/IssueTests/38_Injecting_container_itself.cs",
    "content": "﻿using Xunit;\n\nnamespace Stashbox.Tests.IssueTests;\n\npublic class InjectingContainerItself\n{\n    [Fact]\n    public void Injecting_container_itself()\n    {\n        var container = new StashboxContainer();\n        var factory = container.RegisterInstance(container)\n            .RegisterSingleton<ICoreFactory, CoreFactory>()\n            .Resolve<ICoreFactory>();\n\n        Assert.NotNull(factory);\n    }\n\n    [Fact]\n    public void Injecting_container_itself2()\n    {\n        var factory = new StashboxContainer()\n            .RegisterSingleton<ICoreFactory, CoreFactory2>()\n            .Resolve<ICoreFactory>();\n\n        Assert.NotNull(factory);\n    }\n}\n\ninterface ICoreFactory\n{\n    IEngine GetEngine();\n    ILogManager GetLogManager();\n}\n\ninterface IEngine;\n\ninterface ILogManager;\n\nclass CoreFactory : ICoreFactory\n{\n    private readonly StashboxContainer _container;\n\n    public CoreFactory(StashboxContainer container)\n    {\n        _container = container;\n    }\n\n    public IEngine GetEngine()\n    {\n        return _container.Resolve<IEngine>();\n    }\n\n    public ILogManager GetLogManager()\n    {\n        return _container.Resolve<ILogManager>();\n    }\n}\n\nclass CoreFactory2 : ICoreFactory\n{\n    private readonly IDependencyResolver _container;\n\n    public CoreFactory2(IDependencyResolver container)\n    {\n        _container = container;\n    }\n\n    public IEngine GetEngine()\n    {\n        return _container.Resolve<IEngine>();\n    }\n\n    public ILogManager GetLogManager()\n    {\n        return _container.Resolve<ILogManager>();\n    }\n}"
  },
  {
    "path": "test/IssueTests/42_Circular_dependency_tracking_doesnt_work_with_factory_resolution.cs",
    "content": "﻿using Stashbox.Exceptions;\nusing Xunit;\n\nnamespace Stashbox.Tests.IssueTests;\n\npublic class CircularDependencyTrackingDoesntWorkWithFactoryResolution\n{\n    [Fact]\n    public void Circular_dependency_tracking_doesnt_work_with_factory_resolution()\n    {\n        var container = new StashboxContainer();\n        container.Register<IFoo, Foo>(registrator => registrator.WithFactory<IFoo>(f => new Foo(f)));\n        Assert.Throws<ResolutionFailedException>(container.Resolve<IFoo>);\n    }\n\n    interface IFoo;\n\n    class Foo : IFoo\n    {\n        public Foo(IFoo foo)\n        { }\n    }\n}"
  },
  {
    "path": "test/IssueTests/43_Issue_with_Member_Injection_with_Attribute_but_private_setter.cs",
    "content": "﻿using Stashbox.Configuration;\nusing Xunit;\n\nnamespace Stashbox.Tests.IssueTests;\n\npublic class IssueWithMemberInjectionwithAttributeButPrivateSetter\n{\n    [Fact]\n    public void Issue_with_Member_Injection_with_Attribute_but_private_setter_private_property()\n    {\n        using var container = new StashboxContainer(config => config.WithUnknownTypeResolution());\n        var test = container.Register<Test2>(config => config.WithAutoMemberInjection(Rules.AutoMemberInjectionRules.PropertiesWithLimitedAccess))\n            .Resolve<Test2>();\n\n        Assert.True(test.Test1Prop2 != null, \"test.Test1Prop2 != null\");\n        Assert.True(test.Test1Prop != null, \"test.Test1Prop != null\");\n    }\n\n    [Fact]\n    public void Issue_with_Member_Injection_with_Attribute_but_private_setter_private_field()\n    {\n        using var container = new StashboxContainer(config => config.WithUnknownTypeResolution());\n        var test = container.Register<Test4>(config => config.WithAutoMemberInjection(Rules.AutoMemberInjectionRules.PrivateFields))\n            .Resolve<Test4>();\n\n        Assert.True(test.Test1Prop2 != null, \"test.Test1Prop2 != null\");\n        Assert.True(test.Test1Prop != null, \"test.Test1Prop != null\");\n    }\n\n    [Fact]\n    public void Issue_with_Member_Injection_with_Attribute_but_private_setter_public_property()\n    {\n        using var container = new StashboxContainer(config => config.WithUnknownTypeResolution());\n        var test = container.Register<Test6>(config => config.WithAutoMemberInjection())\n            .Resolve<Test6>();\n\n        Assert.True(test.Test1Prop2 != null, \"test.Test1Prop2 != null\");\n        Assert.True(test.Test1Prop != null, \"test.Test1Prop != null\");\n    }\n\n    class Test;\n\n    class Test1\n    {\n        public Test Test1Prop { get; private set; }\n    }\n\n    class Test2 : Test1\n    {\n        public Test Test1Prop2 { get; private set; }\n    }\n\n    class Test3\n    {\n        private Test test1 = null;\n\n        public Test Test1Prop => this.test1;\n    }\n\n    class Test4 : Test3\n    {\n        private Test test1 = null;\n\n        public Test Test1Prop2 => this.test1;\n    }\n\n    class Test5\n    {\n        public Test Test1Prop { get; set; }\n    }\n\n    class Test6 : Test5\n    {\n        public Test Test1Prop2 { get; set; }\n    }\n}"
  },
  {
    "path": "test/IssueTests/44_Lifetime_Issues.cs",
    "content": "﻿using Stashbox.Registration.Fluent;\nusing System;\nusing System.Linq;\nusing Xunit;\n\nnamespace Stashbox.Tests.IssueTests;\n\npublic class LifetimeIssues\n{\n    class DoResolveAttribute : Attribute;\n    interface ITier1;\n    class Tier1 : ITier1 {[DoResolve] public ITier2 Inner { get; set; }[DoResolve] public TierBase OtherInner { get; set; } }\n    interface ITier2;\n    class Tier2 : ITier2 { public Tier2(string name) { Name = name; } public string Name { get; set; } }\n    abstract class TierBase { public int Id { get; protected set; } }\n    class Tier3 : TierBase { public Tier3(int id) { Id = id; }[DoResolve] public ITier2 Inner { get; set; } }\n\n    public abstract class PrivateArgs\n    {\n        public object[] ArgList { get; protected set; }\n        public abstract Type Target { get; }\n    }\n    public class PrivateArgs<T> : PrivateArgs\n    {\n        static readonly Type _Target = typeof(T);\n\n        public PrivateArgs(params object[] args) : base()\n        {\n            ArgList = args;\n        }\n\n        public static PrivateArgs<T> Get(params object[] args)\n        {\n            var res = new PrivateArgs<T>\n            {\n                ArgList = args\n            };\n            return res;\n        }\n\n        public override Type Target { get; } = _Target;\n    }\n\n    [Fact]\n    public void ContextEstablishedInChildContainersCanBeAccessedWhenUsingAParentScopeConstruction()\n    {\n        StashboxContainer sb1 = CreateContainer(c => c.WithSingletonLifetime());\n        StashboxContainer sb2 = CreateContainer(c => c.WithSingletonLifetime());\n\n        // This works\n        sb1.PutInstanceInScope(typeof(PrivateArgs<ITier2>), PrivateArgs<ITier2>.Get(\"Bob\"));\n        sb1.PutInstanceInScope(typeof(PrivateArgs<TierBase>), PrivateArgs<TierBase>.Get(5));\n        ITier1 renderer = (ITier1)sb1.Resolve(typeof(ITier1));\n\n        Assert.NotNull(renderer);\n\n        using var scope = sb2.BeginScope();\n        scope.PutInstanceInScope(typeof(PrivateArgs<ITier2>), PrivateArgs<ITier2>.Get(\"Bob\"));\n        scope.PutInstanceInScope(typeof(PrivateArgs<TierBase>), PrivateArgs<TierBase>.Get(5));\n        ITier1 renderer2 = (ITier1)scope.Resolve(typeof(ITier1));\n\n        Assert.NotNull(renderer2);\n    }\n\n    [Fact]\n    public void ContextEstablishedInChildContainersCanBeAccessedWhenUsingAParentScopeConstructionWithChildContainer()\n    {\n        StashboxContainer sb1 = CreateContainer(c => c.WithScopedLifetime());\n        StashboxContainer sb2 = CreateContainer(c => c.WithScopedLifetime());\n\n        // This works\n        using var scope1 = sb1.BeginScope();\n        scope1.PutInstanceInScope(typeof(PrivateArgs<ITier2>), PrivateArgs<ITier2>.Get(\"Bob\"));\n        scope1.PutInstanceInScope(typeof(PrivateArgs<TierBase>), PrivateArgs<TierBase>.Get(5));\n        ITier1 renderer = (ITier1)scope1.Resolve(typeof(ITier1));\n\n        Assert.NotNull(renderer);\n\n        // This fails\n        using var sbc = sb2.CreateChildContainer();\n        using var scope2 = sbc.BeginScope();\n        scope2.PutInstanceInScope(typeof(PrivateArgs<ITier2>), PrivateArgs<ITier2>.Get(\"Bob\"));\n        scope2.PutInstanceInScope(typeof(PrivateArgs<TierBase>), PrivateArgs<TierBase>.Get(5));\n        ITier1 renderer2 = (ITier1)scope2.Resolve(typeof(ITier1));\n\n        Assert.NotNull(renderer2);\n    }\n\n    private static StashboxContainer CreateContainer(Action<RegistrationConfigurator> scopeConfig = null)\n    {\n        var sb = new StashboxContainer(\n            config => config\n                .WithUnknownTypeResolution(ctx => ctx.WhenHas<DoResolveAttribute>())\n                .WithAutoMemberInjection(\n                    Stashbox.Configuration.Rules.AutoMemberInjectionRules.PropertiesWithPublicSetter,\n                    ti => ti.CustomAttributes.Any(a => a.GetType() == typeof(DoResolveAttribute))\n                )\n        );\n\n        var allTypes = new[]\n        {\n            new Tuple<Type, Type>(typeof(ITier1), typeof(Tier1)),\n            new Tuple<Type, Type>(typeof(ITier2), typeof(Tier2)),\n            new Tuple<Type, Type>(typeof(TierBase), typeof(Tier3)),\n        }.ToList();\n\n        foreach (var type in allTypes)\n        {\n            var tbuilt = type.Item2;\n            var tinterface = type.Item1;\n\n\n            var targs = typeof(PrivateArgs<>).MakeGenericType(tinterface);\n            sb.Register(tinterface, tbuilt,\n                c =>\n                    c\n                        .WithFactory(d =>\n                        {\n                            PrivateArgs argContainer = d.Resolve(targs) as PrivateArgs;\n                            object[] args = argContainer?.ArgList;\n                            object res = null;\n                            try { res = Activator.CreateInstance(tbuilt, args ?? new object[0]); }\n                            catch { }\n\n                            return res;\n                        })\n                        .WithAutoMemberInjection(\n                            Stashbox.Configuration.Rules.AutoMemberInjectionRules.PropertiesWithPublicSetter,\n                            ti => ti.CustomAttributes.Any(a => a.GetType() == typeof(DoResolveAttribute)))\n                        // Simple extension method allowing conditional configuration inline\n                        .ApplyIf(scopeConfig != null, scopeConfig)\n            );\n        }\n\n        return sb;\n    }\n}\n\npublic static class RegExt\n{\n    public static void ApplyIf(this RegistrationConfigurator configurator, bool b, Action<RegistrationConfigurator> scopeConfig)\n    {\n        if (b)\n            scopeConfig.Invoke(configurator);\n    }\n}"
  },
  {
    "path": "test/IssueTests/46_AspNetCore_Failing_spec_tests_forconstrained_generics.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing Xunit;\n\nnamespace Stashbox.Tests.IssueTests;\n\npublic class AspNetCoreFailingSpecTestsForConstrainedGenerics\n{\n    [Fact]\n    public void PublicNoArgCtorConstrainedOpenGenericServicesCanBeResolved()\n    {\n        var container = new StashboxContainer();\n        container.Register(typeof(IFakeOpenGenericService<>), typeof(ClassWithNoConstraints<>))\n            .Register(typeof(IFakeOpenGenericService<>), typeof(ClassWithNewConstraint<>));\n\n        var allServices = container.ResolveAll<IFakeOpenGenericService<PocoClass>>().ToList();\n        var constrainedServices = container.ResolveAll<IFakeOpenGenericService<ClassWithPrivateCtor>>().ToList();\n\n        Assert.Equal(2, allServices.Count);\n        Assert.Single(constrainedServices);\n    }\n\n    [Fact]\n    public void SelfReferencingConstrainedOpenGenericServicesCanBeResolved()\n    {\n        var container = new StashboxContainer();\n        var poco = new PocoClass();\n        var comparable = new ClassImplementingIComparable();\n        container.Register(typeof(IFakeOpenGenericService<>), typeof(FakeOpenGenericService<>))\n            .Register(typeof(IFakeOpenGenericService<>), typeof(ClassWithSelfReferencingConstraint<>))\n            .RegisterInstance(poco)\n            .RegisterInstance(comparable);\n\n        var allServices = container.ResolveAll<IFakeOpenGenericService<ClassImplementingIComparable>>().ToList();\n        var constrainedServices = container.ResolveAll<IFakeOpenGenericService<PocoClass>>().ToList();\n\n        Assert.Equal(2, allServices.Count);\n        Assert.Same(comparable, allServices[0].Value);\n        Assert.Same(comparable, allServices[1].Value);\n        Assert.Single(constrainedServices);\n        Assert.Same(poco, constrainedServices[0].Value);\n    }\n\n    [Fact]\n    public void ClassConstrainedOpenGenericServicesCanBeResolved()\n    {\n        var container = new StashboxContainer();\n        container.Register(typeof(IFakeOpenGenericService<>), typeof(ClassWithNoConstraints<>))\n            .Register(typeof(IFakeOpenGenericService<>), typeof(ClassWithClassConstraint<>));\n\n        var allServices = container.ResolveAll<IFakeOpenGenericService<PocoClass>>().ToList();\n        var constrainedServices = container.ResolveAll<IFakeOpenGenericService<int>>().ToList();\n\n        Assert.Equal(2, allServices.Count);\n        Assert.Single(constrainedServices);\n    }\n\n    [Fact]\n    public void StructConstrainedOpenGenericServicesCanBeResolved()\n    {\n        var container = new StashboxContainer();\n        container.Register(typeof(IFakeOpenGenericService<>), typeof(ClassWithNoConstraints<>))\n            .Register(typeof(IFakeOpenGenericService<>), typeof(ClassWithStructConstraint<>));\n\n        var allServices = container.ResolveAll<IFakeOpenGenericService<int>>().ToList();\n        var constrainedServices = container.ResolveAll<IFakeOpenGenericService<PocoClass>>().ToList();\n\n        Assert.Equal(2, allServices.Count);\n        Assert.Single(constrainedServices);\n    }\n\n    [Fact]\n    public void ClosedServicesPreferredOverOpenGenericServices()\n    {\n        // Arrange\n        var container = new StashboxContainer()\n            .Register(typeof(IFakeOpenGenericService<PocoClass>), typeof(FakeService))\n            .Register(typeof(IFakeOpenGenericService<>), typeof(FakeOpenGenericService<>))\n            .RegisterSingleton<PocoClass>();\n\n        // Act\n        var service = container.Resolve<IFakeOpenGenericService<PocoClass>>();\n\n        // Assert\n        Assert.IsType<FakeService>(service);\n    }\n\n    [Fact]\n    public void ResolvesMixedOpenClosedGenericsAsEnumerable()\n    {\n        // Arrange\n        var container = new StashboxContainer();\n        var instance = new FakeOpenGenericService<PocoClass>(null);\n\n        container.Register<PocoClass, PocoClass>();\n        container.RegisterSingleton(typeof(IFakeOpenGenericService<PocoClass>), typeof(FakeService));\n        container.RegisterSingleton(typeof(IFakeOpenGenericService<>), typeof(FakeOpenGenericService<>));\n        container.RegisterInstance<IFakeOpenGenericService<PocoClass>>(instance);\n\n        var enumerable = container.Resolve<IEnumerable<IFakeOpenGenericService<PocoClass>>>().ToArray();\n\n        // Assert\n        Assert.Equal(3, enumerable.Length);\n        Assert.NotNull(enumerable[0]);\n        Assert.NotNull(enumerable[1]);\n        Assert.NotNull(enumerable[2]);\n\n        Assert.Equal(instance, enumerable[2]);\n        Assert.IsType<FakeService>(enumerable[0]);\n    }\n}\n\ninterface IFakeService;\n\ninterface IFakeSingletonService : IFakeService;\n\ninterface IFakeEveryService :\n    IFakeService,\n    IFakeSingletonService,\n    IFakeOpenGenericService<PocoClass>;\n\ninterface IFakeOpenGenericService<T>\n{\n    T Value { get; }\n}\n\nclass ClassWithNoConstraints<T> : IFakeOpenGenericService<T>\n{\n    public T Value { get; } = default;\n}\n\nclass ClassWithNewConstraint<T> : IFakeOpenGenericService<T>\n    where T : new()\n{\n    public T Value { get; } = new T();\n}\n\nclass ClassWithSelfReferencingConstraint<T> : IFakeOpenGenericService<T>\n    where T : IComparable<T>\n{\n    public ClassWithSelfReferencingConstraint(T value) => Value = value;\n    public T Value { get; }\n}\n\nclass FakeOpenGenericService<TVal> : IFakeOpenGenericService<TVal>\n{\n    public FakeOpenGenericService(TVal value)\n    {\n        Value = value;\n    }\n\n    public TVal Value { get; }\n}\n\nclass ClassWithClassConstraint<T> : IFakeOpenGenericService<T>\n    where T : class\n{\n    public T Value { get; } = default;\n}\n\nclass ClassWithStructConstraint<T> : IFakeOpenGenericService<T>\n    where T : struct\n{\n    public T Value { get; } = default;\n}\n\nclass PocoClass;\n\nclass ClassWithPrivateCtor\n{\n    private ClassWithPrivateCtor()\n    {\n    }\n}\n\nclass ClassImplementingIComparable : IComparable<ClassImplementingIComparable>\n{\n    public int CompareTo(ClassImplementingIComparable other) => 0;\n}\n\nclass FakeService : IFakeEveryService, IDisposable\n{\n    public PocoClass Value { get; set; }\n\n    public bool Disposed { get; private set; }\n\n    public void Dispose()\n    {\n        if (Disposed)\n        {\n            throw new ObjectDisposedException(nameof(FakeService));\n        }\n\n        Disposed = true;\n    }\n}"
  },
  {
    "path": "test/IssueTests/48_Chained_named_scopes_are_not_working_properly.cs",
    "content": "﻿using Xunit;\n\nnamespace Stashbox.Tests.IssueTests;\n\npublic class ChainedNamedScopesAreNotWorkingProperly\n{\n    [Fact]\n    public void Chained_named_scopes_are_not_working_properly()\n    {\n        var container = new StashboxContainer()\n            .Register<NamedScopeTest2>(config => config.DefinesScope(\"B\").InNamedScope(\"A\"))\n            .Register<NamedScopeTest1>(config => config.InNamedScope(\"B\"))\n            .Register<NamedScopeTest3>(config => config.DefinesScope(\"A\"));\n\n        Assert.NotNull(container.Resolve<NamedScopeTest3>());\n    }\n\n    class NamedScopeTest1;\n\n    class NamedScopeTest2\n    {\n        public NamedScopeTest2(NamedScopeTest1 t)\n        { }\n    }\n\n    class NamedScopeTest3\n    {\n        public NamedScopeTest3(NamedScopeTest2 t)\n        { }\n    }\n}"
  },
  {
    "path": "test/IssueTests/49_Unable_to_use_nullable_types_with_injection_parameters.cs",
    "content": "﻿using Xunit;\n\nnamespace Stashbox.Tests.IssueTests;\n\npublic class UnableToUseNullableTypesWithInjectionParameters\n{\n    [Fact]\n    public void Unable_to_use_nullable_types_with_injection_parameters()\n    {\n        var container = new StashboxContainer(config => config\n            .WithDefaultValueInjection());\n\n        var someInt = 123;\n\n        var inst = container.Register<IExample, ExampleClass>(\n            config => config.WithInjectionParameter(\"exampleValue\", someInt)).Resolve<IExample>();\n\n        Assert.NotNull(inst);\n        Assert.IsType<ExampleClass>(inst);\n        Assert.Equal(someInt, inst.ExampleProperty.Value);\n    }\n\n    [Fact]\n    public void Unable_to_use_nullable_types_with_injection_parameters_member()\n    {\n        var container = new StashboxContainer(config => config\n            .WithDefaultValueInjection()\n            .WithAutoMemberInjection());\n\n        var someInt = 123;\n\n        var inst = container.Register<IExample, ExampleClass2>(\n            config => config.WithInjectionParameter(\"ExampleProperty\", someInt)).Resolve<IExample>();\n\n        Assert.NotNull(inst);\n        Assert.IsType<ExampleClass2>(inst);\n        Assert.Equal(someInt, inst.ExampleProperty.Value);\n    }\n\n    interface IExample\n    {\n        int? ExampleProperty { get; }\n    }\n\n    class ExampleClass : IExample\n    {\n        public ExampleClass(int? exampleValue = null)\n        {\n            ExampleProperty = exampleValue;\n        }\n\n        public int? ExampleProperty { get; private set; }\n    }\n\n    class ExampleClass2 : IExample\n    {\n        public int? ExampleProperty { get; set; }\n    }\n}"
  },
  {
    "path": "test/IssueTests/50_Generate_one_instance_for_multiple_interfaces.cs",
    "content": "﻿using Xunit;\n\nnamespace Stashbox.Tests.IssueTests;\n\npublic class GenerateOneInstanceForMultipleInterfaces\n{\n    [Fact]\n    public void Generate_one_instance_for_multiple_interfaces()\n    {\n        var container = new StashboxContainer();\n        container.Register<Test2>(context => context.AsImplementedTypes());\n        var inst1 = container.Resolve<ITest>();\n        var inst2 = container.Resolve<ITest1>();\n        var inst3 = container.Resolve<ITest2>();\n        var inst4 = container.Resolve<Test>();\n        var inst5 = container.Resolve<Test2>();\n\n        Assert.NotSame(inst1, inst2);\n        Assert.NotSame(inst2, inst3);\n        Assert.NotSame(inst3, inst4);\n        Assert.NotSame(inst4, inst5);\n    }\n\n    [Fact]\n    public void Generate_one_instance_for_multiple_interfaces_singleton()\n    {\n        var container = new StashboxContainer();\n        container.Register<Test2>(context => context.AsImplementedTypes().WithSingletonLifetime());\n        var inst1 = container.Resolve<ITest>();\n        var inst2 = container.Resolve<ITest1>();\n        var inst3 = container.Resolve<ITest2>();\n        var inst4 = container.Resolve<Test>();\n        var inst5 = container.Resolve<Test2>();\n\n        Assert.Same(inst1, inst2);\n        Assert.Same(inst2, inst3);\n        Assert.Same(inst3, inst4);\n        Assert.Same(inst4, inst5);\n    }\n\n    [Fact]\n    public void Generate_one_instance_for_multiple_interfaces_scoped()\n    {\n        var container = new StashboxContainer();\n        container.Register<Test2>(context => context.AsImplementedTypes().WithScopedLifetime());\n\n        var scope = container.BeginScope();\n        var inst1 = scope.Resolve<ITest>();\n        var inst2 = scope.Resolve<ITest1>();\n        var inst3 = scope.Resolve<ITest2>();\n        var inst4 = scope.Resolve<Test>();\n        var inst5 = scope.Resolve<Test2>();\n\n        Assert.Same(inst1, inst2);\n        Assert.Same(inst2, inst3);\n        Assert.Same(inst3, inst4);\n        Assert.Same(inst4, inst5);\n    }\n\n    [Fact]\n    public void Generate_one_instance_for_multiple_interfaces_named_scope()\n    {\n        var container = new StashboxContainer();\n        container.Register<Test2>(context => context.AsImplementedTypes().InNamedScope(\"A\"));\n\n        var scope = container.BeginScope(\"A\");\n        var inst1 = scope.Resolve<ITest>();\n        var inst2 = scope.Resolve<ITest1>();\n        var inst3 = scope.Resolve<ITest2>();\n        var inst4 = scope.Resolve<Test>();\n        var inst5 = scope.Resolve<Test2>();\n\n        Assert.Same(inst1, inst2);\n        Assert.Same(inst2, inst3);\n        Assert.Same(inst3, inst4);\n        Assert.Same(inst4, inst5);\n    }\n\n    interface ITest;\n\n    interface ITest1;\n\n    interface ITest2;\n\n    class Test;\n\n    class Test2 : Test, ITest, ITest1, ITest2;\n}"
  },
  {
    "path": "test/IssueTests/51_WithUnknownTypeResolution_breaks_constructor_selection_rules.cs",
    "content": "﻿using Xunit;\n\nnamespace Stashbox.Tests.IssueTests;\n\npublic class WithUnknownTypeResolutionBreaksConstructorSelectionRules\n{\n    [Fact]\n    public void WithUnknownTypeResolution_breaks_constructor_selection_rules()\n    {\n        var container = new StashboxContainer(config => config.WithUnknownTypeResolution());\n        var inst = container\n            .Register<Test>()\n            .Register<Dep1>()\n            .Resolve<Test>();\n\n        Assert.NotNull(inst.Dep1);\n        Assert.Null(inst.Dep);\n    }\n\n    [Fact]\n    public void WithUnknownTypeResolution_breaks_constructor_selection_rules_ensure_ok_without_unknown_type_resolver()\n    {\n        var container = new StashboxContainer();\n        var inst = container\n            .Register<Test>()\n            .Register<Dep1>()\n            .Resolve<Test>();\n\n        Assert.NotNull(inst.Dep1);\n        Assert.Null(inst.Dep);\n    }\n\n    class Dep;\n\n    class Dep1;\n\n    class Test\n    {\n        public Dep Dep { get; }\n        public Dep1 Dep1 { get; }\n        public Test(Dep dep) { Dep = dep; }\n        public Test(Dep1 dep) { Dep1 = dep; }\n    }\n}"
  },
  {
    "path": "test/IssueTests/52_Verify_child_container_working.cs",
    "content": "﻿using System;\nusing System.Threading;\nusing Xunit;\n\nnamespace Stashbox.Tests.IssueTests;\n\npublic class VerifyChildContainerWorking\n{\n    [Fact]\n    public void Verify_child_container_working()\n    {\n        var container = new StashboxContainer()\n            .RegisterSingleton<Singleton>()\n            .RegisterScoped<Scoped>();\n\n        Assert.Equal(1, container.Resolve<Singleton>().Id);\n        Assert.Equal(1, container.BeginScope().Resolve<Scoped>().Id);\n\n        var child = container.CreateChildContainer();\n        Assert.Equal(1, child.Resolve<Singleton>().Id);\n        Assert.Equal(2, child.BeginScope().Resolve<Scoped>().Id);\n\n        var child2 = container.CreateChildContainer().RegisterSingleton<Singleton>();\n        Assert.Equal(2, child2.Resolve<Singleton>().Id);\n        Assert.Equal(3, child2.BeginScope().Resolve<Scoped>().Id);\n    }\n\n    [Fact]\n    public void Verify_child_container_working_dispose()\n    {\n        Singleton s = null;\n        {\n            using var container = new StashboxContainer()\n                .RegisterSingleton<Singleton>();\n            {\n                {\n                    using var child = container.CreateChildContainer();\n                    s = child.Resolve<Singleton>();\n                }\n\n                Assert.False(s.Disposed);\n            }\n        }\n\n        Assert.True(s.Disposed);\n    }\n\n    private class Singleton : IDisposable\n    {\n        private static int seed;\n\n        public int Id = Interlocked.Increment(ref seed);\n\n        public bool Disposed { get; private set; }\n\n        public void Dispose()\n        {\n            if (this.Disposed)\n                throw new ObjectDisposedException(nameof(Singleton));\n\n            this.Disposed = true;\n        }\n    }\n\n    private class Scoped\n    {\n        private static int seed;\n\n        public int Id = Interlocked.Increment(ref seed);\n    }\n}"
  },
  {
    "path": "test/IssueTests/53_ComposeBy_with_instance_or_injection.cs",
    "content": "﻿using Moq;\nusing Xunit;\n\nnamespace Stashbox.Tests.IssueTests;\n\npublic class ComposeByWithInstanceOrInjection\n{\n    [Fact]\n    public void ComposeByWithInstance()\n    {\n        var mock = new Mock<ICompositionRoot>();\n        var container = new StashboxContainer().ComposeBy(mock.Object);\n        mock.Verify(m => m.Compose(container), Times.Once);\n    }\n\n    [Fact]\n    public void ComposeByWithInjection()\n    {\n        new StashboxContainer()\n            .Register<TestDep>()\n            .ComposeBy<TestRoot1>();\n    }\n\n    [Fact]\n    public void ComposeByWithMemberInjection()\n    {\n        new StashboxContainer(c => c.WithAutoMemberInjection())\n            .Register<TestDep>()\n            .ComposeBy<TestRoot>();\n    }\n\n    [Fact]\n    public void ComposeByWithInjectionWithDependencyOverride()\n    {\n        new StashboxContainer()\n            .ComposeBy<TestRoot2>(5);\n    }\n\n    class TestDep;\n\n    class TestRoot : ICompositionRoot\n    {\n        public TestDep Test { get; set; }\n\n        public void Compose(IStashboxContainer container)\n        {\n            if (this.Test == null)\n                Assert.True(false, \"Dependency not resolved\");\n        }\n    }\n\n    class TestRoot1 : ICompositionRoot\n    {\n        public TestDep Test { get; set; }\n\n        public TestRoot1(TestDep test)\n        {\n            this.Test = test;\n        }\n\n        public void Compose(IStashboxContainer container)\n        {\n            if (this.Test == null)\n                Assert.True(false, \"Dependency not resolved\");\n        }\n    }\n\n    class TestRoot2 : ICompositionRoot\n    {\n        public int Test { get; set; }\n\n        public TestRoot2(int test)\n        {\n            this.Test = test;\n        }\n\n        public void Compose(IStashboxContainer container)\n        {\n            if (this.Test != 5)\n                Assert.True(false, \"Dependency not resolved\");\n        }\n    }\n}"
  },
  {
    "path": "test/IssueTests/54_Make_InjectionParameter_configuration_more_fluent.cs",
    "content": "﻿using System.Collections.Generic;\nusing Xunit;\n\nnamespace Stashbox.Tests.IssueTests;\n\npublic class MakeInjectionParameterConfigurationMoreFluent\n{\n    [Fact]\n    public void MakeInjectionParameterConfigurationMoreFluent_Mixed()\n    {\n        var instance = new StashboxContainer()\n            .Register<Test1>(c => c.WithAutoMemberInjection()\n                .WithInjectionParameter(nameof(Test1.TestString), \"sample\")\n                .WithInjectionParameters(new KeyValuePair<string, object>(nameof(Test1.TestInt), 5)))\n            .Resolve<Test1>();\n\n        Assert.Equal(\"sample\", instance.TestString);\n        Assert.Equal(5, instance.TestInt);\n    }\n\n    class Test1\n    {\n        public string TestString { get; set; }\n\n        public int TestInt { get; set; }\n    }\n}"
  },
  {
    "path": "test/IssueTests/55_Conditions_on_member_name_are_not_easy_to_recognize.cs",
    "content": "﻿using Xunit;\n\nnamespace Stashbox.Tests.IssueTests;\n\npublic class ConditionsOnMemberNameAreNotEasyToRecognize\n{\n    [Fact]\n    public void ConditionsOnMemberNameAreNotEasyToRecognize_UseParameterOrMemberName()\n    {\n        var container = new StashboxContainer();\n        container.Register<ITest1, Test1>(context => context.When(t => t.ParameterOrMemberName == \"Test1\"));\n        container.Register<ITest1, Test11>(context => context.When(t => t.ParameterOrMemberName == \"Test11\"));\n        container.Register<Test2>(c => c.WithAutoMemberInjection());\n\n        var test5 = container.Resolve<Test2>();\n\n        Assert.IsType<Test1>(test5.Test1);\n        Assert.IsType<Test11>(test5.Test11);\n    }\n\n    interface ITest1;\n\n    class Test1 : ITest1;\n\n    class Test11 : ITest1;\n\n    class Test2\n    {\n        public ITest1 Test1 { get; set; }\n\n        public ITest1 Test11 { get; set; }\n    }\n}"
  },
  {
    "path": "test/IssueTests/58_InjectionParameter_NullReference.cs",
    "content": "﻿using Xunit;\n\nnamespace Stashbox.Tests.IssueTests;\n\npublic class InjectionParameterNullReference\n{\n    [Fact]\n    public void InjectionParameter_NullReference()\n    {\n        var inst = new StashboxContainer()\n            .Register<Test>(c => c.WithInjectionParameter(\"arg\", null))\n            .Resolve<Test>();\n\n        Assert.NotNull(inst);\n    }\n\n    [Fact]\n    public void InjectionParameter_NullReference_Object()\n    {\n        var inst = new StashboxContainer()\n            .Register<Test2>(c => c.WithInjectionParameter(\"arg\", null))\n            .Resolve<Test2>();\n\n        Assert.NotNull(inst);\n    }\n\n    class Test\n    {\n        public Test(Test2 arg)\n        { }\n    }\n\n    class Test2\n    {\n        public Test2(object arg)\n        { }\n    }\n}"
  },
  {
    "path": "test/IssueTests/59_Static_factory_fails.cs",
    "content": "﻿using System;\nusing System.Linq.Expressions;\nusing System.Reflection;\nusing Xunit;\n\nnamespace Stashbox.Tests.IssueTests;\n\npublic class StaticFactoryFails\n{\n    [Fact]\n    public void Ensure_Static_Factory_Registration_Works()\n    {\n        var inst = new StashboxContainer().Register<T>(c => c.WithFactory(Factory)).Resolve<T>();\n\n        Assert.NotNull(inst);\n    }\n\n    [Fact]\n    public void Ensure_Static_Factory_Registration_With_Resolver_Works()\n    {\n        var inst = new StashboxContainer().Register<T>(c => c.WithFactory(ResolverFactory)).Resolve<T>();\n\n        Assert.NotNull(inst);\n    }\n\n    [Fact]\n    public void Ensure_Static_Factory_Registration_WithProperty_Works()\n    {\n        var prop = typeof(St)\n            .GetProperty(\"Tp\");\n        var inst = new StashboxContainer().Register<T>(c => c\n                .WithFactory(prop\n                    .Access(null)\n                    .AsLambda<Func<T>>()\n                    .Compile()))\n            .Resolve<T>();\n\n        Assert.NotNull(inst);\n    }\n\n    [Fact]\n    public void Ensure_Static_Factory_Registration_CompiledLambda_Works()\n    {\n        var param = typeof(IDependencyResolver).AsParameter();\n        var inst = new StashboxContainer().Register<T>(c => c\n                .WithFactory(this\n                    .GetType()\n                    .GetMethod(\"ResolverFactory\", BindingFlags.Static | BindingFlags.NonPublic)\n                    .CallStaticMethod(param)\n                    .AsLambda<Func<IDependencyResolver, T>>(param)\n                    .Compile()))\n            .Resolve<T>();\n\n        Assert.NotNull(inst);\n    }\n\n    private static T Factory() => new();\n\n    private static T ResolverFactory(IDependencyResolver resolver) => new();\n\n    private class T;\n\n    private static class St\n    {\n        public static T Tp => new();\n    }\n}"
  },
  {
    "path": "test/IssueTests/63_named_unnamed_resolution_not_working_as_expected.cs",
    "content": "﻿using Stashbox.Attributes;\nusing Stashbox.Exceptions;\nusing Xunit;\n\nnamespace Stashbox.Tests.IssueTests;\n\npublic class NamedUnnamedResolutionNotWorkingAsExpected\n{\n    [Fact]\n    public void Ensures_Named_Dependency_Selected_When_Convention_Enabled()\n    {\n        var inst = new StashboxContainer(c => c.TreatParameterAndMemberNameAsDependencyName())\n            .Register<ITest, Test1>(c => c.WithName(\"t1\"))\n            .Register<ITest, Test2>(c => c.WithName(\"t2\"))\n            .Register<Test3>()\n            .Resolve<Test3>();\n\n        Assert.IsType<Test1>(inst.T1);\n        Assert.IsType<Test2>(inst.T2);\n    }\n\n    [Fact]\n    public void Ensures_Named_Dependency_Selected_When_Convention_Enabled_InjectionMembers()\n    {\n        var inst = new StashboxContainer(c => c.TreatParameterAndMemberNameAsDependencyName())\n            .Register<ITest, Test1>(c => c.WithName(\"T1\"))\n            .Register<ITest, Test2>(c => c.WithName(\"T2\"))\n            .Register<Test4>(c => c.WithAutoMemberInjection())\n            .Resolve<Test4>();\n\n        Assert.IsType<Test1>(inst.T1);\n        Assert.IsType<Test2>(inst.T2);\n    }\n\n    [Fact]\n    public void Ensures_Named_Dependency_Selected_When_Convention_Enabled_InjectionMethod()\n    {\n        var inst = new StashboxContainer(c => c.TreatParameterAndMemberNameAsDependencyName())\n            .Register<ITest, Test1>(c => c.WithName(\"t1\"))\n            .Register<ITest, Test2>(c => c.WithName(\"t2\"))\n            .Register<Test5>()\n            .Resolve<Test5>();\n\n        Assert.IsType<Test1>(inst.T1);\n        Assert.IsType<Test2>(inst.T2);\n    }\n\n    [Fact]\n    public void Ensures_UnNamed_Dependency_Selected_When_Named_Not_Available()\n    {\n        var container = new StashboxContainer(c => c.WithNamedDependencyResolutionForUnNamedRequests())\n            .Register<ITest, Test1>(c => c.WithName(\"t1\").WithSingletonLifetime());\n\n        var inst = container.Resolve<ITest>(\"t1\");\n        var inst2 = container.Resolve<ITest>();\n\n        Assert.NotNull(inst);\n        Assert.NotNull(inst2);\n        Assert.Equal(inst, inst2);\n    }\n\n    [Fact]\n    public void Ensures_UnNamed_Dependency_Selected_When_Convention_Enabled_But_Named_Preferred()\n    {\n        var container = new StashboxContainer(c => c\n                .TreatParameterAndMemberNameAsDependencyName()\n                .WithNamedDependencyResolutionForUnNamedRequests())\n            .Register<Test3>()\n            .Register<ITest, Test1>(\"t1\")\n            .Register<ITest, Test2>();\n\n        var inst = container.Resolve<Test3>();\n\n        Assert.IsType<Test1>(inst.T1);\n        Assert.IsType<Test2>(inst.T2);\n    }\n\n    [Fact]\n    public void Ensures_Dont_Resolve_Named_When_Not_Enabled()\n    {\n        var container = new StashboxContainer(c => c\n                .TreatParameterAndMemberNameAsDependencyName())\n            .Register<Test3>()\n            .Register<ITest, Test1>(\"t1\");\n\n        Assert.Throws<ResolutionFailedException>(() => container.Resolve<Test3>());\n    }\n\n    [Fact]\n    public void Ensures_UnNamed_Dependency_Selected_When_Named_Not_Available_With_Treating_Param_Names_As_Dependency_Names()\n    {\n        var container = new StashboxContainer(c => c\n                .TreatParameterAndMemberNameAsDependencyName())\n            .Register<Test3>()\n            .Register<ITest, Test1>(\"t1\")\n            .Register<ITest, Test2>();\n\n        var inst = container.Resolve<Test3>();\n\n        Assert.IsType<Test1>(inst.T1);\n        Assert.IsType<Test2>(inst.T2);\n    }\n\n    interface ITest;\n\n    class Test1 : ITest;\n\n    class Test2 : ITest;\n\n    class Test3\n    {\n        public ITest T1 { get; }\n        public ITest T2 { get; }\n\n        public Test3(ITest t1, ITest t2)\n        {\n            T1 = t1;\n            T2 = t2;\n        }\n    }\n\n    class Test4\n    {\n        public ITest T1 { get; set; }\n        public ITest T2 { get; set; }\n    }\n\n    class Test5\n    {\n        public ITest T1 { get; set; }\n        public ITest T2 { get; set; }\n\n        [InjectionMethod]\n        public void Init(ITest t1, ITest t2)\n        {\n            T1 = t1;\n            T2 = t2;\n        }\n    }\n}"
  },
  {
    "path": "test/IssueTests/64_WithFactory_MemberInjection_Not_Working_With_ImplementationType.cs",
    "content": "﻿using Xunit;\n\nnamespace Stashbox.Tests.IssueTests;\n\npublic class WithFactoryMemberInjectionNotWorkingWithImplementationType\n{\n    [Fact]\n    public void Ensure_MemberInjection_Works_WithFactory()\n    {\n        var inst = new StashboxContainer(c => c.WithUnknownTypeResolution().WithAutoMemberInjection())\n            .Register<ITest, Test>(ctx => ctx.WithFactory(r => new Test()))\n            .Resolve<ITest>();\n\n        Assert.NotNull(((Test)inst).Dummy);\n    }\n\n    class Dummy;\n\n    interface ITest;\n\n    class Test : ITest\n    {\n        public Dummy Dummy { get; set; }\n    }\n\n\n}"
  },
  {
    "path": "test/IssueTests/66_Named_PutInstanceInScope.cs",
    "content": "﻿using Xunit;\n\nnamespace Stashbox.Tests.IssueTests;\n\npublic class NamedPutInstanceInScope\n{\n    [Fact]\n    public void Ensure_Named_Scoped_Instance_Working()\n    {\n        using var container = new StashboxContainer()\n            .Register<A>();\n\n        var a1 = new A();\n        var a2 = new A();\n        var a3 = new A();\n\n        {\n            using var scope = container.BeginScope();\n\n\n\n            scope.PutInstanceInScope(a1);\n            scope.PutInstanceInScope(a2, name: \"a\");\n            scope.PutInstanceInScope(a3);\n\n            Assert.Same(a2, scope.Resolve<A>(\"a\"));\n        }\n\n        {\n            using var scope = container.BeginScope();\n\n            scope.PutInstanceInScope(a1, name: \"a1\");\n            scope.PutInstanceInScope(a2, name: \"a2\");\n            scope.PutInstanceInScope(a3, name: \"a3\");\n\n            Assert.Same(a2, scope.Resolve<A>(\"a2\"));\n        }\n    }\n\n    class A;\n}"
  },
  {
    "path": "test/IssueTests/67_Dictionaries_get_resolved_to_arrays_of_key_type_by_default.cs",
    "content": "﻿using Stashbox.Configuration;\nusing System.Collections.Generic;\nusing Xunit;\n\nnamespace Stashbox.Tests.IssueTests;\n\npublic class DictionariesGetResolvedToArraysOfKeyTypeByDefault\n{\n    [Fact]\n    public void Ensure_Dictionary_Resolves()\n    {\n        var container = new StashboxContainer(c => c.WithUnknownTypeResolution(c2 =>\n            c2.WithConstructorSelectionRule(Rules.ConstructorSelection.PreferLeastParameters)));\n        Assert.NotNull(container.Resolve<Dictionary<string, object>>());\n    }\n}"
  },
  {
    "path": "test/IssueTests/68_Programmatic_multiple_instances_registration.cs",
    "content": "﻿using System.Linq;\nusing Xunit;\n\nnamespace Stashbox.Tests.IssueTests;\n\npublic class ProgrammaticMultipleInstancesRegistration\n{\n    [Fact]\n    public void Ensure_Multiple_Instance_Registration_Working()\n    {\n        var regs = new StashboxContainer()\n            .RegisterInstances<ITest>(new Test(), new Test1()).GetRegistrationMappings();\n\n        Assert.Equal(2, regs.Count());\n    }\n\n    [Fact]\n    public void Ensure_Multiple_Instance_Registration_Working_Enumerable()\n    {\n        var regs = new StashboxContainer()\n            .RegisterInstances(new ITest[] { new Test(), new Test1() }).GetRegistrationMappings();\n\n        Assert.Equal(2, regs.Count());\n    }\n\n    interface ITest;\n\n    class Test : ITest;\n\n    class Test1 : ITest;\n}"
  },
  {
    "path": "test/IssueTests/70_UnkownType_overrides_instance_in_scope.cs",
    "content": "﻿using Xunit;\n\nnamespace Stashbox.Tests.IssueTests;\n\npublic class UnkownTypOverridesInstanceInScope\n{\n    [Fact]\n    public void Ensure_UnknownType_Doesnt_Overrides_Instance_In_Scope()\n    {\n        var container = new StashboxContainer(c => c.WithUnknownTypeResolution());\n        var inst = container.Resolve<object>();\n\n        using var scope = container.BeginScope();\n        var @new = new object();\n        scope.PutInstanceInScope(@new);\n\n        var scoped = scope.Resolve<object>();\n        Assert.NotSame(inst, scoped);\n        Assert.Same(@new, scoped);\n    }\n}"
  },
  {
    "path": "test/IssueTests/71_FastExpressionCompiler_Issue.cs",
    "content": "﻿using FastExpressionCompiler;\nusing System;\nusing System.Linq.Expressions;\nusing System.Reflection;\nusing Xunit;\n\nnamespace Stashbox.Tests.IssueTests;\n\npublic class FastExpressionCompilerIssue\n{\n    static Test T { get; } = new Test();\n\n    [Fact]\n    public void Ensure_FastExpressionCompiler_Works()\n    {\n        var prop = typeof(FastExpressionCompilerIssue).GetProperty(\"T\", BindingFlags.NonPublic | BindingFlags.Static);\n        var memberLambda = Expression.MakeMemberAccess(null, prop).AsLambda<Func<object>>().CompileFast();\n\n        Assert.NotNull(new StashboxContainer()\n            .Register<Test>(c => c.WithFactory(memberLambda, true))\n            .Resolve<Test>());\n    }\n\n    class Test;\n}"
  },
  {
    "path": "test/IssueTests/72_Default_lifetime_set.cs",
    "content": "﻿using Stashbox.Lifetime;\nusing System.Linq;\nusing Xunit;\n\nnamespace Stashbox.Tests.IssueTests;\n\npublic class DefaultLifetimeSet\n{\n    [Fact]\n    public void Ensure_Default_Lifetime_Used_When_Custom_Not_Set()\n    {\n        var mappings = new StashboxContainer(c => c.WithDefaultLifetime(Lifetimes.Scoped))\n            .Register<Test>().GetRegistrationMappings();\n\n        var reg = mappings.First();\n\n        Assert.Equal(typeof(Test), reg.Key);\n        Assert.Same(Lifetimes.Scoped, reg.Value.Lifetime);\n    }\n\n    [Fact]\n    public void Ensure_Custom_Lifetime_Used_When_Both_Set()\n    {\n        var mappings = new StashboxContainer(c => c.WithDefaultLifetime(Lifetimes.Scoped))\n            .Register<Test>(c => c.WithSingletonLifetime()).GetRegistrationMappings();\n\n        var reg = mappings.First();\n\n        Assert.Equal(typeof(Test), reg.Key);\n        Assert.Same(Lifetimes.Singleton, reg.Value.Lifetime);\n    }\n\n    [Fact]\n    public void Ensure_Transient_Lifetime_Used_By_Default()\n    {\n        var mappings = new StashboxContainer()\n            .Register<Test>().GetRegistrationMappings();\n\n        var reg = mappings.First();\n\n        Assert.Equal(typeof(Test), reg.Key);\n        Assert.Same(Lifetimes.Transient, reg.Value.Lifetime);\n    }\n\n    class Test;\n}"
  },
  {
    "path": "test/IssueTests/76_Exception_when_building_expressions.cs",
    "content": "﻿using Stashbox.Configuration;\nusing Stashbox.Tests.Utils;\nusing System;\nusing System.Threading;\nusing Xunit;\n\nnamespace Stashbox.Tests.IssueTests;\n\npublic class ExceptionWhenBuildingExpressions\n{\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void Ensure_expression_built_correctly_scoped(CompilerType compilerType)\n    {\n        A.Counter = 0;\n        B.Counter = 0;\n        C.Counter = 0;\n        D.Counter = 0;\n        E.Counter = 0;\n        F.Counter = 0;\n\n        A inst = null;\n        {\n            using var container = new StashboxContainer(c => c.WithDisposableTransientTracking()\n                    .WithCompiler(compilerType))\n                .Register<A>(c => c.WithScopedLifetime())\n                .Register<B>(c => c.WithScopedLifetime())\n                .Register<D>(c => c.WithScopedLifetime())\n                .Register<E>(c => c.WithScopedLifetime())\n                .Register<F>(c => c.WithScopedLifetime())\n                .Register<C>(c => c.WithFactory(r => new C()).WithScopedLifetime().WithoutDisposalTracking());\n\n            using var scope = container.BeginScope();\n            inst = scope.Resolve<A>();\n\n            Assert.NotNull(inst);\n            Assert.NotNull(inst.B);\n            Assert.NotNull(inst.C);\n            Assert.NotNull(inst.B.D);\n            Assert.NotNull(inst.B.C);\n            Assert.NotNull(inst.B.D.C);\n            Assert.NotNull(inst.B.D.E);\n            Assert.NotNull(inst.B.D.F);\n            Assert.NotNull(inst.B.D.E.C);\n            Assert.NotNull(inst.B.D.F.C);\n\n            Assert.Same(inst.C, inst.B.C);\n            Assert.Same(inst.B.C, inst.B.D.C);\n            Assert.Same(inst.B.D.C, inst.B.D.E.C);\n            Assert.Same(inst.B.D.E.C, inst.B.D.F.C);\n        }\n\n        Assert.True(inst.Disposed);\n        Assert.True(inst.B.Disposed);\n        Assert.False(inst.C.Disposed);\n        Assert.True(inst.B.D.Disposed);\n        Assert.False(inst.B.C.Disposed);\n        Assert.False(inst.B.D.C.Disposed);\n        Assert.True(inst.B.D.E.Disposed);\n        Assert.True(inst.B.D.F.Disposed);\n        Assert.False(inst.B.D.E.C.Disposed);\n        Assert.False(inst.B.D.F.C.Disposed);\n\n        Assert.Equal(1, A.Counter);\n        Assert.Equal(1, B.Counter);\n        Assert.Equal(1, C.Counter);\n        Assert.Equal(1, D.Counter);\n        Assert.Equal(1, E.Counter);\n        Assert.Equal(1, F.Counter);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void Ensure_expression_built_correctly_scoped_one_singleton(CompilerType compilerType)\n    {\n        A.Counter = 0;\n        B.Counter = 0;\n        C.Counter = 0;\n        D.Counter = 0;\n        E.Counter = 0;\n        F.Counter = 0;\n\n        A inst = null;\n        {\n            using var container = new StashboxContainer(c =>\n                {\n                    c.WithDisposableTransientTracking().WithCompiler(compilerType);\n                })\n                .Register<A>(c => c.WithScopedLifetime())\n                .Register<B>(c => c.WithSingletonLifetime())\n                .Register<D>(c => c.WithScopedLifetime())\n                .Register<E>(c => c.WithScopedLifetime())\n                .Register<F>(c => c.WithScopedLifetime())\n                .Register<C>(c => c.WithFactory(r => new C()).WithScopedLifetime().WithoutDisposalTracking());\n\n            using var scope = container.BeginScope();\n            inst = scope.Resolve<A>();\n\n            Assert.NotNull(inst);\n            Assert.NotNull(inst.B);\n            Assert.NotNull(inst.C);\n            Assert.NotNull(inst.B.D);\n            Assert.NotNull(inst.B.C);\n            Assert.NotNull(inst.B.D.C);\n            Assert.NotNull(inst.B.D.E);\n            Assert.NotNull(inst.B.D.F);\n            Assert.NotNull(inst.B.D.E.C);\n            Assert.NotNull(inst.B.D.F.C);\n\n            Assert.NotSame(inst.C, inst.B.C);\n            Assert.Same(inst.B.C, inst.B.D.C);\n            Assert.Same(inst.B.D.C, inst.B.D.E.C);\n            Assert.Same(inst.B.D.E.C, inst.B.D.F.C);\n        }\n\n        Assert.True(inst.Disposed);\n        Assert.True(inst.B.Disposed);\n        Assert.False(inst.C.Disposed);\n        Assert.True(inst.B.D.Disposed);\n        Assert.False(inst.B.C.Disposed);\n        Assert.False(inst.B.D.C.Disposed);\n        Assert.True(inst.B.D.E.Disposed);\n        Assert.True(inst.B.D.F.Disposed);\n        Assert.False(inst.B.D.E.C.Disposed);\n        Assert.False(inst.B.D.F.C.Disposed);\n\n        Assert.Equal(1, A.Counter);\n        Assert.Equal(1, B.Counter);\n        Assert.Equal(2, C.Counter);\n        Assert.Equal(1, D.Counter);\n        Assert.Equal(1, E.Counter);\n        Assert.Equal(1, F.Counter);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void Ensure_expression_built_correctly_singleton(CompilerType compilerType)\n    {\n        A.Counter = 0;\n        B.Counter = 0;\n        C.Counter = 0;\n        D.Counter = 0;\n        E.Counter = 0;\n        F.Counter = 0;\n\n        A inst = null;\n        {\n            using var container = new StashboxContainer(c =>\n                {\n                    c.WithDisposableTransientTracking()\n                        .WithCompiler(compilerType);\n                })\n                .Register<A>(c => c.DefinesScope(\"A\"))\n                .Register<B>(c => c.WithSingletonLifetime().DefinesScope(\"B\"))\n                .Register<D>(c => c.DefinesScope(\"D\").WithScopedLifetime())\n                .Register<E>(c => c.DefinesScope(\"E\"))\n                .Register<F>(c => c.DefinesScope(\"F\"))\n                .Register<C>(c => c.WithFactory(r => new C()).WithoutDisposalTracking().WithScopedLifetime());\n\n            {\n                using var scope = container.BeginScope();\n                inst = scope.Resolve<A>();\n\n                Assert.NotNull(inst);\n                Assert.NotNull(inst.B);\n                Assert.NotNull(inst.C);\n                Assert.NotNull(inst.B.D);\n                Assert.NotNull(inst.B.C);\n                Assert.NotNull(inst.B.D.C);\n                Assert.NotNull(inst.B.D.E);\n                Assert.NotNull(inst.B.D.F);\n                Assert.NotNull(inst.B.D.E.C);\n                Assert.NotNull(inst.B.D.F.C);\n\n                Assert.NotSame(inst.C, inst.B.C);\n                Assert.NotSame(inst.B.C, inst.B.D.C);\n                Assert.NotSame(inst.B.D.C, inst.B.D.E.C);\n                Assert.NotSame(inst.B.D.E.C, inst.B.D.F.C);\n            }\n\n            Assert.True(inst.Disposed);\n            Assert.False(inst.B.Disposed);\n            Assert.False(inst.C.Disposed);\n            Assert.False(inst.B.D.Disposed);\n            Assert.False(inst.B.C.Disposed);\n            Assert.False(inst.B.D.C.Disposed);\n            Assert.False(inst.B.D.E.Disposed);\n            Assert.False(inst.B.D.F.Disposed);\n            Assert.False(inst.B.D.E.C.Disposed);\n            Assert.False(inst.B.D.F.C.Disposed);\n        }\n\n        Assert.True(inst.Disposed);\n        Assert.True(inst.B.Disposed);\n        Assert.False(inst.C.Disposed);\n        Assert.True(inst.B.D.Disposed);\n        Assert.False(inst.B.C.Disposed);\n        Assert.False(inst.B.D.C.Disposed);\n        Assert.True(inst.B.D.E.Disposed);\n        Assert.True(inst.B.D.F.Disposed);\n        Assert.False(inst.B.D.E.C.Disposed);\n        Assert.False(inst.B.D.F.C.Disposed);\n\n        Assert.Equal(1, A.Counter);\n        Assert.Equal(1, B.Counter);\n        Assert.Equal(5, C.Counter);\n        Assert.Equal(1, D.Counter);\n        Assert.Equal(1, E.Counter);\n        Assert.Equal(1, F.Counter);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void Ensure_expression_built_correctly_mixed(CompilerType compilerType)\n    {\n        A.Counter = 0;\n        B.Counter = 0;\n        C.Counter = 0;\n        D.Counter = 0;\n        E.Counter = 0;\n        F.Counter = 0;\n\n        A inst = null;\n        {\n            using var container = new StashboxContainer(c =>\n                {\n                    c.WithDisposableTransientTracking().WithCompiler(compilerType);\n                })\n                .Register<A>()\n                .Register<B>()\n                .Register<D>(c => c.WithScopedLifetime())\n                .Register<E>(c => c.WithScopedLifetime())\n                .Register<F>(c => c.WithScopedLifetime())\n                .Register<C>(c => c.WithSingletonLifetime());\n\n            {\n                for (int i = 0; i < 5; i++)\n                {\n                    {\n                        using var scope = container.BeginScope();\n                        for (int j = 0; j < 5; j++)\n                        {\n                            inst = scope.Resolve<A>();\n\n                            Assert.NotNull(inst);\n                            Assert.NotNull(inst.B);\n                            Assert.NotNull(inst.C);\n                            Assert.NotNull(inst.B.D);\n                            Assert.NotNull(inst.B.C);\n                            Assert.NotNull(inst.B.D.C);\n                            Assert.NotNull(inst.B.D.E);\n                            Assert.NotNull(inst.B.D.F);\n                            Assert.NotNull(inst.B.D.E.C);\n                            Assert.NotNull(inst.B.D.F.C);\n\n                            Assert.Same(inst.C, inst.B.C);\n                            Assert.Same(inst.B.C, inst.B.D.C);\n                            Assert.Same(inst.B.D.C, inst.B.D.E.C);\n                            Assert.Same(inst.B.D.E.C, inst.B.D.F.C);\n                        }\n                    }\n\n                    Assert.True(inst.Disposed);\n                    Assert.True(inst.B.Disposed);\n                    Assert.False(inst.C.Disposed);\n                    Assert.True(inst.B.D.Disposed);\n                    Assert.False(inst.B.C.Disposed);\n                    Assert.False(inst.B.D.C.Disposed);\n                    Assert.True(inst.B.D.E.Disposed);\n                    Assert.True(inst.B.D.F.Disposed);\n                    Assert.False(inst.B.D.E.C.Disposed);\n                    Assert.False(inst.B.D.F.C.Disposed);\n                }\n            }\n        }\n\n        Assert.True(inst.Disposed);\n        Assert.True(inst.B.Disposed);\n        Assert.True(inst.C.Disposed);\n        Assert.True(inst.B.D.Disposed);\n        Assert.True(inst.B.C.Disposed);\n        Assert.True(inst.B.D.C.Disposed);\n        Assert.True(inst.B.D.E.Disposed);\n        Assert.True(inst.B.D.F.Disposed);\n        Assert.True(inst.B.D.E.C.Disposed);\n        Assert.True(inst.B.D.F.C.Disposed);\n\n        Assert.Equal(25, A.Counter);\n        Assert.Equal(25, B.Counter);\n        Assert.Equal(1, C.Counter);\n        Assert.Equal(5, D.Counter);\n        Assert.Equal(5, E.Counter);\n        Assert.Equal(5, F.Counter);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void Ensure_expression_built_correctly_singleton_dispose(CompilerType compilerType)\n    {\n        C.Counter = 0;\n        D inst = null;\n        {\n            using var container = new StashboxContainer(c =>\n                {\n                    c.WithDisposableTransientTracking().WithCompiler(compilerType);\n                })\n                .Register<D>(c => c.WithScopedLifetime().DefinesScope())\n                .Register<E>(c => c.WithSingletonLifetime().DefinesScope())\n                .Register<F>(c => c.WithScopedLifetime().DefinesScope())\n                .Register<C>(c => c.WithScopedLifetime());\n\n\n            {\n                using var scope = container.BeginScope();\n                inst = scope.Resolve<D>();\n            }\n\n            Assert.False(inst.E.Disposed);\n        }\n\n        Assert.True(inst.E.Disposed);\n\n        Assert.Equal(3, C.Counter);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void Ensure_expression_built_correctly_singleton_dispose_simple(CompilerType compilerType)\n    {\n        C.Counter = 0;\n        F inst = null;\n        {\n            using var container = new StashboxContainer(c =>\n                {\n                    c.WithDisposableTransientTracking().WithCompiler(compilerType);\n                })\n                .Register<F>(c => c.WithScopedLifetime())\n                .Register<C>(c => c.WithSingletonLifetime());\n\n\n            {\n                using var scope = container.BeginScope();\n                inst = scope.Resolve<F>();\n            }\n\n            Assert.True(inst.Disposed);\n            Assert.False(inst.C.Disposed);\n        }\n\n        Assert.True(inst.C.Disposed);\n\n        Assert.Equal(1, C.Counter);\n    }\n\n    class A : IDisposable\n    {\n        public static int Counter = 0;\n\n        public A(B b, C c)\n        {\n            Interlocked.Increment(ref Counter);\n            B = b;\n            C = c;\n        }\n\n        public B B { get; }\n        public C C { get; }\n\n        public bool Disposed { get; private set; }\n\n        public void Dispose()\n        {\n            if (this.Disposed)\n                throw new ObjectDisposedException(nameof(A));\n\n            this.Disposed = true;\n        }\n    }\n\n    class B : IDisposable\n    {\n        public static int Counter = 0;\n\n        public B(C c, D d)\n        {\n            Interlocked.Increment(ref Counter);\n            C = c;\n            D = d;\n        }\n\n        public C C { get; }\n        public D D { get; }\n\n        public bool Disposed { get; private set; }\n\n        public void Dispose()\n        {\n            if (this.Disposed)\n                throw new ObjectDisposedException(nameof(B));\n\n            this.Disposed = true;\n        }\n    }\n\n    class C : IDisposable\n    {\n        public static int Counter = 0;\n\n        public C()\n        {\n            Interlocked.Increment(ref Counter);\n        }\n\n        public bool Disposed { get; private set; }\n\n        public void Dispose()\n        {\n            if (this.Disposed)\n                throw new ObjectDisposedException(nameof(C));\n\n            this.Disposed = true;\n        }\n    }\n\n    class D : IDisposable\n    {\n        public static int Counter = 0;\n\n        public D(C c, E e, F f)\n        {\n            Interlocked.Increment(ref Counter);\n            C = c;\n            E = e;\n            F = f;\n        }\n\n        public C C { get; }\n        public E E { get; }\n        public F F { get; }\n\n        public bool Disposed { get; private set; }\n\n        public void Dispose()\n        {\n            if (this.Disposed)\n                throw new ObjectDisposedException(nameof(D));\n\n            this.Disposed = true;\n        }\n    }\n\n    class E : IDisposable\n    {\n        public static int Counter = 0;\n\n        public E(C c)\n        {\n            Interlocked.Increment(ref Counter);\n            C = c;\n        }\n\n        public C C { get; }\n\n        public bool Disposed { get; private set; }\n\n        public void Dispose()\n        {\n            if (this.Disposed)\n                throw new ObjectDisposedException(nameof(E));\n\n            this.Disposed = true;\n        }\n    }\n\n    class F : IDisposable\n    {\n        public static int Counter = 0;\n\n        public F(C c)\n        {\n            Interlocked.Increment(ref Counter);\n            C = c;\n        }\n\n        public C C { get; }\n\n        public bool Disposed { get; private set; }\n\n        public void Dispose()\n        {\n            if (this.Disposed)\n                throw new ObjectDisposedException(nameof(F));\n\n            this.Disposed = true;\n        }\n    }\n}"
  },
  {
    "path": "test/IssueTests/77_UnknownType_Resolution_Does_Not_Work.cs",
    "content": "﻿using Stashbox.Exceptions;\nusing System;\nusing Xunit;\n\nnamespace Stashbox.Tests.IssueTests;\n\npublic class UnknownTypeResolutionDoesNotWork\n{\n    [Fact]\n    public void Ensure_Unknown_Type_Resolution_Works_With_Interface()\n    {\n        using var container = new StashboxContainer(c => c.WithUnknownTypeResolution(config =>\n        {\n            if (config.ServiceType == typeof(ITest))\n                config.SetImplementationType(typeof(Test));\n        }));\n\n        var inst = container.Resolve<Test1>();\n\n        Assert.NotNull(inst);\n        Assert.NotNull(inst.Test);\n\n    }\n\n    [Fact]\n    public void Unknown_Type_Resolution_With_Interface_Bad_Implementation()\n    {\n        Assert.Throws<ArgumentException>(() =>\n        {\n            using var container = new StashboxContainer(c => c.WithUnknownTypeResolution(config =>\n            {\n                if (config.ServiceType == typeof(ITest))\n                    config.SetImplementationType(typeof(object));\n            }));\n\n            container.Resolve<Test1>();\n        });\n\n    }\n\n    [Fact]\n    public void Ensures_Registration_Validation_Works()\n    {\n        using var container = new StashboxContainer();\n        Assert.Throws<InvalidRegistrationException>(() => container.Register<ITest>());\n        Assert.Throws<InvalidRegistrationException>(() => container.Register<ITest>(typeof(Test1)));\n    }\n\n    [Fact]\n    public void Ensures_Unknown_Registration_Does_Not_Activate_When_Unresolvable_And_Null_Enabled()\n    {\n        using var container = new StashboxContainer(c => c.WithUnknownTypeResolution(config => { }));\n        Assert.Null(container.ResolveOrDefault<ITest>());\n    }\n\n    [Fact]\n    public void Ensures_Unknown_Registration_Activate_When_Resolvable_And_Null_Enabled()\n    {\n        using var container = new StashboxContainer(c => c.WithUnknownTypeResolution(config =>\n        {\n            if (config.ServiceType == typeof(ITest))\n                config.SetImplementationType(typeof(Test));\n        }));\n        Assert.NotNull(container.ResolveOrDefault<ITest>());\n    }\n\n    interface ITest;\n\n    class Test : ITest;\n\n    class Test1\n    {\n        public Test1(ITest test)\n        {\n            Test = test;\n        }\n\n        public ITest Test { get; }\n    }\n}"
  },
  {
    "path": "test/IssueTests/80_Expected_override_behaviour_not_working_with_scopes.cs",
    "content": "﻿using Xunit;\n\nnamespace Stashbox.Tests.IssueTests;\n\npublic class ExpectedOverrideBehaviourNotWorkingWithScopes\n{\n    [Fact]\n    public void RegisteredInstancesCanBeOverridenViaAFactory()\n    {\n        var container = new StashboxContainer();\n\n        var toInclude = new A { Id = 20 };\n        container.RegisterInstance(toInclude);\n\n        var outer = container.Resolve<A>();\n        A inner1 = null;\n        A inner2 = null;\n        using (var scope = container.BeginScope())\n        {\n            inner1 = scope.Resolve<A>();\n            var toOverride = new A { Id = 30 };\n            scope.PutInstanceInScope(toOverride);\n            inner2 = scope.Resolve<A>();\n        }\n\n        Assert.Equal(toInclude.Id, outer.Id);\n        Assert.Equal(toInclude.Id, inner1.Id);\n        Assert.Equal(30, inner2.Id);\n    }\n\n    class A\n    {\n        public int Id { get; set; }\n    }\n}"
  },
  {
    "path": "test/IssueTests/84_DefinesScope_does_not_work_correctly.cs",
    "content": "﻿using Stashbox.Lifetime;\nusing Xunit;\n\nnamespace Stashbox.Tests.IssueTests;\n\npublic class DefinesScopeDoesNotWorkCorrectly\n{\n    [Fact]\n    public void DefinesScope_does_not_work_correctly()\n    {\n        using var container = new StashboxContainer()\n            .Register<ProductCache>(c => c\n                .DefinesScope()\n                .WithLifetime(Lifetimes.Singleton)\n                .WithoutDisposalTracking())\n            .Register<ProductService>()\n            .RegisterScoped<ProductRepository>();\n\n        var inst = container.Resolve<ProductService>();\n\n        Assert.NotSame(inst.Repo, inst.Cache.Repo);\n    }\n}\n\nclass ProductCache\n{\n    public ProductRepository Repo { get; }\n\n    public ProductCache(ProductRepository repo)\n    {\n        Repo = repo;\n    }\n\n}\n\nclass ProductService\n{\n    public ProductRepository Repo { get; }\n    public ProductCache Cache { get; }\n\n    public ProductService(ProductRepository repo, ProductCache cache)\n    {\n        Repo = repo;\n        Cache = cache;\n    }\n}\n\nclass ProductRepository;"
  },
  {
    "path": "test/IssueTests/88_IdentityServer_not_compatible.cs",
    "content": "﻿using Xunit;\n\nnamespace Stashbox.Tests.IssueTests;\n\npublic class IdentityServerNotCompatible\n{\n    [Fact]\n    public void Ensure_SubGraph_Cache_Not_Messes_Up_The_Graph()\n    {\n        using var container = new StashboxContainer()\n            .Register<TransientRoot>()\n            .Register<TransientProxy>()\n            .RegisterScoped<ScopedProxy>()\n            .RegisterScoped<Scoped>();\n\n        Assert.NotNull(container.Resolve<TransientRoot>());\n    }\n\n    [Fact]\n    public void Ensure_SubGraph_Cache_Not_Messes_Up_The_Graph_2()\n    {\n        using var container = new StashboxContainer()\n            .Register<TransientRoot2>()\n            .Register<TransientProxy>()\n            .RegisterScoped<ScopedProxy>()\n            .RegisterScoped<Scoped>();\n\n        Assert.NotNull(container.Resolve<TransientRoot2>());\n    }\n\n    class TransientRoot2\n    {\n        public TransientRoot2(TransientProxy d, ScopedProxy c)\n        { }\n    }\n\n    class TransientRoot\n    {\n        public TransientRoot(ScopedProxy c, TransientProxy d)\n        { }\n    }\n\n    class TransientProxy\n    {\n        public TransientProxy(Scoped d)\n        { }\n    }\n\n    class Scoped;\n\n    class ScopedProxy\n    {\n        public ScopedProxy(TransientProxy b)\n        {\n\n        }\n    }\n}"
  },
  {
    "path": "test/IssueTests/89_Call_interception.cs",
    "content": "﻿using Castle.DynamicProxy;\nusing System;\nusing Xunit;\n\nnamespace Stashbox.Tests.IssueTests;\n\npublic class CallInterception\n{\n    [Fact]\n    public void Ensure_Expression_Override_Does_Not_Mess_Up_Cache()\n    {\n        var proxyBuilder = new DefaultProxyBuilder();\n\n        using var container = new StashboxContainer().Register<IInterceptor, NoInterceptor>()\n            .RegisterDecorator<ILevel2Service>(proxyBuilder.CreateInterfaceProxyTypeWithTargetInterface(typeof(ILevel2Service), new Type[0], ProxyGenerationOptions.Default))\n            .RegisterDecorator<ILevel2bService>(proxyBuilder.CreateInterfaceProxyTypeWithTargetInterface(typeof(ILevel2bService), new Type[0], ProxyGenerationOptions.Default))\n            .RegisterDecorator<ILevel3Service>(proxyBuilder.CreateInterfaceProxyTypeWithTargetInterface(typeof(ILevel3Service), new Type[0], ProxyGenerationOptions.Default))\n            .RegisterScoped<ILevel1Service, Level1Service>()\n            .RegisterScoped<ILevel2Service, Level2Service>()\n            .RegisterScoped<ILevel2bService, Level2bService>()\n            .RegisterScoped<ILevel3Service, Level3Service>()\n            .RegisterScoped<ILevel4Service, Level4Service>();\n\n        Assert.NotNull(container.Resolve<ILevel2Service>());\n    }\n\n    public interface ILevel1Service;\n\n    public interface ILevel2bService;\n\n    public interface ILevel2Service;\n\n    public interface ILevel3Service;\n\n    public interface ILevel4Service;\n\n    class Level1Service : ILevel1Service\n    {\n        private readonly ILevel2Service level2Service;\n\n        public Level1Service(ILevel2Service level2Service)\n        {\n            this.level2Service = level2Service;\n        }\n    }\n\n    class Level2bService : ILevel2bService\n    {\n        public Level2bService(ILevel3Service level3Service)\n        {\n\n        }\n    }\n\n    class Level2Service : ILevel2Service\n    {\n        public Level2Service(ILevel2bService level2BService, ILevel3Service level3Service)\n        {\n\n        }\n    }\n\n    class Level3Service : ILevel3Service\n    {\n        public Level3Service(ILevel4Service level4Service)\n        {\n\n        }\n    }\n\n    class Level4Service : ILevel4Service\n    {\n        public Level4Service()\n        {\n        }\n    }\n\n    class NoInterceptor : IInterceptor\n    {\n        public void Intercept(IInvocation invocation)\n        {\n\n        }\n    }\n}"
  },
  {
    "path": "test/IssueTests/91_Resolving_with_custom_parameter_values.cs",
    "content": "﻿using Xunit;\n\nnamespace Stashbox.Tests.IssueTests;\n\npublic class ResolvingWithCustomParameterValues\n{\n    [Fact]\n    public void Ensure_Dependency_Override_Works()\n    {\n        var name = \"PAS.LEV\";\n        using var container = new StashboxContainer()\n            .Register<IVariantSubproduct, StainlessSteelPlate>(name);\n\n        var subProduct = new Subproduct();\n        var variant = container.Resolve<IVariantSubproduct>(name, [subProduct]);\n        Assert.NotNull(variant);\n        Assert.Same(subProduct, variant.Subproduct);\n    }\n\n    interface IVariantSubproduct\n    {\n        ISubproduct Subproduct { get; }\n    }\n\n    interface ISubproduct;\n\n    class Subproduct : ISubproduct;\n\n    class VariantSubproduct : IVariantSubproduct\n    {\n        public ISubproduct Subproduct { get; }\n\n        protected VariantSubproduct(ISubproduct subproduct)\n        {\n            Subproduct = subproduct;\n        }\n    }\n\n    class StainlessSteelPlate : VariantSubproduct\n    {\n        public StainlessSteelPlate(ISubproduct subproduct) : base(subproduct) { }\n    }\n}"
  },
  {
    "path": "test/IssueTests/97_Does_Scope_AttachToParent_only_affect_Dispose_behaviour.cs",
    "content": "﻿using System;\nusing Xunit;\n\nnamespace Stashbox.Tests.IssueTests;\n\npublic class DoesScopeAttachToParentOnlyAffectDisposeBehaviour\n{\n    [Fact]\n    public void Test_ScopeGraph_Named_Job_Scopes()\n    {\n        var container = new StashboxContainer()\n            .Register<Cached1>(c => c.InNamedScope(\"A\"))\n            .Register<Cached2>(c => c.InNamedScope(\"A\"))\n            .Register<Job1>(c => c.InNamedScope(\"B\"))\n            .Register<Job2>(c => c.InNamedScope(\"B\"));\n\n        Job1 j1 = null;\n        Job2 j2 = null;\n        {\n            using var a = container.BeginScope(\"A\");\n\n            {\n                using var b = a.BeginScope(\"B\");\n                j1 = b.Resolve<Job1>();\n                j2 = b.Resolve<Job2>();\n            }\n\n            Assert.Same(j1, j2.Job);\n\n            Assert.True(j1.Disposed);\n            Assert.True(j2.Disposed);\n\n            Assert.Same(j1.Cached, j2.Cached1);\n\n            Assert.False(j1.Cached.Disposed);\n            Assert.False(j2.Cached1.Disposed);\n            Assert.False(j2.Cached2.Disposed);\n            Assert.False(j2.Job.Cached.Disposed);\n        }\n\n        Assert.True(j1.Cached.Disposed);\n        Assert.True(j2.Cached1.Disposed);\n        Assert.True(j2.Cached2.Disposed);\n    }\n\n    [Fact]\n    public void Test_ScopeGraph_Nameless_Job_Scopes()\n    {\n        var container = new StashboxContainer()\n            .Register<Cached1>(c => c.InNamedScope(\"A\"))\n            .Register<Cached2>(c => c.InNamedScope(\"A\"))\n            .RegisterScoped<Job1>()\n            .RegisterScoped<Job2>();\n\n        Job1 j1 = null;\n        Job2 j2 = null;\n        {\n            using var a = container.BeginScope(\"A\");\n\n            {\n                using var b = a.BeginScope();\n                j1 = b.Resolve<Job1>();\n                j2 = b.Resolve<Job2>();\n            }\n\n            Assert.Same(j1, j2.Job);\n\n            Assert.True(j1.Disposed);\n            Assert.True(j2.Disposed);\n\n            Assert.Same(j1.Cached, j2.Cached1);\n\n            Assert.False(j1.Cached.Disposed);\n            Assert.False(j2.Cached1.Disposed);\n            Assert.False(j2.Cached2.Disposed);\n            Assert.False(j2.Job.Cached.Disposed);\n        }\n\n        Assert.True(j1.Cached.Disposed);\n        Assert.True(j2.Cached1.Disposed);\n        Assert.True(j2.Cached2.Disposed);\n    }\n}\n\nclass Cached1 : Disposable;\n\nclass Cached2 : Disposable;\n\nclass Job1 : Disposable\n{\n    public Job1(Cached1 cached)\n    {\n        Cached = cached;\n    }\n\n    public Cached1 Cached { get; }\n}\n\nclass Job2 : Disposable\n{\n    public Job2(Job1 job, Cached2 cached2, Cached1 cached1)\n    {\n        Job = job;\n        Cached2 = cached2;\n        Cached1 = cached1;\n    }\n\n    public Job1 Job { get; }\n    public Cached2 Cached2 { get; }\n    public Cached1 Cached1 { get; }\n}\n\nabstract class Disposable : IDisposable\n{\n    public bool Disposed { get; private set; }\n\n    public void Dispose()\n    {\n        if (this.Disposed)\n        {\n            throw new ObjectDisposedException(nameof(Disposable));\n        }\n\n        this.Disposed = true;\n    }\n}"
  },
  {
    "path": "test/IssueTests/98_Replace_doesnt_working_singleton.cs",
    "content": "﻿using Xunit;\n\nnamespace Stashbox.Tests.IssueTests;\n\npublic class ReplaceDoesntWorkingSingleton\n{\n    [Fact]\n    public void Ensure_Replace_Works_With_Singleton()\n    {\n        using var container = new StashboxContainer();\n\n        container.Register<ITest, Test1>(context => context.WithName(\"test\").WithSingletonLifetime());\n\n        var test1 = container.Resolve<ITest>(\"test\");\n\n        Assert.IsType<Test1>(test1);\n\n        container.Register<ITest, Test2>(context => context.WithName(\"test\").ReplaceExisting().WithSingletonLifetime());\n\n        var test2 = container.Resolve<ITest>(\"test\");\n\n        Assert.IsType<Test2>(test2);\n    }\n\n    interface ITest;\n\n    class Test1 : ITest;\n\n    class Test2 : ITest;\n}"
  },
  {
    "path": "test/KeyValueTests.cs",
    "content": "﻿using Stashbox.Configuration;\nusing Stashbox.Exceptions;\nusing Stashbox.Tests.Utils;\nusing System;\nusing System.Collections.Generic;\nusing Xunit;\n\nnamespace Stashbox.Tests;\n\npublic class KeyValueTests\n{\n    [Fact]\n    public void KeyValueTests_NotFound()\n    {\n        var container = new StashboxContainer();\n        container.Register<IT, A>(\"A\");\n\n        Assert.Throws<ResolutionFailedException>(() => container.Resolve<KeyValuePair<string, IT>>(\"A\"));\n    }\n\n    [Fact]\n    public void KeyValueTests_NotFound_Null()\n    {\n        var container = new StashboxContainer();\n        container.Register<IT, A>(\"A\");\n\n        Assert.Equal(default, container.ResolveOrDefault<KeyValuePair<string, IT>>(\"A\"));\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void KeyValueTests_Resolve(CompilerType compilerType)\n    {\n        var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<IT, A>(\"A\");\n        container.Register<IT, B>(\"B\");\n        var a = container.Resolve<KeyValuePair<object, IT>>(\"A\");\n\n        Assert.IsType<A>(a.Value);\n        Assert.Equal(\"A\", a.Key);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void KeyValueTests_Resolve_Wrapped(CompilerType compilerType)\n    {\n        var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<IT, A>(\"A\");\n        container.Register<IT, B>(\"B\");\n        var a = container.Resolve<KeyValuePair<object, Lazy<IT>>>(\"A\");\n\n        Assert.IsType<A>(a.Value.Value);\n        Assert.Equal(\"A\", a.Key);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void KeyValueTests_Resolve_Wrapped_Enumerable(CompilerType compilerType)\n    {\n        var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<IT, A>(\"A\");\n        container.Register<IT, B>(\"B\");\n        var a = container.Resolve<KeyValuePair<object, IT[]>>();\n\n        Assert.IsType<A>(a.Value[0]);\n        Assert.IsType<B>(a.Value[1]);\n        Assert.Null(a.Key);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void KeyValueTests_Resolve_Enumerable(CompilerType compilerType)\n    {\n        var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<IT, A>(\"A\");\n        container.Register<IT, B>(\"B\");\n        var values = container.Resolve<KeyValuePair<object, IT>[]>();\n\n        Assert.Equal(2, values.Length);\n        Assert.IsType<A>(values[0].Value);\n        Assert.Equal(\"A\", values[0].Key);\n        Assert.IsType<B>(values[1].Value);\n        Assert.Equal(\"B\", values[1].Key);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void KeyValueTests_Resolve_Enumerable_Includes_Non_Named(CompilerType compilerType)\n    {\n        var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<IT, A>(\"A\");\n        container.Register<IT, B>();\n        var values = container.Resolve<KeyValuePair<object, IT>[]>();\n\n        Assert.Equal(2, values.Length);\n        Assert.IsType<A>(values[0].Value);\n        Assert.Equal(\"A\", values[0].Key);\n        Assert.IsType<B>(values[1].Value);\n        Assert.Null(values[1].Key);\n    }\n\n    [Fact]\n    public void ReadOnlyKeyValueTests_NotFound()\n    {\n        var container = new StashboxContainer();\n        container.Register<IT, A>(\"A\");\n\n        Assert.Throws<ResolutionFailedException>(() => container.Resolve<ReadOnlyKeyValue<string, IT>>(\"A\"));\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void ReadOnlyKeyValueTests_Resolve(CompilerType compilerType)\n    {\n        var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<IT, A>(\"A\");\n        container.Register<IT, B>(\"B\");\n        var a = container.Resolve<ReadOnlyKeyValue<object, IT>>(\"A\");\n\n        Assert.IsType<A>(a.Value);\n        Assert.Equal(\"A\", a.Key);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void ReadOnlyKeyValueTests_Resolve_Wrapped(CompilerType compilerType)\n    {\n        var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<IT, A>(\"A\");\n        container.Register<IT, B>(\"B\");\n        var a = container.Resolve<ReadOnlyKeyValue<object, Lazy<IT>>>(\"A\");\n\n        Assert.IsType<A>(a.Value.Value);\n        Assert.Equal(\"A\", a.Key);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void ReadOnlyKeyValueTests_Resolve_Wrapped_Enumerable(CompilerType compilerType)\n    {\n        var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<IT, A>(\"A\");\n        container.Register<IT, B>(\"B\");\n        var a = container.Resolve<ReadOnlyKeyValue<object, IT[]>>();\n\n        Assert.IsType<A>(a.Value[0]);\n        Assert.IsType<B>(a.Value[1]);\n        Assert.Null(a.Key);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void ReadOnlyKeyValueTests_Resolve_Enumerable(CompilerType compilerType)\n    {\n        var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<IT, A>(\"A\");\n        container.Register<IT, B>(\"B\");\n        var values = container.Resolve<ReadOnlyKeyValue<object, IT>[]>();\n\n        Assert.Equal(2, values.Length);\n        Assert.IsType<A>(values[0].Value);\n        Assert.Equal(\"A\", values[0].Key);\n        Assert.IsType<B>(values[1].Value);\n        Assert.Equal(\"B\", values[1].Key);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void ReadOnlyKeyValueTests_Resolve_Enumerable_Includes_Non_Named(CompilerType compilerType)\n    {\n        var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<IT, A>(\"A\");\n        container.Register<IT, B>();\n        var values = container.Resolve<ReadOnlyKeyValue<object, IT>[]>();\n\n        Assert.Equal(2, values.Length);\n        Assert.IsType<A>(values[0].Value);\n        Assert.Equal(\"A\", values[0].Key);\n        Assert.IsType<B>(values[1].Value);\n        Assert.Null(values[1].Key);\n    }\n\n    interface IT;\n\n    class A : IT;\n\n    class B : IT;\n}"
  },
  {
    "path": "test/KeyedTests.cs",
    "content": "﻿using System;\nusing System.Linq;\nusing Stashbox.Attributes;\nusing Stashbox.Configuration;\nusing Stashbox.Exceptions;\nusing Stashbox.Resolution;\nusing Stashbox.Tests.IssueTests;\nusing Xunit;\n\nnamespace Stashbox.Tests;\n\npublic class KeyedTests\n{\n    private static object UniversalName = new();\n\n    [Fact]\n    public void ResolveKeyedService()\n    {\n        var service1 = new Service();\n        var service2 = new Service();\n        using var container = new StashboxContainer(config => config\n            .WithDisposableTransientTracking()\n            .WithRegistrationBehavior(Rules.RegistrationBehavior.PreserveDuplications));\n        container.Register<IService>(c => c.WithInstance(service1).WithName(\"service1\").WithSingletonLifetime());\n        container.Register<IService>(c => c.WithInstance(service2).WithName(\"service2\").WithSingletonLifetime());\n\n        Assert.Null(container.ResolveOrDefault<IService>());\n        Assert.Same(service1, container.ResolveOrDefault<IService>(\"service1\"));\n        Assert.Same(service2, container.ResolveOrDefault<IService>(\"service2\"));\n    }\n\n    [Fact]\n    public void ResolveKeyedOpenGenericService()\n    {\n        using var container = new StashboxContainer(config => config\n            .WithDisposableTransientTracking()\n            .WithRegistrationBehavior(Rules.RegistrationBehavior.PreserveDuplications));\n        container.Register(typeof(IFakeOpenGenericService<>), typeof(FakeOpenGenericService<>),\n            c => c.WithName(\"my-service\"));\n        container.RegisterSingleton<IFakeSingletonService, FakeService>();\n\n        // Act\n        var genericService = container.ResolveOrDefault<IFakeOpenGenericService<IFakeSingletonService>>(\"my-service\");\n        var singletonService = container.ResolveOrDefault<IFakeSingletonService>();\n\n        // Assert\n        Assert.Same(singletonService, genericService.Value);\n    }\n\n    [Fact]\n    public void ResolveKeyedServices()\n    {\n        var service1 = new Service();\n        var service2 = new Service();\n        var service3 = new Service();\n        var service4 = new Service();\n        using var container = new StashboxContainer(config => config\n            .WithDisposableTransientTracking()\n            .WithRegistrationBehavior(Rules.RegistrationBehavior.PreserveDuplications));\n        container.Register<IService>(c => c.WithName(\"first-service\").WithInstance(service1).WithSingletonLifetime());\n        container.Register<IService>(c => c.WithName(\"service\").WithInstance(service2).WithSingletonLifetime());\n        container.Register<IService>(c => c.WithName(\"service\").WithInstance(service3).WithSingletonLifetime());\n        container.Register<IService>(c => c.WithName(\"service\").WithInstance(service4).WithSingletonLifetime());\n\n        var firstSvc = container.ResolveAll<IService>(\"first-service\").ToList();\n        Assert.Single(firstSvc);\n        Assert.Same(service1, firstSvc[0]);\n\n        var services = container.ResolveAll<IService>(\"service\").ToList();\n        Assert.Equal(new[] { service2, service3, service4 }, services);\n    }\n\n    [Fact]\n    public void ResolveKeyedGenericServices()\n    {\n        var service1 = new FakeService();\n        var service2 = new FakeService();\n        var service3 = new FakeService();\n        var service4 = new FakeService();\n        using var container = new StashboxContainer(config => config\n            .WithDisposableTransientTracking()\n            .WithRegistrationBehavior(Rules.RegistrationBehavior.PreserveDuplications));\n        container.Register<IFakeOpenGenericService<PocoClass>>(c => c.WithName(\"first-service\")\n            .WithInstance(service1).WithSingletonLifetime());\n        container.Register<IFakeOpenGenericService<PocoClass>>(c => c.WithName(\"service\")\n            .WithInstance(service2).WithSingletonLifetime());\n        container.Register<IFakeOpenGenericService<PocoClass>>(c => c.WithName(\"service\")\n            .WithInstance(service3).WithSingletonLifetime());\n        container.Register<IFakeOpenGenericService<PocoClass>>(c => c.WithName(\"service\")\n            .WithInstance(service4).WithSingletonLifetime());\n\n        var firstSvc = container.ResolveAll<IFakeOpenGenericService<PocoClass>>(\"first-service\").ToList();\n        Assert.Single(firstSvc);\n        Assert.Same(service1, firstSvc[0]);\n\n        var services = container.ResolveAll<IFakeOpenGenericService<PocoClass>>(\"service\").ToList();\n        Assert.Equal(new[] { service2, service3, service4 }, services);\n    }\n\n    [Fact]\n    public void ResolveKeyedServiceSingletonInstance()\n    {\n        var service = new Service();\n        using var container = new StashboxContainer(config => config\n            .WithDisposableTransientTracking()\n            .WithRegistrationBehavior(Rules.RegistrationBehavior.PreserveDuplications));\n        container.Register<IService>(c => c.WithName(\"service1\").WithInstance(service).WithSingletonLifetime());\n\n        Assert.Null(container.ResolveOrDefault<IService>());\n        Assert.Same(service, container.ResolveOrDefault<IService>(\"service1\"));\n    }\n\n    [Fact]\n    public void ResolveKeyedServiceSingletonInstanceWithKeyInjection()\n    {\n        var serviceKey = \"this-is-my-service\";\n        using var container = new StashboxContainer(config => config\n            .WithDisposableTransientTracking()\n            .WithRegistrationBehavior(Rules.RegistrationBehavior.PreserveDuplications));\n        container.RegisterSingleton<IService, Service>(serviceKey);\n\n        Assert.Null(container.ResolveOrDefault<IService>());\n        var svc = container.ResolveOrDefault<IService>(serviceKey);\n        Assert.NotNull(svc);\n        Assert.Equal(serviceKey, svc.ToString());\n    }\n\n    [Fact]\n    public void ResolveKeyedServiceSingletonInstanceWithAnyKey()\n    {\n        using var container = new StashboxContainer(config => config\n            .WithUniversalName(UniversalName)\n            .WithDisposableTransientTracking()\n            .WithRegistrationBehavior(Rules.RegistrationBehavior.PreserveDuplications));\n        container.RegisterSingleton<IService, Service>(UniversalName);\n\n        Assert.Null(container.ResolveOrDefault<IService>());\n\n        var serviceKey1 = \"some-key\";\n        var svc1 = container.ResolveOrDefault<IService>(serviceKey1);\n        Assert.NotNull(svc1);\n        Assert.Equal(serviceKey1, svc1.ToString());\n\n        var serviceKey2 = \"some-other-key\";\n        var svc2 = container.ResolveOrDefault<IService>(serviceKey2);\n        Assert.NotNull(svc2);\n        Assert.Equal(serviceKey2, svc2.ToString());\n    }\n\n    [Fact]\n    public void ResolveKeyedServicesSingletonInstanceWithAnyKey()\n    {\n        var service1 = new FakeService();\n        var service2 = new FakeService();\n\n        using var container = new StashboxContainer(config => config\n            .WithUniversalName(UniversalName)\n            .WithDisposableTransientTracking()\n            .WithRegistrationBehavior(Rules.RegistrationBehavior.PreserveDuplications));\n        container.Register<IFakeOpenGenericService<PocoClass>>(c => c.WithName(UniversalName)\n            .WithInstance(service1).WithSingletonLifetime());\n        container.Register<IFakeOpenGenericService<PocoClass>>(c => c.WithName(\"some-key\")\n            .WithInstance(service2).WithSingletonLifetime());\n\n        var services = container.ResolveAll<IFakeOpenGenericService<PocoClass>>(\"some-key\").ToList();\n        Assert.Equal(new[] { service2 }, services);\n    }\n\n    [Fact]\n    public void ResolveKeyedServiceSingletonInstanceWithKeyedParameter()\n    {\n        using var container = new StashboxContainer(config => config\n            .WithDisposableTransientTracking()\n            .WithRegistrationBehavior(Rules.RegistrationBehavior.PreserveDuplications));\n        container.RegisterSingleton<IService, Service>(\"service1\");\n        container.RegisterSingleton<IService, Service>(\"service2\");\n        container.RegisterSingleton<OtherService>();\n\n        Assert.Null(container.ResolveOrDefault<IService>());\n        var svc = container.ResolveOrDefault<OtherService>();\n        Assert.NotNull(svc);\n        Assert.Equal(\"service1\", svc.Service1.ToString());\n        Assert.Equal(\"service2\", svc.Service2.ToString());\n    }\n\n    [Fact]\n    public void ResolveKeyedServiceSingletonInstanceWithKeyedParameterWithAdditionalAttribute()\n    {\n        using var container = new StashboxContainer(config => config\n            .WithAdditionalDependencyAttribute<AdditionalDependencyAttribute>()\n            .WithAdditionalDependencyNameAttribute<AdditionalNameAttribute>()\n            .WithDisposableTransientTracking()\n            .WithRegistrationBehavior(Rules.RegistrationBehavior.PreserveDuplications));\n        container.RegisterSingleton<IService, Service2>(\"service1\");\n        container.RegisterSingleton<IService, Service2>(\"service2\");\n        container.RegisterSingleton<OtherService2>();\n\n        Assert.Null(container.ResolveOrDefault<IService>());\n        var svc = container.ResolveOrDefault<OtherService2>();\n        Assert.NotNull(svc);\n        Assert.Equal(\"service1\", svc.Service1.ToString());\n        Assert.Equal(\"service2\", svc.Service2.ToString());\n    }\n\n    [Fact]\n    public void ResolveKeyedServiceSingletonFactory()\n    {\n        var service = new Service();\n        using var container = new StashboxContainer(config => config\n            .WithDisposableTransientTracking()\n            .WithRegistrationBehavior(Rules.RegistrationBehavior.PreserveDuplications));\n        container.Register<IService>(c => c.WithName(\"service1\")\n            .WithFactory(() => service).WithSingletonLifetime());\n\n        Assert.Null(container.ResolveOrDefault<IService>());\n        Assert.Same(service, container.ResolveOrDefault<IService>(\"service1\"));\n    }\n\n    [Fact]\n    public void ResolveKeyedServiceSingletonFactoryWithAnyKey()\n    {\n        using var container = new StashboxContainer(config => config\n            .WithUniversalName(UniversalName)\n            .WithDisposableTransientTracking()\n            .WithRegistrationBehavior(Rules.RegistrationBehavior.PreserveDuplications));\n        container.Register<IService>(c => c.WithName(UniversalName)\n            .WithFactory<TypeInformation>(t => new Service((string)t.DependencyName)).WithSingletonLifetime());\n\n        Assert.Null(container.ResolveOrDefault<IService>());\n\n        for (int i = 0; i < 3; i++)\n        {\n            var key = \"service\" + i;\n            var s1 = container.ResolveOrDefault<IService>(key);\n            var s2 = container.ResolveOrDefault<IService>(key);\n            Assert.Same(s1, s2);\n            Assert.Equal(key, s1.ToString());\n        }\n    }\n\n    [Fact]\n    public void ResolveKeyedServiceSingletonType()\n    {\n        using var container = new StashboxContainer(config => config\n            .WithDisposableTransientTracking()\n            .WithRegistrationBehavior(Rules.RegistrationBehavior.PreserveDuplications));\n        container.RegisterSingleton<IService, Service>(\"service1\");\n\n        Assert.Null(container.ResolveOrDefault<IService>());\n        Assert.Equal(typeof(Service), container.ResolveOrDefault<IService>(\"service1\")!.GetType());\n    }\n\n    [Fact]\n    public void ResolveKeyedServiceTransientFactory()\n    {\n        using var container = new StashboxContainer(config => config\n            .WithDisposableTransientTracking()\n            .WithRegistrationBehavior(Rules.RegistrationBehavior.PreserveDuplications));\n        container.Register<IService>(c => c.WithName(\"service1\")\n            .WithFactory<TypeInformation>(t => new Service((string)t.DependencyName)));\n\n        Assert.Null(container.ResolveOrDefault<IService>());\n        var first = container.ResolveOrDefault<IService>(\"service1\");\n        var second = container.ResolveOrDefault<IService>(\"service1\");\n        Assert.NotSame(first, second);\n        Assert.Equal(\"service1\", first.ToString());\n        Assert.Equal(\"service1\", second.ToString());\n    }\n\n    [Fact]\n    public void ResolveKeyedServiceTransientType()\n    {\n        using var container = new StashboxContainer(config => config\n            .WithDisposableTransientTracking()\n            .WithRegistrationBehavior(Rules.RegistrationBehavior.PreserveDuplications));\n        container.Register<IService, Service>(\"service1\");\n\n        Assert.Null(container.ResolveOrDefault<IService>());\n        var first = container.ResolveOrDefault<IService>(\"service1\");\n        var second = container.ResolveOrDefault<IService>(\"service1\");\n        Assert.NotSame(first, second);\n    }\n\n    [Fact]\n    public void ResolveKeyedServiceTransientTypeWithAnyKey()\n    {\n        using var container = new StashboxContainer(config => config\n            .WithUniversalName(UniversalName)\n            .WithDisposableTransientTracking()\n            .WithRegistrationBehavior(Rules.RegistrationBehavior.PreserveDuplications));\n        container.Register<IService, Service>(UniversalName);\n\n        Assert.Null(container.ResolveOrDefault<IService>());\n        var first = container.ResolveOrDefault<IService>(\"service1\");\n        var second = container.ResolveOrDefault<IService>(\"service1\");\n        Assert.NotSame(first, second);\n    }\n\n    [Fact]\n    public void ResolveKeyedServicesAnyKey()\n    {\n        var service1 = new Service();\n        var service2 = new Service();\n        var service3 = new Service();\n        var service4 = new Service();\n        var service5 = new Service();\n        var service6 = new Service();\n        using var container = new StashboxContainer(config => config\n            .WithUniversalName(UniversalName)\n            .WithDisposableTransientTracking()\n            .WithRegistrationBehavior(Rules.RegistrationBehavior.PreserveDuplications));\n        container.Register<IService, Service>(c =>\n            c.WithInstance(service1).WithName(\"first-service\").WithSingletonLifetime());\n        container.Register<IService, Service>(c =>\n            c.WithInstance(service2).WithName(\"service\").WithSingletonLifetime());\n        container.Register<IService, Service>(c =>\n            c.WithInstance(service3).WithName(\"service\").WithSingletonLifetime());\n        container.Register<IService, Service>(c =>\n            c.WithInstance(service4).WithName(\"service\").WithSingletonLifetime());\n        container.Register<IService, Service>(c => c.WithInstance(service5).WithName(null).WithSingletonLifetime());\n        container.Register<IService, Service>(c => c.WithInstance(service6).WithSingletonLifetime());\n\n        // Return all services registered with a non null key\n        var allServices = container.ResolveAll<IService>(UniversalName).ToList();\n        Assert.Equal(4, allServices.Count);\n        Assert.Equal(new[] { service1, service2, service3, service4 }, allServices);\n\n        // Check again (caching)\n        var allServices2 = container.ResolveAll<IService>(UniversalName).ToList();\n        Assert.Equal(allServices, allServices2);\n    }\n\n    [Fact]\n    public void ResolveKeyedServicesAnyKeyWithAnyKeyRegistration()\n    {\n        var service1 = new Service();\n        var service2 = new Service();\n        var service3 = new Service();\n        var service4 = new Service();\n        var service5 = new Service();\n        var service6 = new Service();\n        using var container = new StashboxContainer(config => config\n            .WithUniversalName(UniversalName)\n            .WithDisposableTransientTracking()\n            .WithRegistrationBehavior(Rules.RegistrationBehavior.PreserveDuplications));\n        container.Register<IService, Service>(c => c.WithFactory(() => new Service()).WithName(UniversalName));\n        container.Register<IService, Service>(c =>\n            c.WithInstance(service1).WithName(\"first-service\").WithSingletonLifetime());\n        container.Register<IService, Service>(c =>\n            c.WithInstance(service2).WithName(\"service\").WithSingletonLifetime());\n        container.Register<IService, Service>(c =>\n            c.WithInstance(service3).WithName(\"service\").WithSingletonLifetime());\n        container.Register<IService, Service>(c =>\n            c.WithInstance(service4).WithName(\"service\").WithSingletonLifetime());\n        container.Register<IService, Service>(c => c.WithInstance(service5).WithName(null).WithSingletonLifetime());\n        container.Register<IService, Service>(c => c.WithInstance(service6).WithSingletonLifetime());\n\n        _ = container.Resolve<IService>(\"something-else\");\n        _ = container.Resolve<IService>(\"something-else-again\");\n\n        // Return all services registered with a non null key, but not the one \"created\" with KeyedService.AnyKey\n        var allServices = container.ResolveAll<IService>(UniversalName).ToList();\n        Assert.Equal(5, allServices.Count);\n        Assert.Equal([service1, service2, service3, service4], allServices.Skip(1));\n    }\n\n    [Fact]\n    public void CombinationalRegistration()\n    {\n        Service service1 = new();\n        Service service2 = new();\n        Service keyedService1 = new();\n        Service keyedService2 = new();\n        Service anykeyService1 = new();\n        Service anykeyService2 = new();\n        Service nullkeyService1 = new();\n        Service nullkeyService2 = new();\n        using var container = new StashboxContainer(config => config\n            .WithUniversalName(UniversalName)\n            .WithDisposableTransientTracking()\n            .WithNamedDependencyResolutionForUnNamedRequests(false, false)\n            .OverrideResolutionFailedExceptionWith<InvalidOperationException>()\n            .WithIgnoreServicesWithUniversalNameForUniversalNamedRequests()\n            .WithForceThrowWhenNamedDependencyIsNotResolvable()\n            .WithRegistrationBehavior(Rules.RegistrationBehavior.PreserveDuplications));\n        container.Register<IService, Service>(c => c.WithInstance(service1).WithSingletonLifetime());\n        container.Register<IService, Service>(c => c.WithInstance(service2).WithSingletonLifetime());\n        container.Register<IService, Service>(c =>\n            c.WithInstance(nullkeyService1).WithName(null).WithSingletonLifetime());\n        container.Register<IService, Service>(c =>\n            c.WithInstance(nullkeyService2).WithName(null).WithSingletonLifetime());\n        container.Register<IService, Service>(c =>\n            c.WithInstance(anykeyService1).WithName(UniversalName).WithSingletonLifetime());\n        container.Register<IService, Service>(c =>\n            c.WithInstance(anykeyService2).WithName(UniversalName).WithSingletonLifetime());\n        container.Register<IService, Service>(c =>\n            c.WithInstance(keyedService1).WithName(\"keyedService\").WithSingletonLifetime());\n        container.Register<IService, Service>(c =>\n            c.WithInstance(keyedService2).WithName(\"keyedService\").WithSingletonLifetime());\n\n        Assert.Equal(\n            [service1, service2, nullkeyService1, nullkeyService2],\n            container.ResolveAll<IService>());\n        Assert.Equal(nullkeyService2, container.Resolve<IService>());\n        Assert.Equal(\n            [service1, service2, nullkeyService1, nullkeyService2],\n            container.ResolveAll<IService>());\n        Assert.Equal(nullkeyService2, container.Resolve<IService>());\n        Assert.Equal(\n            [keyedService1, keyedService2],\n            container.ResolveAll<IService>(UniversalName));\n        Assert.Throws<InvalidOperationException>(() => container.Resolve<IService>(UniversalName));\n        Assert.Equal(\n            [keyedService1, keyedService2],\n            container.ResolveAll<IService>(\"keyedService\"));\n        Assert.Equal(keyedService2, container.Resolve<IService>(\"keyedService\"));\n    }\n    \n    [Fact]\n    public void ResolveKeyedServiceWithKeyedParameter_MissingRegistration_FirstParameter()\n    {\n        using var container = new StashboxContainer(config => config\n            .WithUniversalName(UniversalName)\n            .WithDisposableTransientTracking()\n            .WithNamedDependencyResolutionForUnNamedRequests(false, false)\n            .OverrideResolutionFailedExceptionWith<InvalidOperationException>()\n            .WithIgnoreServicesWithUniversalNameForUniversalNamedRequests()\n            .WithForceThrowWhenNamedDependencyIsNotResolvable()\n            .WithRegistrationBehavior(Rules.RegistrationBehavior.PreserveDuplications));\n\n        container.RegisterSingleton<OtherService>();\n        \n        Assert.Null(container.ResolveOrDefault<IService>());\n        Assert.Throws<InvalidOperationException>(container.ResolveOrDefault<OtherService>);\n    }\n    \n    [Fact]\n    public void ResolveKeyedServiceWithKeyedParameter_MissingRegistration_SecondParameter()\n    {\n        using var container = new StashboxContainer(config => config\n            .WithUniversalName(UniversalName)\n            .WithDisposableTransientTracking()\n            .WithNamedDependencyResolutionForUnNamedRequests(false, false)\n            .OverrideResolutionFailedExceptionWith<InvalidOperationException>()\n            .WithIgnoreServicesWithUniversalNameForUniversalNamedRequests()\n            .WithForceThrowWhenNamedDependencyIsNotResolvable()\n            .WithRegistrationBehavior(Rules.RegistrationBehavior.PreserveDuplications));\n\n        container.RegisterSingleton<OtherService>();\n\n        container.RegisterSingleton<IService, Service>(\"service1\");\n\n        Assert.Null(container.ResolveOrDefault<IService>());\n        Assert.Throws<InvalidOperationException>(container.ResolveOrDefault<OtherService>);\n    }\n    \n    [Fact]\n    public void ResolveKeyedServiceWithKeyedParameter_MissingRegistrationButWithUnkeyedService()\n    {\n        using var container = new StashboxContainer(config => config\n            .WithUniversalName(UniversalName)\n            .WithDisposableTransientTracking()\n            .WithNamedDependencyResolutionForUnNamedRequests(false, false)\n            .OverrideResolutionFailedExceptionWith<InvalidOperationException>()\n            .WithIgnoreServicesWithUniversalNameForUniversalNamedRequests()\n            .WithForceThrowWhenNamedDependencyIsNotResolvable()\n            .WithRegistrationBehavior(Rules.RegistrationBehavior.PreserveDuplications));\n\n        container.RegisterSingleton<OtherService>();\n        \n        container.RegisterSingleton<IService, Service>();\n\n        Assert.NotNull(container.ResolveOrDefault<IService>());\n        Assert.Throws<InvalidOperationException>(container.ResolveOrDefault<OtherService>);\n    }\n    \n    [Fact]\n    public void ResolveKeyedServiceSingletonFactoryWithAnyKeyIgnoreWrongType()\n    {\n        using var container = new StashboxContainer(config => config\n            .WithUniversalName(UniversalName)\n            .WithDisposableTransientTracking()\n            .WithNamedDependencyResolutionForUnNamedRequests(false, false)\n            .OverrideResolutionFailedExceptionWith<InvalidOperationException>()\n            .WithIgnoreServicesWithUniversalNameForUniversalNamedRequests()\n            .WithForceThrowWhenNamedDependencyIsNotResolvable()\n            .WithRegistrationBehavior(Rules.RegistrationBehavior.PreserveDuplications));\n        container.Register<IService, ServiceWithIntKey>(UniversalName);\n\n        Assert.Null(container.ResolveOrDefault<IService>());\n        Assert.NotNull(container.ResolveOrDefault<IService>(87));\n        Assert.ThrowsAny<InvalidOperationException>(() => container.ResolveOrDefault<IService>(new object()));\n    }\n\n    [Fact]\n    public void EnsureNamedResolveOrDefaultDoesntThrow()\n    {\n        using var container = new StashboxContainer(config => config\n            .WithUniversalName(UniversalName)\n            .WithDisposableTransientTracking()\n            .WithNamedDependencyResolutionForUnNamedRequests(false, false)\n            .OverrideResolutionFailedExceptionWith<InvalidOperationException>()\n            .WithIgnoreServicesWithUniversalNameForUniversalNamedRequests()\n            .WithForceThrowWhenNamedDependencyIsNotResolvable()\n            .WithRegistrationBehavior(Rules.RegistrationBehavior.PreserveDuplications));\n        \n        Assert.Null(container.ResolveOrDefault<IService>(\"missing\"));\n    }\n\n    private interface IService;\n\n    private class Service([DependencyName] string id) : IService\n    {\n        public Service() : this(Guid.NewGuid().ToString())\n        {\n        }\n\n        public override string ToString() => id;\n    }\n\n    private class Service2([AdditionalName] string id) : IService\n    {\n        public Service2() : this(Guid.NewGuid().ToString())\n        {\n        }\n\n        public override string ToString() => id;\n    }\n\n    private class OtherService(\n        [Dependency(\"service1\")] IService service1,\n        [Dependency(\"service2\")] IService service2)\n    {\n        public IService Service1 { get; } = service1;\n\n        public IService Service2 { get; } = service2;\n    }\n\n    private class OtherService2(\n        [AdditionalDependency(\"service1\")] IService service1,\n        [AdditionalDependency(\"service2\")] IService service2)\n    {\n        public IService Service1 { get; } = service1;\n\n        public IService Service2 { get; } = service2;\n    }\n\n    private class ServiceWithIntKey([DependencyName] int id) : IService\n    {\n        private readonly int id = id;\n    }\n\n    private class AdditionalNameAttribute : Attribute;\n\n    private class AdditionalDependencyAttribute : Attribute\n    {\n        public AdditionalDependencyAttribute(string name)\n        {\n        }\n    }\n}"
  },
  {
    "path": "test/LazyTests.cs",
    "content": "﻿using Stashbox.Exceptions;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing Xunit;\n\nnamespace Stashbox.Tests;\n\npublic class LazyTests\n{\n    [Fact]\n    public void LazyTests_Resolve()\n    {\n        var container = new StashboxContainer();\n        container.Register<ITest, Test>();\n        var inst = container.Resolve<Lazy<ITest>>();\n\n        Assert.NotNull(inst);\n        Assert.False(inst.IsValueCreated);\n        Assert.IsType<Lazy<ITest>>(inst);\n        Assert.IsType<Test>(inst.Value);\n    }\n\n    [Fact]\n    public void LazyTests_Resolve_Null()\n    {\n        var container = new StashboxContainer();\n        var inst = container.ResolveOrDefault<Lazy<ITest>>();\n\n        Assert.Null(inst);\n    }\n\n    [Fact]\n    public void LazyTests_Resolve_Func()\n    {\n        var container = new StashboxContainer();\n        container.Register<ITest, Test>();\n        var inst = container.Resolve<Lazy<Func<ITest>>>();\n\n        Assert.NotNull(inst);\n        Assert.False(inst.IsValueCreated);\n        Assert.IsType<Lazy<Func<ITest>>>(inst);\n        Assert.IsType<Test>(inst.Value());\n    }\n\n    [Fact]\n    public void LazyTests_Resolve_Func_Param()\n    {\n        var container = new StashboxContainer();\n        container.Register<ITest2, Test3>();\n        var inst = container.Resolve<Lazy<Func<int, Lazy<ITest2>>>>();\n\n        Assert.NotNull(inst);\n        Assert.False(inst.IsValueCreated);\n        Assert.IsType<Lazy<Func<int, Lazy<ITest2>>>>(inst);\n        Assert.IsType<Test3>(inst.Value(5).Value);\n        Assert.Equal(5, inst.Value(5).Value.T);\n    }\n\n    [Fact]\n    public void LazyTests_Resolve_Func_Null()\n    {\n        var container = new StashboxContainer();\n        var inst = container.ResolveOrDefault<Lazy<Func<ITest>>>();\n\n        Assert.Null(inst);\n    }\n\n    [Fact]\n    public void LazyTests_Resolve_Enumerable()\n    {\n        var container = new StashboxContainer();\n        container.Register<ITest, Test>();\n        var inst = container.Resolve<Lazy<IEnumerable<ITest>>>();\n\n        Assert.NotNull(inst);\n        Assert.False(inst.IsValueCreated);\n        Assert.IsType<Lazy<IEnumerable<ITest>>>(inst);\n        Assert.IsType<Test>(inst.Value.First());\n    }\n\n    [Fact]\n    public void LazyTests_Resolve_Enumerable_Null()\n    {\n        var container = new StashboxContainer();\n        var inst = container.Resolve<Lazy<IEnumerable<ITest>>>();\n\n        Assert.Empty(inst.Value);\n    }\n\n    [Fact]\n    public void LazyTests_Resolve_ConstructorDependency()\n    {\n        var container = new StashboxContainer();\n        container.Register<ITest, Test>();\n        container.Register<Test2>();\n        var inst = container.Resolve<Test2>();\n\n        Assert.NotNull(inst.Test);\n        Assert.False(inst.Test.IsValueCreated);\n        Assert.IsType<Lazy<ITest>>(inst.Test);\n        Assert.IsType<Test>(inst.Test.Value);\n    }\n\n    [Fact]\n    public void LazyTests_Resolve_ConstructorDependency_Null()\n    {\n        var container = new StashboxContainer();\n        container.Register<Test2>();\n        var inst = container.ResolveOrDefault<Test2>();\n\n        Assert.Null(inst);\n    }\n\n    [Fact]\n    public void LazyTests_Resolve_Circular_Evaluate()\n    {\n        var container = new StashboxContainer();\n\n        container.Register<Circular1>();\n        container.Register<Circular2>();\n\n        Assert.Throws<ResolutionFailedException>(container.Resolve<Circular1>);\n    }\n\n    [Fact]\n    public void LazyTests_Resolve_Circular_Evaluate_Singleton()\n    {\n        var container = new StashboxContainer();\n\n        container.RegisterSingleton<Circular1>();\n        container.RegisterSingleton<Circular2>();\n\n        Assert.Throws<ResolutionFailedException>(container.Resolve<Circular1>);\n    }\n\n    interface ITest;\n\n    class Test : ITest;\n\n    interface ITest2\n    {\n        int T { get; }\n    }\n\n    class Test3 : ITest2\n    {\n        public Test3(int t)\n        {\n            this.T = t;\n        }\n\n        public int T { get; }\n    }\n\n    class Test2\n    {\n        public Lazy<ITest> Test { get; }\n\n        public Test2(Lazy<ITest> test)\n        {\n            this.Test = test;\n        }\n    }\n\n    class Circular1\n    {\n        public Lazy<Circular2> Dep { get; set; }\n\n        public Circular1(Lazy<Circular2> dep)\n        {\n            Dep = dep;\n        }\n    }\n\n    class Circular2\n    {\n        public Lazy<Circular1> Dep { get; set; }\n\n        public Circular2(Lazy<Circular1> dep)\n        {\n            Dep = dep;\n        }\n    }\n\n    class Circular3\n    {\n        public IEnumerable<Lazy<Circular4>> Dep { get; set; }\n\n        public Circular3(IEnumerable<Lazy<Circular4>> dep)\n        {\n            Dep = dep;\n        }\n    }\n\n    class Circular4\n    {\n        public IEnumerable<Lazy<Circular3>> Dep { get; set; }\n\n        public Circular4(IEnumerable<Lazy<Circular3>> dep)\n        {\n            Dep = dep;\n        }\n    }\n}"
  },
  {
    "path": "test/LifetimeTests.cs",
    "content": "﻿using Stashbox.Configuration;\nusing Stashbox.Exceptions;\nusing Stashbox.Lifetime;\nusing Stashbox.Tests.Utils;\nusing Stashbox.Utils;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing Xunit;\n\nnamespace Stashbox.Tests;\n\npublic class LifetimeTests\n{\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void LifetimeTests_Resolve(CompilerType compilerType)\n    {\n        using IStashboxContainer container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.RegisterSingleton<ITest1, Test1>();\n        container.Register<ITest2, Test2>();\n        container.Register<ITest3, Test3>();\n\n        var test1 = container.Resolve<ITest1>();\n        test1.Name = \"test1\";\n        var test2 = container.Resolve<ITest2>();\n        var test3 = container.Resolve<ITest3>();\n\n        Assert.NotNull(test1);\n        Assert.NotNull(test2);\n        Assert.NotNull(test3);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void LifetimeTests_Resolve_Parallel(CompilerType compilerType)\n    {\n        using IStashboxContainer container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.RegisterSingleton(typeof(ITest1), typeof(Test1));\n        container.Register<ITest2, Test2>();\n        container.Register<ITest3, Test3>();\n\n        Parallel.For(0, 50000, (i) =>\n        {\n            var test1 = container.Resolve<ITest1>();\n            test1.Name = \"test1\";\n            var test2 = container.Resolve<ITest2>();\n            var test3 = container.Resolve<ITest3>();\n\n            Assert.NotNull(test1);\n            Assert.NotNull(test2);\n            Assert.NotNull(test3);\n        });\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void LifetimeTests_Resolve_Parallel_Lazy(CompilerType compilerType)\n    {\n        using IStashboxContainer container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<ITest1, Test1>(context => context.WithSingletonLifetime());\n        container.Register<ITest2, Test2>();\n        container.Register<ITest3, Test3>();\n\n        Parallel.For(0, 50000, (i) =>\n        {\n            var test1 = container.Resolve<Lazy<ITest1>>();\n            test1.Value.Name = \"test1\";\n            var test2 = container.Resolve<Lazy<ITest2>>();\n            var test3 = container.Resolve<Lazy<ITest3>>();\n\n            Assert.NotNull(test1.Value);\n            Assert.NotNull(test2.Value);\n            Assert.NotNull(test3.Value);\n        });\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void LifetimeTests_Scoped_WithNull(CompilerType compilerType)\n    {\n        using IStashboxContainer container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.RegisterScoped<Test6>();\n\n        Assert.Null(container.BeginScope().ResolveOrDefault<Test6>());\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void LifetimeTests_DefinesScope_Generic(CompilerType compilerType)\n    {\n        using IStashboxContainer container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<Test6>();\n        container.Register<Test7>(c => c.DefinesScope());\n        container.RegisterScoped<Test5>();\n\n        using var scope = container.BeginScope();\n\n        var inst1 = scope.Resolve<Test6>();\n        var inst2 = scope.Resolve<Test7>();\n\n        Assert.NotSame(inst1.Test5, inst2.Test5);\n        Assert.Same(inst2.Test5, inst2.Test6.Test5);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void LifetimeTests_DefinesScope(CompilerType compilerType)\n    {\n        using IStashboxContainer container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<Test6>();\n        container.Register(typeof(Test7), c => c.DefinesScope());\n        container.RegisterScoped<Test5>();\n\n        using var scope = container.BeginScope();\n\n        var inst1 = scope.Resolve<Test6>();\n        var inst2 = scope.Resolve<Test7>();\n\n        Assert.NotSame(inst1.Test5, inst2.Test5);\n        Assert.Same(inst2.Test5, inst2.Test6.Test5);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void LifetimeTests_Per_Request(CompilerType compilerType)\n    {\n        using IStashboxContainer container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<Test5>(c => c.WithPerRequestLifetime());\n        container.Register<Test6>();\n        container.Register<Test7>();\n\n        var inst = container.Resolve<Test7>();\n        var t5 = container.Resolve<Test5>();\n\n        Assert.NotNull(inst.Test5);\n        Assert.NotNull(inst.Test6.Test5);\n        Assert.Same(inst.Test5, inst.Test6.Test5);\n        Assert.NotSame(t5, inst.Test5);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void LifetimeTests_Per_Request_WithScope(CompilerType compilerType)\n    {\n        using IStashboxContainer container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<Test5>(c => c.WithPerRequestLifetime());\n        container.Register<Test6>(c => c.WithScopedLifetime());\n        container.Register<Test7>();\n\n        using var scope = container.BeginScope();\n\n        var inst = scope.Resolve<Test7>();\n        var t5 = scope.Resolve<Test5>();\n\n        Assert.NotNull(inst.Test5);\n        Assert.NotNull(inst.Test6.Test5);\n        Assert.Same(inst.Test5, inst.Test6.Test5);\n        Assert.NotSame(t5, inst.Test5);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void LifetimeTests_Per_Request_Enumerable(CompilerType compilerType)\n    {\n        using IStashboxContainer container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<Test5>(c => c.WithPerRequestLifetime());\n        container.Register<Test6>();\n        container.Register<Test7>();\n\n        var inst = container.ResolveAll<Test7>().First();\n        var t5 = container.ResolveAll<Test5>().First();\n\n        Assert.NotNull(inst.Test5);\n        Assert.NotNull(inst.Test6.Test5);\n        Assert.Same(inst.Test5, inst.Test6.Test5);\n        Assert.NotSame(t5, inst.Test5);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void LifetimeTests_Per_Request_Wrapper_Enumerable(CompilerType compilerType)\n    {\n        using IStashboxContainer container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<Test5>(c => c.WithPerRequestLifetime());\n        container.Register<Test6>();\n        container.Register<Test9>();\n\n        var inst = container.Resolve<Test9>();\n        var t5 = container.Resolve<Test5>();\n\n        Assert.NotNull(inst.Test5);\n        Assert.NotNull(inst.Test6.Test5);\n        Assert.Same(inst.Test5.First(), inst.Test6.Test5);\n        Assert.NotSame(t5, inst.Test5.First());\n    }\n\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void LifetimeTests_Per_Request_Wrapper_Lazy(CompilerType compilerType)\n    {\n        using IStashboxContainer container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<Test5>(c => c.WithPerRequestLifetime());\n        container.Register<Test6>();\n        container.Register<Test10>();\n\n        var inst = container.Resolve<Test10>();\n        var t5 = container.Resolve<Test5>();\n\n        Assert.NotNull(inst.Test5);\n        Assert.NotNull(inst.Test6.Test5);\n        Assert.Same(inst.Test5.Value, inst.Test6.Test5);\n        Assert.NotSame(t5, inst.Test5.Value);\n    }\n\n    [Theory]\n    [InlineData(true)]\n    [InlineData(false)]\n    public void LifetimeTests_Shorter_Lifetime_Not_Resolvable_From_Longer_Direct(bool enabledValidation)\n    {\n        using IStashboxContainer container = new StashboxContainer(c =>\n        {\n            if (enabledValidation)\n                c.WithLifetimeValidation();\n        });\n        container.RegisterSingleton<Test6>();\n        container.RegisterScoped<Test5>();\n\n        using var scope = container.BeginScope();\n\n        if (enabledValidation)\n        {\n            var exception = Assert.Throws<LifetimeValidationFailedException>(() => scope.Resolve<Test6>());\n            Assert.Equal(typeof(Test5), exception.Type);\n            Assert.Contains(\"The life-span of\", exception.Message);\n        }\n        else\n        {\n            Assert.NotNull(scope.Resolve<Test6>());\n        }\n    }\n\n    [Fact]\n    public void LifetimeTests_Named_Scope_Lifetime_Not_Resolvable_From_Longer_Direct()\n    {\n        using IStashboxContainer container = new StashboxContainer(c => c.WithLifetimeValidation());\n        container.RegisterSingleton<Test6>();\n        container.Register<Test5>(c => c.WithLifetime(Lifetimes.NamedScope(\"A\")));\n\n        using var scope = container.BeginScope(\"A\");\n\n        var exception = Assert.Throws<LifetimeValidationFailedException>(() => scope.Resolve<Test6>());\n        Assert.Equal(typeof(Test5), exception.Type);\n        Assert.Contains(\"The life-span of\", exception.Message);\n    }\n\n    [Fact]\n    public void LifetimeTests_Named_Scope_Lifetime_Not_Resolvable_From_Singleton()\n    {\n        using IStashboxContainer container = new StashboxContainer();\n        container.RegisterSingleton<Test6>();\n        container.Register<Test5>(c => c.WithLifetime(Lifetimes.NamedScope(\"A\")));\n\n        using var scope = container.BeginScope(\"A\");\n\n        var exception = Assert.Throws<ResolutionFailedException>(() => scope.Resolve<Test6>());\n        Assert.Equal(typeof(Test5), exception.Type);\n        Assert.Contains(\"The scope 'A' was not found to resolve\", exception.Message);\n    }\n\n    [Theory]\n    [InlineData(true)]\n    [InlineData(false)]\n    public void LifetimeTests_Shorter_Lifetime_Not_Resolvable_From_Longer_InDirect(bool enabledValidation)\n    {\n        using IStashboxContainer container = new StashboxContainer(c =>\n        {\n            if (enabledValidation)\n                c.WithLifetimeValidation();\n        });\n        container.RegisterSingleton<Test8>();\n        container.Register<Test6>();\n        container.RegisterScoped<Test5>();\n\n        using var scope = container.BeginScope();\n\n        if (enabledValidation)\n        {\n            var exception = Assert.Throws<LifetimeValidationFailedException>(() => scope.Resolve<Test8>());\n            Assert.Equal(typeof(Test5), exception.Type);\n            Assert.Contains(\"The life-span of\", exception.Message);\n        }\n        else\n        {\n            Assert.NotNull(scope.Resolve<Test8>());\n        }\n    }\n\n    [Fact]\n    public void LifetimeTests_Named_Scope_Lifetime_Not_Resolvable_From_Longer_InDirect()\n    {\n        using IStashboxContainer container = new StashboxContainer(c => c.WithLifetimeValidation());\n        container.RegisterSingleton<Test8>();\n        container.Register<Test6>();\n        container.Register<Test5>(c => c.InNamedScope(\"A\"));\n\n        using var scope = container.BeginScope(\"A\");\n\n        var exception = Assert.Throws<LifetimeValidationFailedException>(() => scope.Resolve<Test8>());\n        Assert.Equal(typeof(Test5), exception.Type);\n        Assert.Contains(\"The life-span of\", exception.Message);\n    }\n\n    [Theory]\n    [InlineData(true)]\n    [InlineData(false)]\n    public void LifetimeTests_Scoped_Is_Not_Resolvable_From_Root_Direct(bool enabledValidation)\n    {\n        using IStashboxContainer container = new StashboxContainer(c =>\n        {\n            if (enabledValidation)\n                c.WithLifetimeValidation();\n        });\n\n        container.RegisterScoped<Test5>();\n\n        if (enabledValidation)\n        {\n            var exception = Assert.Throws<LifetimeValidationFailedException>(() => container.Resolve<Test5>());\n            Assert.Equal(typeof(Test5), exception.Type);\n            Assert.Contains(\"from the root scope\", exception.Message);\n        }\n        else\n        {\n            Assert.NotNull(container.Resolve<Test5>());\n        }\n    }\n\n    [Fact]\n    public void LifetimeTests_Named_Scoped_Is_Not_Resolvable_From_Root_Direct()\n    {\n        using IStashboxContainer container = new StashboxContainer();\n        container.Register<Test5>(c => c.InNamedScope(\"A\"));\n\n        Assert.Throws<ResolutionFailedException>(() => container.Resolve<Test5>());\n    }\n\n    [Theory]\n    [InlineData(true)]\n    [InlineData(false)]\n    public void LifetimeTests_Scoped_Is_Not_Resolvable_From_Root_InDirect(bool enabledValidation)\n    {\n        using IStashboxContainer container = new StashboxContainer(c =>\n        {\n            if (enabledValidation)\n                c.WithLifetimeValidation();\n        });\n\n        container.Register<Test6>();\n        container.RegisterScoped<Test5>();\n\n        if (enabledValidation)\n        {\n            var exception = Assert.Throws<LifetimeValidationFailedException>(() => container.Resolve<Test6>());\n            Assert.Equal(typeof(Test5), exception.Type);\n            Assert.Contains(\"from the root scope\", exception.Message);\n        }\n        else\n        {\n            Assert.NotNull(container.Resolve<Test6>());\n        }\n    }\n\n    [Theory]\n    [InlineData(true)]\n    [InlineData(false)]\n    public void LifetimeTests_Scoped_Is_Not_Resolvable_From_Root_AfterResolved(bool enabledValidation)\n    {\n        using IStashboxContainer container = new StashboxContainer(c =>\n        {\n            if (enabledValidation)\n                c.WithLifetimeValidation();\n        });\n\n        container.Register<Test6>();\n        container.RegisterScoped<Test5>();\n\n        if (enabledValidation)\n        {\n            using var scope = container.BeginScope();\n            scope.Resolve<Test6>();\n            var exception = Assert.Throws<LifetimeValidationFailedException>(() => container.Resolve<Test6>());\n            Assert.Equal(typeof(Test5), exception.Type);\n            Assert.Contains(\"from the root scope\", exception.Message);\n        }\n        else\n        {\n            using var scope = container.BeginScope();\n            scope.Resolve<Test6>();\n            Assert.NotNull(container.Resolve<Test6>());\n        }\n    }\n\n    [Fact]\n    public void LifetimeTests_Named_Scoped_Is_Not_Resolvable_From_Root_AfterResolved()\n    {\n        using IStashboxContainer container = new StashboxContainer();\n\n        container.Register<Test6>();\n        container.Register<Test5>(c => c.InNamedScope(\"A\"));\n\n        using var scope = container.BeginScope(\"A\");\n        scope.Resolve<Test6>();\n        var exception = Assert.Throws<ResolutionFailedException>(() => container.Resolve<Test6>());\n        Assert.Equal(typeof(Test6), exception.Type);\n        Assert.Contains(\"found with unresolvable parameter\", exception.Message);\n    }\n\n    [Fact]\n    public void LifetimeTests_PerRequest_With_Singleton()\n    {\n        using IStashboxContainer container = new StashboxContainer();\n\n        container.Register<Test6>(c => c.WithSingletonLifetime());\n        container.Register<Test5>(c => c.WithPerRequestLifetime());\n        container.Register<Test7>();\n\n        var inst = container.Resolve<Test7>();\n\n        Assert.Same(inst.Test5, inst.Test6.Test5);\n    }\n    \n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void LifetimeTests_AutoLifetime(CompilerType compilerType)\n    {\n        using IStashboxContainer container = new StashboxContainer(c => c.WithCompiler(compilerType));\n\n        container.Register<Test6>();\n        container.Register<Test5>(c => c.WithSingletonLifetime());\n        container.Register<Test8>(c => c.WithAutoLifetime(Lifetimes.Singleton));\n\n        Assert.Same(container.Resolve<Test8>(), container.Resolve<Test8>());\n    }\n    \n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void LifetimeTests_AutoLifetime_Scoped(CompilerType compilerType)\n    {\n        using IStashboxContainer container = new StashboxContainer(c => c.WithCompiler(compilerType));\n\n        container.Register<Test6>();\n        container.Register<Test5>(c => c.WithSingletonLifetime());\n        container.Register<Test8>(c => c.WithAutoLifetime(Lifetimes.Scoped));\n\n        Assert.NotSame(container.BeginScope().Resolve<Test8>(), container.BeginScope().Resolve<Test8>());\n\n        var scope = container.BeginScope();\n        Assert.Same(scope.Resolve<Test8>(), scope.Resolve<Test8>());\n    }\n    \n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void LifetimeTests_AutoLifetime_Transient(CompilerType compilerType)\n    {\n        using IStashboxContainer container = new StashboxContainer(c => c.WithCompiler(compilerType));\n\n        container.Register<Test6>();\n        container.Register<Test5>(c => c.WithSingletonLifetime());\n        container.Register<Test8>(c => c.WithAutoLifetime(Lifetimes.Transient));\n\n        Assert.NotSame(container.Resolve<Test8>(), container.Resolve<Test8>());\n    }\n    \n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void LifetimeTests_AutoLifetime_Remains_Transient(CompilerType compilerType)\n    {\n        using IStashboxContainer container = new StashboxContainer(c => c.WithCompiler(compilerType));\n\n        container.Register<Test6>();\n        container.Register<Test5>();\n        container.Register<Test8>(c => c.WithAutoLifetime(Lifetimes.Singleton));\n\n        Assert.NotSame(container.Resolve<Test8>(), container.Resolve<Test8>());\n    }\n    \n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void LifetimeTests_AutoLifetime_Without_Dependency(CompilerType compilerType)\n    {\n        using IStashboxContainer container = new StashboxContainer(c => c.WithCompiler(compilerType));\n\n        container.Register<Test5>(c => c.WithAutoLifetime(Lifetimes.Singleton));\n\n        Assert.NotSame(container.Resolve<Test5>(), container.Resolve<Test5>());\n    }\n    \n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void LifetimeTests_Singleton_Recursive(CompilerType compilerType)\n    {\n        using IStashboxContainer container = new StashboxContainer(c => c.WithCompiler(compilerType));\n\n        container.RegisterSingleton<Test11>();\n\n        var ex = Assert.Throws<ResolutionFailedException>(container.Resolve<Test11>);\n        Assert.Contains(\"Circular dependency was detected while resolving\", ex.Message);\n    }\n    \n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void LifetimeTests_Singleton_Subsequent_Calls_Get_The_Same_Exception(CompilerType compilerType)\n    {\n        using IStashboxContainer container = new StashboxContainer(c => c.WithCompiler(compilerType));\n\n        container.RegisterSingleton<Test12>();\n\n        var ex = Assert.Throws<ResolutionFailedException>(container.Resolve<Test12>);\n        Assert.Contains(\"Service is not registered properly or unresolvable type requested.\", ex.Message);\n        \n        ex = Assert.Throws<ResolutionFailedException>(container.Resolve<Test12>);\n        Assert.Contains(\"Service is not registered properly or unresolvable type requested.\", ex.Message);\n    }\n\n    interface ITest1 { string Name { get; set; } }\n\n    interface ITest2 { string Name { get; set; } }\n\n    interface ITest3 { string Name { get; set; } }\n\n    class Test1 : ITest1\n    {\n        public string Name { get; set; }\n    }\n\n    class Test2 : ITest2\n    {\n        public ITest1 Test1 { get; }\n        public string Name { get; set; }\n\n        public Test2(ITest1 test1)\n        {\n            Test1 = test1;\n            Shield.EnsureNotNull(test1, nameof(test1));\n            Shield.EnsureNotNullOrEmpty(test1.Name, nameof(test1.Name));\n            Shield.EnsureTypeOf<Test1>(test1);\n        }\n    }\n\n    class Test3 : ITest3\n    {\n        public ITest1 Test1 { get; }\n        public ITest2 Test2 { get; }\n        public string Name { get; set; }\n\n        public Test3(ITest1 test1, ITest2 test2)\n        {\n            Test1 = test1;\n            Test2 = test2;\n            Shield.EnsureNotNull(test1, nameof(test1));\n            Shield.EnsureNotNull(test2, nameof(test2));\n            Shield.EnsureNotNullOrEmpty(test1.Name, nameof(test1.Name));\n\n            Shield.EnsureTypeOf<Test1>(test1);\n            Shield.EnsureTypeOf<Test2>(test2);\n        }\n    }\n\n    class Test4\n    {\n        public static bool IsConstructed;\n\n        public Test4()\n        {\n            if (IsConstructed)\n                throw new InvalidOperationException();\n\n            IsConstructed = true;\n        }\n    }\n\n    class Test5;\n\n    class Test6\n    {\n        public Test5 Test5 { get; }\n\n        public Test6(Test5 test5)\n        {\n            Test5 = test5;\n        }\n    }\n\n    class Test7\n    {\n        public Test5 Test5 { get; }\n        public Test6 Test6 { get; }\n\n        public Test7(Test5 test5, Test6 test6)\n        {\n            Test5 = test5;\n            Test6 = test6;\n        }\n    }\n\n    class Test8\n    {\n        public Test6 Test6 { get; }\n\n        public Test8(Test6 test6)\n        {\n            Test6 = test6;\n        }\n    }\n\n    class Test9\n    {\n        public IEnumerable<Test5> Test5 { get; }\n        public Test6 Test6 { get; }\n\n        public Test9(IEnumerable<Test5> test5, Test6 test6)\n        {\n            Test5 = test5;\n            Test6 = test6;\n        }\n    }\n\n    class Test10\n    {\n        public Lazy<Test5> Test5 { get; }\n        public Test6 Test6 { get; }\n\n        public Test10(Lazy<Test5> test5, Test6 test6)\n        {\n            Test5 = test5;\n            Test6 = test6;\n        }\n    }\n    \n    class Test11\n    {\n        public Test11(IDependencyResolver resolver)\n        {\n            resolver.Resolve<Test11>();\n        }\n    }\n    \n    class Test12\n    {\n        public Test12(IDependencyResolver resolver)\n        {\n            resolver.Resolve<Test11>();\n        }\n    }\n}"
  },
  {
    "path": "test/MetadataTests.cs",
    "content": "﻿using Stashbox.Configuration;\nusing Stashbox.Tests.Utils;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing Xunit;\n\nnamespace Stashbox.Tests;\n\npublic class MetadataTests\n{\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void TupleTests_Resolve(CompilerType compilerType)\n    {\n        var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        var meta = new object();\n        container.Register<ITest, Test>(c => c.WithMetadata(meta));\n        var inst = container.Resolve<Tuple<ITest, object>>();\n\n        Assert.NotNull(inst);\n        Assert.IsType<Tuple<ITest, object>>(inst);\n        Assert.IsType<Test>(inst.Item1);\n        Assert.Same(inst.Item2, meta);\n    }\n\n    [Fact]\n    public void TupleTests_Resolve_Null()\n    {\n        var container = new StashboxContainer();\n        var inst = container.ResolveOrDefault<Tuple<ITest, object>>();\n\n        Assert.Null(inst);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void TupleTests_Resolve_Lazy(CompilerType compilerType)\n    {\n        var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        var meta = new object();\n        container.Register<ITest, Test>(c => c.WithMetadata(meta));\n        var inst = container.Resolve<Tuple<Lazy<ITest>, object>>();\n\n        Assert.NotNull(inst);\n        Assert.IsType<Tuple<Lazy<ITest>, object>>(inst);\n        Assert.IsType<Test>(inst.Item1.Value);\n        Assert.Same(inst.Item2, meta);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void TupleTests_Resolve_Func(CompilerType compilerType)\n    {\n        var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        var meta = new object();\n        container.Register<ITest, Test>(c => c.WithMetadata(meta));\n        var inst = container.Resolve<Tuple<Func<ITest>, object>>();\n\n        Assert.NotNull(inst);\n        Assert.IsType<Tuple<Func<ITest>, object>>(inst);\n        Assert.IsType<Test>(inst.Item1());\n        Assert.Same(inst.Item2, meta);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void TupleTests_Resolve_Enumerable(CompilerType compilerType)\n    {\n        var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        var meta = new object();\n        container.Register<ITest, Test>(c => c.WithMetadata(meta));\n        var inst = container.Resolve<IEnumerable<Tuple<ITest, object>>>();\n\n        Assert.NotNull(inst);\n        Assert.IsAssignableFrom<IEnumerable<Tuple<ITest, object>>>(inst);\n        Assert.IsType<Test>(inst.First().Item1);\n        Assert.Same(inst.First().Item2, meta);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void TupleTests_Resolve_Enumerable_ShouldNull(CompilerType compilerType)\n    {\n        var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        var meta = new object();\n        container.Register<ITest, Test>(c => c.WithMetadata(meta));\n        var inst = container.Resolve<Tuple<IEnumerable<ITest>, object>>();\n\n        Assert.NotNull(inst);\n        Assert.IsType<Tuple<IEnumerable<ITest>, object>>(inst);\n        Assert.IsType<Test>(inst.Item1.First());\n        Assert.Null(inst.Item2);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void TupleTests_Resolve_Constructor(CompilerType compilerType)\n    {\n        var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        var meta = new object();\n        container.Register<ITest, Test>(c => c.WithMetadata(meta));\n        container.Register<Test2>();\n        var inst = container.Resolve<Test2>();\n\n        Assert.NotNull(inst);\n        Assert.IsType<Tuple<ITest, object>>(inst.Test);\n        Assert.IsType<Test>(inst.Test.Item1);\n        Assert.Same(inst.Test.Item2, meta);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void TupleTests_Resolve_Custom_Meta(CompilerType compilerType)\n    {\n        var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        ITest1 meta = new Test1();\n        container.Register<ITest, Test>(c => c.WithMetadata(meta));\n        var inst = container.Resolve<Tuple<ITest, ITest1>>();\n\n        Assert.NotNull(inst);\n        Assert.IsType<Tuple<ITest, ITest1>>(inst);\n        Assert.IsType<Test>(inst.Item1);\n        Assert.Same(inst.Item2, meta);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void TupleTests_Resolve_Custom_Meta_Implementation_Type(CompilerType compilerType)\n    {\n        var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        Test1 meta = new Test1();\n        container.Register<ITest, Test>(c => c.WithMetadata(meta));\n        var inst = container.Resolve<Tuple<ITest, ITest1>>();\n\n        Assert.NotNull(inst);\n        Assert.IsType<Tuple<ITest, ITest1>>(inst);\n        Assert.IsType<Test>(inst.Item1);\n        Assert.Same(inst.Item2, meta);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void TupleTests_Resolve_Custom_Meta_Chooses_Best_Match(CompilerType compilerType)\n    {\n        var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<ITest, A>(c => c.WithMetadata(\"A\"));\n        container.Register<ITest, B>(c => c.WithMetadata(1));\n        var inst1 = container.Resolve<Tuple<ITest, string>>();\n        var inst2 = container.Resolve<Tuple<ITest, int>>();\n\n        Assert.NotNull(inst1);\n        Assert.NotNull(inst2);\n        Assert.IsType<A>(inst1.Item1);\n        Assert.Equal(\"A\", inst1.Item2);\n        Assert.IsType<B>(inst2.Item1);\n        Assert.Equal(1, inst2.Item2);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void TupleTests_Resolve_Custom_Meta_Enumerable_Filter(CompilerType compilerType)\n    {\n        var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<ITest, A>(c => c.WithMetadata(\"A\"));\n        container.Register<ITest, B>(c => c.WithMetadata(1));\n        var filtered1 = container.Resolve<IEnumerable<Tuple<ITest, string>>>();\n        var filtered2 = container.Resolve<IEnumerable<Tuple<ITest, int>>>();\n\n        Assert.Single(filtered1);\n        Assert.IsType<A>(filtered1.First().Item1);\n        Assert.Equal(\"A\", filtered1.First().Item2);\n        Assert.Single(filtered2);\n        Assert.IsType<B>(filtered2.First().Item1);\n        Assert.Equal(1, filtered2.First().Item2);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void TupleTests_Resolve_Custom_Meta_Enumerable_Choose_Only_With_Meta(CompilerType compilerType)\n    {\n        var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<ITest, A>(c => c.WithMetadata(\"A\"));\n        container.Register<ITest, B>();\n        var filtered = container.Resolve<IEnumerable<Tuple<ITest, string>>>();\n        var unfiltered = container.Resolve<IEnumerable<ITest>>().ToArray();\n\n        Assert.Single(filtered);\n        Assert.IsType<A>(filtered.First().Item1);\n        Assert.Equal(\"A\", filtered.First().Item2);\n        Assert.Equal(2, unfiltered.Length);\n        Assert.IsType<A>(unfiltered[0]);\n        Assert.IsType<B>(unfiltered[1]);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void TupleTests_Resolve_Custom_Meta_Enumerable_Empty_When_Nothing_Registered_With_Meta(CompilerType compilerType)\n    {\n        var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<ITest, A>();\n        container.Register<ITest, B>();\n        var filtered = container.Resolve<IEnumerable<Tuple<ITest, object>>>();\n        var unfiltered = container.Resolve<IEnumerable<ITest>>().ToArray();\n\n        Assert.Empty(filtered);\n        Assert.Equal(2, unfiltered.Length);\n        Assert.IsType<A>(unfiltered[0]);\n        Assert.IsType<B>(unfiltered[1]);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void ValueTupleTests_Resolve(CompilerType compilerType)\n    {\n        var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        var meta = new object();\n        container.Register<ITest, Test>(c => c.WithMetadata(meta));\n        var inst = container.Resolve<ValueTuple<ITest, object>>();\n\n        Assert.NotEqual(default(ValueTuple<ITest, object>), inst);\n        Assert.IsType<ValueTuple<ITest, object>>(inst);\n        Assert.IsType<Test>(inst.Item1);\n        Assert.Same(inst.Item2, meta);\n    }\n\n    [Fact]\n    public void ValueTupleTests_Resolve_Null()\n    {\n        var container = new StashboxContainer();\n        var inst = container.ResolveOrDefault<ValueTuple<ITest, object>>();\n\n        Assert.Equal(default(ValueTuple<ITest, object>), inst);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void ValueTupleTests_Resolve_Lazy(CompilerType compilerType)\n    {\n        var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        var meta = new object();\n        container.Register<ITest, Test>(c => c.WithMetadata(meta));\n        var inst = container.Resolve<ValueTuple<Lazy<ITest>, object>>();\n\n        Assert.NotEqual(default, inst);\n        Assert.IsType<ValueTuple<Lazy<ITest>, object>>(inst);\n        Assert.IsType<Test>(inst.Item1.Value);\n        Assert.Same(inst.Item2, meta);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void ValueTupleTests_Resolve_Func(CompilerType compilerType)\n    {\n        var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        var meta = new object();\n        container.Register<ITest, Test>(c => c.WithMetadata(meta));\n        var inst = container.Resolve<ValueTuple<Func<ITest>, object>>();\n\n        Assert.NotEqual(default, inst);\n        Assert.IsType<ValueTuple<Func<ITest>, object>>(inst);\n        Assert.IsType<Test>(inst.Item1());\n        Assert.Same(inst.Item2, meta);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void ValueTupleTests_Resolve_Enumerable(CompilerType compilerType)\n    {\n        var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        var meta = new object();\n        container.Register<ITest, Test>(c => c.WithMetadata(meta));\n        var inst = container.Resolve<IEnumerable<ValueTuple<ITest, object>>>();\n\n        Assert.NotNull(inst);\n        Assert.IsAssignableFrom<IEnumerable<ValueTuple<ITest, object>>>(inst);\n        Assert.IsType<Test>(inst.First().Item1);\n        Assert.Same(inst.First().Item2, meta);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void ValueTupleTests_Resolve_Enumerable_ShouldNull(CompilerType compilerType)\n    {\n        var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        var meta = new object();\n        container.Register<ITest, Test>(c => c.WithMetadata(meta));\n        var inst = container.Resolve<ValueTuple<IEnumerable<ITest>, object>>();\n\n        Assert.NotEqual(default, inst);\n        Assert.IsType<ValueTuple<IEnumerable<ITest>, object>>(inst);\n        Assert.IsType<Test>(inst.Item1.First());\n        Assert.Null(inst.Item2);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void ValueTupleTests_Resolve_Constructor(CompilerType compilerType)\n    {\n        var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        var meta = new object();\n        container.Register<ITest, Test>(c => c.WithMetadata(meta));\n        container.Register<Test4>();\n        var inst = container.Resolve<Test4>();\n\n        Assert.NotNull(inst);\n        Assert.IsType<ValueTuple<ITest, object>>(inst.Test);\n        Assert.IsType<Test>(inst.Test.Item1);\n        Assert.Same(inst.Test.Item2, meta);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void ValueTupleTests_Resolve_Custom_Meta(CompilerType compilerType)\n    {\n        var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        ITest1 meta = new Test1();\n        container.Register<ITest, Test>(c => c.WithMetadata(meta));\n        var inst = container.Resolve<ValueTuple<ITest, ITest1>>();\n\n        Assert.NotEqual(default, inst);\n        Assert.IsType<ValueTuple<ITest, ITest1>>(inst);\n        Assert.IsType<Test>(inst.Item1);\n        Assert.Same(inst.Item2, meta);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void ValueTupleTests_Resolve_Custom_Meta_Implementation_Type(CompilerType compilerType)\n    {\n        var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        Test1 meta = new Test1();\n        container.Register<ITest, Test>(c => c.WithMetadata(meta));\n        var inst = container.Resolve<ValueTuple<ITest, ITest1>>();\n\n        Assert.NotEqual(default, inst);\n        Assert.IsType<ValueTuple<ITest, ITest1>>(inst);\n        Assert.IsType<Test>(inst.Item1);\n        Assert.Same(inst.Item2, meta);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void ValueTupleTests_Resolve_Custom_Meta_Chooses_Best_Match(CompilerType compilerType)\n    {\n        var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<ITest, A>(c => c.WithMetadata(\"A\"));\n        container.Register<ITest, B>(c => c.WithMetadata(1));\n        var inst1 = container.Resolve<ValueTuple<ITest, string>>();\n        var inst2 = container.Resolve<ValueTuple<ITest, int>>();\n\n        Assert.NotEqual(default, inst1);\n        Assert.NotEqual(default, inst2);\n        Assert.IsType<A>(inst1.Item1);\n        Assert.Equal(\"A\", inst1.Item2);\n        Assert.IsType<B>(inst2.Item1);\n        Assert.Equal(1, inst2.Item2);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void ValueTupleTests_Resolve_Custom_Meta_Enumerable_Filter(CompilerType compilerType)\n    {\n        var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<ITest, A>(c => c.WithMetadata(\"A\"));\n        container.Register<ITest, B>(c => c.WithMetadata(1));\n        var filtered1 = container.Resolve<IEnumerable<ValueTuple<ITest, string>>>();\n        var filtered2 = container.Resolve<IEnumerable<ValueTuple<ITest, int>>>();\n\n        Assert.Single(filtered1);\n        Assert.IsType<A>(filtered1.First().Item1);\n        Assert.Equal(\"A\", filtered1.First().Item2);\n        Assert.Single(filtered2);\n        Assert.IsType<B>(filtered2.First().Item1);\n        Assert.Equal(1, filtered2.First().Item2);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void ValueTupleTests_Resolve_Custom_Meta_Enumerable_Choose_Only_With_Meta(CompilerType compilerType)\n    {\n        var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<ITest, A>(c => c.WithMetadata(\"A\"));\n        container.Register<ITest, B>();\n        var filtered = container.Resolve<IEnumerable<ValueTuple<ITest, string>>>();\n        var unfiltered = container.Resolve<IEnumerable<ITest>>().ToArray();\n\n        Assert.Single(filtered);\n        Assert.IsType<A>(filtered.First().Item1);\n        Assert.Equal(\"A\", filtered.First().Item2);\n        Assert.Equal(2, unfiltered.Length);\n        Assert.IsType<A>(unfiltered[0]);\n        Assert.IsType<B>(unfiltered[1]);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void ValueTupleTests_Resolve_Custom_Meta_Enumerable_Empty_When_Nothing_Registered_With_Meta(CompilerType compilerType)\n    {\n        var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<ITest, A>();\n        container.Register<ITest, B>();\n        var filtered = container.Resolve<IEnumerable<ValueTuple<ITest, object>>>();\n        var unfiltered = container.Resolve<IEnumerable<ITest>>().ToArray();\n\n        Assert.Empty(filtered);\n        Assert.Equal(2, unfiltered.Length);\n        Assert.IsType<A>(unfiltered[0]);\n        Assert.IsType<B>(unfiltered[1]);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void MetadataTests_Resolve(CompilerType compilerType)\n    {\n        var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        var meta = new object();\n        container.Register<ITest, Test>(c => c.WithMetadata(meta));\n        var inst = container.Resolve<Metadata<ITest, object>>();\n\n        Assert.NotNull(inst);\n        Assert.IsType<Metadata<ITest, object>>(inst);\n        Assert.IsType<Test>(inst.Service);\n        Assert.Same(inst.Data, meta);\n    }\n\n    [Fact]\n    public void MetadataTests_Resolve_Null()\n    {\n        var container = new StashboxContainer();\n        var inst = container.ResolveOrDefault<Metadata<ITest, object>>();\n\n        Assert.Null(inst);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void MetadataTests_Resolve_Lazy(CompilerType compilerType)\n    {\n        var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        var meta = new object();\n        container.Register<ITest, Test>(c => c.WithMetadata(meta));\n        var inst = container.Resolve<Metadata<Lazy<ITest>, object>>();\n\n        Assert.NotNull(inst);\n        Assert.IsType<Metadata<Lazy<ITest>, object>>(inst);\n        Assert.IsType<Test>(inst.Service.Value);\n        Assert.Same(inst.Data, meta);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void MetadataTests_Resolve_Func(CompilerType compilerType)\n    {\n        var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        var meta = new object();\n        container.Register<ITest, Test>(c => c.WithMetadata(meta));\n        var inst = container.Resolve<Metadata<Func<ITest>, object>>();\n\n        Assert.NotNull(inst);\n        Assert.IsType<Metadata<Func<ITest>, object>>(inst);\n        Assert.IsType<Test>(inst.Service());\n        Assert.Same(inst.Data, meta);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void MetadataTests_Resolve_Enumerable(CompilerType compilerType)\n    {\n        var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        var meta = new object();\n        container.Register<ITest, Test>(c => c.WithMetadata(meta));\n        var inst = container.Resolve<IEnumerable<Metadata<ITest, object>>>();\n\n        Assert.NotNull(inst);\n        Assert.IsAssignableFrom<IEnumerable<Metadata<ITest, object>>>(inst);\n        Assert.IsType<Test>(inst.First().Service);\n        Assert.Same(inst.First().Data, meta);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void MetadataTests_Resolve_Enumerable_ShouldNull(CompilerType compilerType)\n    {\n        var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        var meta = new object();\n        container.Register<ITest, Test>(c => c.WithMetadata(meta));\n        var inst = container.Resolve<Metadata<IEnumerable<ITest>, object>>();\n\n        Assert.NotNull(inst);\n        Assert.IsType<Metadata<IEnumerable<ITest>, object>>(inst);\n        Assert.IsType<Test>(inst.Service.First());\n        Assert.Null(inst.Data);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void MetadataTests_Resolve_Constructor(CompilerType compilerType)\n    {\n        var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        var meta = new object();\n        container.Register<ITest, Test>(c => c.WithMetadata(meta));\n        container.Register<Test3>();\n        var inst = container.Resolve<Test3>();\n\n        Assert.NotNull(inst);\n        Assert.IsType<Metadata<ITest, object>>(inst.Test);\n        Assert.IsType<Test>(inst.Test.Service);\n        Assert.Same(inst.Test.Data, meta);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void MetadataTests_Resolve_Custom_Meta(CompilerType compilerType)\n    {\n        var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        ITest1 meta = new Test1();\n        container.Register<ITest, Test>(c => c.WithMetadata(meta));\n        var inst = container.Resolve<Metadata<ITest, ITest1>>();\n\n        Assert.NotNull(inst);\n        Assert.IsType<Metadata<ITest, ITest1>>(inst);\n        Assert.IsType<Test>(inst.Service);\n        Assert.Same(inst.Data, meta);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void MetadataTests_Resolve_Custom_Meta_ImplementationType(CompilerType compilerType)\n    {\n        var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        Test1 meta = new Test1();\n        container.Register<ITest, Test>(c => c.WithMetadata(meta));\n        var inst = container.Resolve<Metadata<ITest, ITest1>>();\n\n        Assert.NotNull(inst);\n        Assert.IsType<Metadata<ITest, ITest1>>(inst);\n        Assert.IsType<Test>(inst.Service);\n        Assert.Same(inst.Data, meta);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void MetadataTests_Resolve_Custom_Meta_Chooses_Best_Match(CompilerType compilerType)\n    {\n        var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<ITest, A>(c => c.WithMetadata(\"A\"));\n        container.Register<ITest, B>(c => c.WithMetadata(1));\n        var inst1 = container.Resolve<Metadata<ITest, string>>();\n        var inst2 = container.Resolve<Metadata<ITest, int>>();\n\n        Assert.NotNull(inst1);\n        Assert.NotNull(inst2);\n        Assert.IsType<A>(inst1.Service);\n        Assert.Equal(\"A\", inst1.Data);\n        Assert.IsType<B>(inst2.Service);\n        Assert.Equal(1, inst2.Data);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void MetadataTests_Resolve_Custom_Meta_Enumerable_Filter(CompilerType compilerType)\n    {\n        var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<ITest, A>(c => c.WithMetadata(\"A\"));\n        container.Register<ITest, B>(c => c.WithMetadata(1));\n        var filtered1 = container.Resolve<IEnumerable<Metadata<ITest, string>>>();\n        var filtered2 = container.Resolve<IEnumerable<Metadata<ITest, int>>>();\n\n        Assert.Single(filtered1);\n        Assert.IsType<A>(filtered1.First().Service);\n        Assert.Equal(\"A\", filtered1.First().Data);\n        Assert.Single(filtered2);\n        Assert.IsType<B>(filtered2.First().Service);\n        Assert.Equal(1, filtered2.First().Data);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void MetadataTests_Resolve_Custom_Meta_Enumerable_Choose_Only_With_Meta(CompilerType compilerType)\n    {\n        var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<ITest, A>(c => c.WithMetadata(\"A\"));\n        container.Register<ITest, B>();\n        var filtered = container.Resolve<IEnumerable<Metadata<ITest, string>>>();\n        var unfiltered = container.Resolve<IEnumerable<ITest>>().ToArray();\n\n        Assert.Single(filtered);\n        Assert.IsType<A>(filtered.First().Service);\n        Assert.Equal(\"A\", filtered.First().Data);\n        Assert.Equal(2, unfiltered.Length);\n        Assert.IsType<A>(unfiltered[0]);\n        Assert.IsType<B>(unfiltered[1]);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void MetadataTests_Resolve_Custom_Meta_Enumerable_Empty_When_Nothing_Registered_With_Meta(CompilerType compilerType)\n    {\n        var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<ITest, A>();\n        container.Register<ITest, B>();\n        var filtered = container.Resolve<IEnumerable<Metadata<ITest, object>>>();\n        var unfiltered = container.Resolve<IEnumerable<ITest>>().ToArray();\n\n        Assert.Empty(filtered);\n        Assert.Equal(2, unfiltered.Length);\n        Assert.IsType<A>(unfiltered[0]);\n        Assert.IsType<B>(unfiltered[1]);\n    }\n\n    interface ITest;\n\n    interface ITest1;\n\n    class Test : ITest;\n\n    class A : ITest;\n\n    class B : ITest;\n\n    class Test1 : ITest1;\n\n    class Test2\n    {\n        public Tuple<ITest, object> Test { get; }\n\n        public Test2(Tuple<ITest, object> test)\n        {\n            this.Test = test;\n        }\n    }\n\n    class Test3\n    {\n        public Metadata<ITest, object> Test { get; }\n\n        public Test3(Metadata<ITest, object> test)\n        {\n            this.Test = test;\n        }\n    }\n\n    class Test4\n    {\n        public ValueTuple<ITest, object> Test { get; }\n\n        public Test4(ValueTuple<ITest, object> test)\n        {\n            this.Test = test;\n        }\n    }\n}"
  },
  {
    "path": "test/MultitenantTests.cs",
    "content": "﻿using Stashbox.Multitenant;\nusing System;\nusing System.Reflection;\nusing System.Threading.Tasks;\nusing Moq;\nusing Stashbox.Configuration;\nusing Stashbox.Registration.Fluent;\nusing Stashbox.Resolution;\nusing Xunit;\n\nnamespace Stashbox.Tests;\n\n#pragma warning disable 0618\n\npublic class MultitenantTests\n{\n    [Fact]\n    public void MultitenantTests_Same_Root()\n    {\n        var container = new StashboxContainer();\n        ITenantDistributor md = new TenantDistributor(container);\n\n        Assert.Same(container, md.GetType().GetField(\"rootContainer\", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(md));\n    }\n\n    [Fact]\n    public void MultitenantTests_Null_Container()\n    {\n        ITenantDistributor md = new TenantDistributor(null);\n\n        Assert.NotNull(md.GetType().GetField(\"rootContainer\", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(md));\n    }\n\n    [Fact]\n    public void MultitenantTests_Get_NonExisting_Null()\n    {\n        var container = new StashboxContainer();\n        ITenantDistributor md = new TenantDistributor(container);\n\n        Assert.Null(md.GetTenant(\"A\"));\n    }\n\n    [Fact]\n    public void MultitenantTests_Configure()\n    {\n        var container = new StashboxContainer();\n        container.Register<IA, A>();\n\n        ITenantDistributor md = new TenantDistributor(container);\n\n        md.ConfigureTenant(\"A\", c => c.Register<IA, B>());\n\n        Assert.IsType<A>(container.Resolve<IA>());\n\n        var tenant = md.GetTenant(\"A\");\n\n        Assert.NotNull(tenant);\n        Assert.IsType<B>(md.GetTenant(\"A\").Resolve<IA>());\n    }\n\n    [Fact]\n    public void MultitenantTests_Configure_Dep()\n    {\n        var container = new StashboxContainer();\n        container.Register<D>();\n        container.Register<IA, A>();\n\n        ITenantDistributor md = new TenantDistributor(container);\n\n        md.ConfigureTenant(\"A\", c => c.Register<IA, B>());\n\n        var tenant = md.GetTenant(\"A\");\n\n        Assert.IsType<A>(container.Resolve<D>().Ia);\n        Assert.IsType<B>(md.GetTenant(\"A\").Resolve<D>().Ia);\n    }\n\n    [Fact]\n    public void MultitenantTests_Configure_Validate_Root_Throws()\n    {\n        var container = new StashboxContainer();\n        container.Register<D>();\n\n        ITenantDistributor md = new TenantDistributor(container);\n\n        md.ConfigureTenant(\"A\", c => c.Register<IA, B>());\n\n        var exception = Assert.Throws<AggregateException>(() => md.Validate());\n        Assert.Single(exception.InnerExceptions);\n    }\n\n    [Fact]\n    public void MultitenantTests_Configure_Validate_Root_And_Tenants_Throws()\n    {\n        var container = new StashboxContainer();\n        container.Register<D>();\n\n        ITenantDistributor md = new TenantDistributor(container);\n\n        md.ConfigureTenant(\"A\", c => c.Register<D>());\n\n        var exception = Assert.Throws<AggregateException>(() => md.Validate());\n        Assert.Equal(2, exception.InnerExceptions.Count);\n    }\n\n    [Fact]\n    public void MultitenantTests_Configure_Validate_Valid()\n    {\n        var container = new StashboxContainer();\n        container.Register<IA, A>();\n\n        ITenantDistributor md = new TenantDistributor(container);\n\n        md.ConfigureTenant(\"A\", c => c.Register<D>());\n\n        md.Validate();\n    }\n\n    [Fact]\n    public void MultitenantTests_Dispose()\n    {\n        var container = new StashboxContainer(c => c.WithDisposableTransientTracking());\n        container.Register<IA, C>();\n\n        ITenantDistributor md = new TenantDistributor(container);\n\n        md.ConfigureTenant(\"C\", c => { });\n        var tenant = md.GetTenant(\"C\");\n\n        var inst = (C)tenant.Resolve<IA>();\n\n        md.Dispose();\n\n        Assert.True(inst.Disposed);\n        Assert.Throws<ObjectDisposedException>(() => container.Resolve<IA>());\n        Assert.Throws<ObjectDisposedException>(() => tenant.Resolve<IA>());\n    }\n\n    [Fact]\n    public void MultitenantTests_Dispose_Tenant()\n    {\n        var container = new StashboxContainer(c => c.WithDisposableTransientTracking());\n\n        ITenantDistributor md = new TenantDistributor(container);\n\n        md.ConfigureTenant(\"C\", c => c.Register<IA, C>());\n        var tenant = md.GetTenant(\"C\");\n\n        var inst = (C)tenant.Resolve<IA>();\n\n        md.Dispose();\n\n        Assert.True(inst.Disposed);\n\n        Assert.Throws<ObjectDisposedException>(() => container.Resolve<IA>());\n        Assert.Throws<ObjectDisposedException>(() => tenant.Resolve<IA>());\n    }\n\n    [Fact]\n    public void MultitenantTests_Dispose_Multiple()\n    {\n        var container = new StashboxContainer();\n        container.Register<IA, C>();\n\n        ITenantDistributor md = new TenantDistributor(container);\n\n        md.Dispose();\n        md.Dispose();\n    }\n\n    [Fact]\n    public void MultitenantTests_Ensure_Container_Method_Calls_Delegate_To_Root()\n    {\n        var container = new Mock<IStashboxContainer>();\n        ITenantDistributor d = new TenantDistributor(container.Object);\n\n        d.RegisterResolver(new Mock<IResolver>().Object);\n        d.CreateChildContainer();\n        d.IsRegistered<IA>();\n        d.IsRegistered(typeof(IA));\n        d.Configure(c => { });\n        d.Validate();\n        d.GetRegistrationMappings();\n        d.GetRegistrationDiagnostics();\n        d.Register<IA, C>(c => { });\n        d.Register<IA, C>();\n        d.Register<IA, C>(\"a\");\n        d.Register<IA>(typeof(C));\n        d.Register(typeof(IA), typeof(C));\n        d.Register<C>(c => { });\n        d.Register<C>(\"a\");\n        d.Register(typeof(C));\n        d.RegisterSingleton<IA, C>();\n        d.RegisterSingleton(typeof(IA), typeof(C));\n        d.RegisterSingleton<C>(\"a\");\n        d.RegisterScoped<IA, C>();\n        d.RegisterScoped(typeof(IA), typeof(C));\n        d.RegisterScoped<C>(\"a\");\n        d.RegisterInstance<IA>(new C());\n        d.RegisterInstance((object)new C(), typeof(IA));\n        d.WireUp<IA>(new C());\n        d.WireUp((object)new C(), typeof(IA));\n        d.GetService(typeof(IA));\n        d.Resolve(typeof(IA));\n        d.Resolve(typeof(IA), ResolutionBehavior.Default);\n        d.Resolve(typeof(IA), [\"a\"]);\n        d.Resolve(typeof(IA), \"a\", [\"a\"]);\n        d.Resolve(typeof(IA), \"a\");\n        d.ResolveOrDefault(typeof(IA));\n        d.ResolveOrDefault(typeof(IA), ResolutionBehavior.Default);\n        d.ResolveOrDefault(typeof(IA), [\"a\"]);\n        d.ResolveOrDefault(typeof(IA), \"a\", [\"a\"]);\n        d.ResolveOrDefault(typeof(IA), \"a\");\n        d.ResolveAll<IA>();\n        d.ResolveAll<IA>(\"a\");\n        d.ResolveAll<IA>([\"a\"]);\n        d.ResolveAll<IA>(\"a\", [\"a\"]);\n        d.ResolveAll(typeof(IA));\n        d.ResolveAll(typeof(IA),\"a\");\n        d.ResolveAll(typeof(IA), [\"a\"]);\n        d.ResolveAll(typeof(IA),\"a\", [\"a\"]);\n        d.ResolveFactory(typeof(IA));\n        d.ResolveFactoryOrDefault(typeof(IA));\n        d.BeginScope();\n        d.PutInstanceInScope(typeof(IA), new C());\n        d.BuildUp<IA>(new C());\n        d.Activate(typeof(C));\n        d.Activate(typeof(C), ResolutionBehavior.Default);\n        d.InvokeAsyncInitializers();\n        d.CanResolve<IA>();\n        d.CanResolve(typeof(IA));\n        d.GetDelegateCacheEntries();\n        d.ReMap<IA, C>();\n        d.ReMap<IA>(typeof(C));\n        d.ReMap(typeof(IA), typeof(C));\n        d.ReMap<C>();\n        d.ReMapDecorator<IA, C>();\n        d.ReMapDecorator<IA>(typeof(C));\n        d.ReMapDecorator(typeof(IA), typeof(C));\n        d.RegisterTypesAs(typeof(IA), new []{typeof(C)});\n        d.RegisterTypes(new []{typeof(C)});\n        d.ComposeBy(new Mock<ICompositionRoot>().Object.GetType());\n        d.ComposeBy(new Mock<ICompositionRoot>().Object);\n        d.RegisterDecorator<IA, C>();\n        d.RegisterDecorator(typeof(IA), typeof(C));\n        d.RegisterDecorator<C>();\n        d.RegisterDecorator<IA>(typeof(C));\n        d.RegisterDecorator(typeof(C));\n        d.RegisterFunc<IA>((r) => new C());\n        d.RegisterFunc<int, IA>((i, resolver) => new C());\n        d.RegisterFunc<int, int, IA>((i, i1, arg3) => new C());\n        d.RegisterFunc<int, int, int, IA>((i, i1, arg3, arg4) => new C());\n        d.RegisterFunc<int, int, int, int, IA>((i, i1, arg3, arg4, arg5) => new C());\n            \n        container.Verify(c => c.RegisterResolver(It.IsAny<IResolver>()), Times.Once);\n        container.Verify(c => c.CreateChildContainer(null, true), Times.Once);\n        container.Verify(c => c.IsRegistered<IA>(null), Times.Once);\n        container.Verify(c => c.IsRegistered(typeof(IA), null), Times.Once);\n        container.Verify(c => c.Configure(It.IsAny<Action<ContainerConfigurator>>()), Times.Once);\n        container.Verify(c => c.Validate(), Times.Once);\n        container.Verify(c => c.GetRegistrationMappings(), Times.Once);\n        container.Verify(c => c.GetRegistrationDiagnostics(), Times.Once);\n        container.Verify(c => c.Register<IA, C>(It.IsAny<RegistrationConfigurator<IA, C>>()), Times.Once);\n        container.Verify(c => c.Register<IA, C>(\"a\"), Times.Once);\n        container.Verify(c => c.Register<IA>(typeof(C), null), Times.Once);\n        container.Verify(c => c.Register(typeof(IA), typeof(C), null), Times.Once);\n        container.Verify(c => c.Register<C>(It.IsAny<Action<RegistrationConfigurator<C, C>>>()), Times.Once);\n        container.Verify(c => c.Register<C>(\"a\"), Times.Once);\n        container.Verify(c => c.Register(typeof(C), null), Times.Once);\n        container.Verify(c => c.RegisterSingleton<IA, C>(null), Times.Once);\n        container.Verify(c => c.RegisterSingleton(typeof(IA), typeof(C), null), Times.Once);\n        container.Verify(c => c.RegisterSingleton<C>(\"a\"), Times.Once);\n        container.Verify(c => c.RegisterScoped<IA, C>(null), Times.Once);\n        container.Verify(c => c.RegisterScoped(typeof(IA), typeof(C), null), Times.Once);\n        container.Verify(c => c.RegisterScoped<C>(\"a\"), Times.Once);\n        container.Verify(c => c.RegisterInstance<IA>(It.IsAny<C>(), null, false, null), Times.Once);\n        container.Verify(c => c.RegisterInstance(It.IsAny<object>(), It.IsAny<Type>(), null, false), Times.Once);\n        container.Verify(c => c.WireUp<IA>(It.IsAny<C>(), null, false, null), Times.Once);\n        container.Verify(c => c.WireUp(It.IsAny<object>(), It.IsAny<Type>(), null, false), Times.Once);\n        container.Verify(c => c.GetService(typeof(IA)), Times.Once);\n        container.Verify(c => c.Resolve(typeof(IA)), Times.Once);\n        container.Verify(c => c.Resolve(typeof(IA), \"a\", new object[] { \"a\" }, ResolutionBehavior.Default), Times.Once);\n        container.Verify(c => c.ResolveOrDefault(typeof(IA)), Times.Once);\n        container.Verify(c => c.ResolveOrDefault(typeof(IA), \"a\", new object[] { \"a\" }, ResolutionBehavior.Default), Times.Once);\n        container.Verify(c => c.ResolveFactory(typeof(IA), null, ResolutionBehavior.Default, It.IsAny<Type[]>()), Times.Once);\n        container.Verify(c => c.ResolveFactoryOrDefault(typeof(IA), null, ResolutionBehavior.Default, It.IsAny<Type[]>()), Times.Once);\n        container.Verify(c => c.BeginScope(null, false), Times.Once);\n        container.Verify(c => c.PutInstanceInScope(typeof(IA), It.IsAny<C>(), false, null), Times.Once);\n        container.Verify(c => c.BuildUp<IA>(It.IsAny<C>(), ResolutionBehavior.Default), Times.Once);\n        container.Verify(c => c.Activate(typeof(C), ResolutionBehavior.Default), Times.Exactly(2));\n        container.Verify(c => c.InvokeAsyncInitializers(default), Times.Once);\n        container.Verify(c => c.CanResolve(typeof(IA), null, ResolutionBehavior.Default), Times.Exactly(2));\n        container.Verify(c => c.GetDelegateCacheEntries(), Times.Once);\n        container.Verify(c => c.ReMap<IA, C>(null), Times.Once);\n        container.Verify(c => c.ReMap<IA>(typeof(C), null), Times.Once);\n        container.Verify(c => c.ReMap(typeof(IA), typeof(C), null), Times.Once);\n        container.Verify(c => c.ReMap<C>(null), Times.Once);\n        container.Verify(c => c.ReMapDecorator<IA, C>(null), Times.Once);\n        container.Verify(c => c.ReMapDecorator<IA>(typeof(C), null), Times.Once);\n        container.Verify(c => c.ReMapDecorator(typeof(IA), typeof(C), null), Times.Once);\n        container.Verify(c => c.RegisterTypesAs(typeof(IA), It.IsAny<Type[]>(), null, null), Times.Once);\n        container.Verify(c => c.RegisterTypes(It.IsAny<Type[]>(), null, null, true, null), Times.Once);\n        container.Verify(c => c.ComposeBy(It.IsAny<Type>(), It.IsAny<object[]>()), Times.Once);\n        container.Verify(c => c.ComposeBy(It.IsAny<Type>(), It.IsAny<object[]>()), Times.Once);\n        container.Verify(c => c.RegisterDecorator<IA, C>(null), Times.Once);\n        container.Verify(c => c.RegisterDecorator(typeof(IA), typeof(C), null), Times.Once);\n        container.Verify(c => c.RegisterDecorator<C>(null), Times.Once);\n        container.Verify(c => c.RegisterDecorator<IA>(typeof(C), null), Times.Once);\n        container.Verify(c => c.RegisterDecorator(typeof(C), null), Times.Once);\n        container.Verify(c => c.RegisterFunc(It.IsAny<Func<IDependencyResolver, IA>>(), null), Times.Once);\n        container.Verify(c => c.RegisterFunc(It.IsAny<Func<int, IDependencyResolver, IA>>(), null), Times.Once);\n        container.Verify(c => c.RegisterFunc(It.IsAny<Func<int, int, IDependencyResolver, IA>>(), null), Times.Once);\n        container.Verify(c => c.RegisterFunc(It.IsAny<Func<int, int, int, IDependencyResolver, IA>>(), null), Times.Once);\n        container.Verify(c => c.RegisterFunc(It.IsAny<Func<int, int, int, int, IDependencyResolver, IA>>(), null), Times.Once);\n    }\n\n#if HAS_ASYNC_DISPOSABLE\n        [Fact]\n        public async Task MultitenantTests_Dispose_Async()\n        {\n            var container = new StashboxContainer(c => c.WithDisposableTransientTracking());\n            container.Register<IA, C>();\n\n            ITenantDistributor md = new TenantDistributor(container);\n\n            md.ConfigureTenant(\"C\", c => { });\n            var tenant = md.GetTenant(\"C\");\n\n            var inst = (C)tenant.Resolve<IA>();\n\n            await md.DisposeAsync();\n\n            Assert.True(inst.Disposed);\n            Assert.Throws<ObjectDisposedException>(() => container.Resolve<IA>());\n            Assert.Throws<ObjectDisposedException>(() => tenant.Resolve<IA>());\n        }\n\n        [Fact]\n        public async Task MultitenantTests_Dispose_Async_Tenant()\n        {\n            var container = new StashboxContainer(c => c.WithDisposableTransientTracking());\n\n            ITenantDistributor md = new TenantDistributor(container);\n\n            md.ConfigureTenant(\"C\", c => c.Register<IA, C>());\n            var tenant = md.GetTenant(\"C\");\n\n            var inst = (C)tenant.Resolve<IA>();\n\n            await md.DisposeAsync();\n\n            Assert.True(inst.Disposed);\n            Assert.Throws<ObjectDisposedException>(() => container.Resolve<IA>());\n            Assert.Throws<ObjectDisposedException>(() => tenant.Resolve<IA>());\n        }\n\n        [Fact]\n        public async Task MultitenantTests_Dispose_Async_Multiple()\n        {\n            var container = new StashboxContainer();\n            container.Register<IA, C>();\n\n            ITenantDistributor md = new TenantDistributor(container);\n\n            await md.DisposeAsync();\n            await md.DisposeAsync();\n        }\n#endif\n\n    interface IA;\n\n    class A : IA;\n\n    class B : IA;\n\n    class C : IA, IDisposable\n    {\n        public bool Disposed { get; private set; }\n\n        public void Dispose()\n        {\n            if (this.Disposed)\n                throw new ObjectDisposedException(nameof(C));\n\n            this.Disposed = true;\n        }\n    }\n\n    class D\n    {\n        public D(IA ia)\n        {\n            Ia = ia;\n        }\n\n        public IA Ia { get; }\n    }\n}"
  },
  {
    "path": "test/NamedResolveTests.cs",
    "content": "﻿using Stashbox.Exceptions;\nusing System.Linq;\nusing System.Reflection;\nusing System.Text;\nusing Xunit;\n\nnamespace Stashbox.Tests;\n\npublic class NamedResolveTests\n{\n    [Fact]\n    public void NamedResolveTests_Resolve()\n    {\n        using var container = new StashboxContainer()\n            .Register<IA, A>(\"A\")\n            .Register<IA, B>(\"B\");\n\n        Assert.IsType<A>(container.Resolve<IA>(\"A\"));\n        Assert.IsType<B>(container.Resolve<IA>(\"B\"));\n    }\n\n    [Fact]\n    public void NamedResolveTests_Resolve_ImplType()\n    {\n        using var container = new StashboxContainer()\n            .Register<A>(\"A\")\n            .Register<B>(\"B\");\n\n        Assert.IsType<A>(container.Resolve<A>(\"A\"));\n        Assert.IsType<B>(container.Resolve<B>(\"B\"));\n    }\n\n    [Fact]\n    public void NamedResolveTests_Resolve_Throw_On_Same_Name()\n    {\n        Assert.Throws<ServiceAlreadyRegisteredException>(\n            () => new StashboxContainer(c => c.WithRegistrationBehavior(Configuration.Rules.RegistrationBehavior.ThrowException))\n                .Register<IA, A>(\"A\")\n                .Register<IA, A>(\"A\"));\n    }\n\n    [Fact]\n    public void NamedResolveTests_Resolve_Throw_On_Same_Name_Equality_By_Value()\n    {\n        var key = new StringBuilder(\"A\");\n        Assert.Throws<ServiceAlreadyRegisteredException>(\n            () => new StashboxContainer(c => c.WithRegistrationBehavior(Configuration.Rules.RegistrationBehavior.ThrowException))\n                .Register<IA, A>(\"A\")\n                .Register<IA, A>(key.ToString()));\n    }\n\n    [Fact]\n    public void NamedResolveTests_Ensure_Delegate_Cache_Works_OnRoot()\n    {\n        using var container = new StashboxContainer()\n            .Register<IA, A>(\"A\");\n\n        container.Resolve<IA>(\"A\");\n        container.Resolve<IA>(\"A\");\n\n        var cache = container.ContainerContext.RootScope.GetDelegateCacheEntries();\n        Assert.Single(cache);\n    }\n\n    [Fact]\n    public void NamedResolveTests_Ensure_Delegate_Cache_Works_By_Value_OnRoot()\n    {\n        var key = new StringBuilder(\"A\");\n        using var container = new StashboxContainer()\n            .Register<IA, A>(\"A\");\n\n        container.Resolve<IA>(\"A\");\n        container.Resolve<IA>(key.ToString());\n\n        var cache = container.ContainerContext.RootScope.GetDelegateCacheEntries();\n        Assert.Single(cache);\n    }\n\n    [Fact]\n    public void NamedResolveTests_Ensure_Delegate_Cache_Shared_Between_UnNamed_Scopes()\n    {\n        using var container = new StashboxContainer();\n\n        var scope1 = container.BeginScope();\n        var scope2 = container.BeginScope();\n        var scope3 = scope2.BeginScope();\n\n        var scopeType = scope1.GetType();\n        var delegateCache1 = scopeType.GetField(\"delegateCache\", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(scope1);\n        var delegateCache2 = scopeType.GetField(\"delegateCache\", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(scope2);\n        var delegateCache3 = scopeType.GetField(\"delegateCache\", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(scope3);\n\n        Assert.Same(delegateCache1, delegateCache2);\n        Assert.Same(delegateCache2, delegateCache3);\n    }\n\n    [Fact]\n    public void NamedResolveTests_Ensure_Delegate_Cache_Not_Shared_Between_Root_And_UnNamed_Scopes()\n    {\n        using var container = new StashboxContainer();\n\n        var scope = container.BeginScope();\n\n        var scopeType = scope.GetType();\n        var delegateCache1 = scopeType.GetField(\"delegateCache\", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(scope);\n        var delegateCache2 = scopeType.GetField(\"delegateCache\", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(container.ContainerContext.RootScope);\n\n        Assert.NotSame(delegateCache1, delegateCache2);\n    }\n\n    [Fact]\n    public void NamedResolveTests_Named_Scope_Cache_Works()\n    {\n        using var container = new StashboxContainer()\n            .Register<A>()\n            .Register<B>();\n\n        var scope1 = container.BeginScope(\"A\");\n        var scope2 = container.BeginScope(\"A\");\n\n        scope1.Resolve<A>();\n        scope2.Resolve<B>();\n\n        var rootCache = container.ContainerContext.RootScope.GetDelegateCacheEntries();\n        Assert.Empty(rootCache);\n\n        var scope1Cache = scope1.GetDelegateCacheEntries();\n        Assert.Equal(2, scope1Cache.Count());\n\n        var scope2Cache = scope2.GetDelegateCacheEntries();\n        Assert.Equal(2, scope2Cache.Count());\n    }\n\n    [Fact]\n    public void NamedResolveTests_Named_Scope_Cache_Works_Equality_By_Value()\n    {\n        using var container = new StashboxContainer()\n            .Register<A>()\n            .Register<B>();\n\n        var scope1 = container.BeginScope(\"A\");\n        var scope2 = container.BeginScope(\"A\");\n\n        scope1.Resolve<A>();\n        scope2.Resolve<B>();\n\n        var rootCache = container.ContainerContext.RootScope.GetDelegateCacheEntries();\n        Assert.Empty(rootCache);\n\n        var scope1Cache = scope1.GetDelegateCacheEntries();\n        Assert.Equal(2, scope1Cache.Count());\n\n        var scope2Cache = scope2.GetDelegateCacheEntries();\n        Assert.Equal(2, scope2Cache.Count());\n    }\n\n    interface IA;\n\n    class A : IA;\n\n    class B : IA;\n\n    class C : IA;\n\n    class D : IA;\n}"
  },
  {
    "path": "test/NamedScopeTests.cs",
    "content": "﻿using Stashbox.Configuration;\nusing Stashbox.Exceptions;\nusing Stashbox.Lifetime;\nusing Stashbox.Tests.Utils;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing Xunit;\n\nnamespace Stashbox.Tests;\n\npublic class NamedScopeTests\n{\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void NamedScope_Simple_Resolve_Prefer_Named(CompilerType compilerType)\n    {\n        var name = \"A\".ToLower();\n        var inst = new StashboxContainer(config => config.WithCompiler(compilerType))\n            .Register<ITest, Test11>()\n            .Register<ITest, Test>(config => config.InNamedScope(name))\n            .Register<ITest, Test1>()\n            .BeginScope(name)\n            .Resolve<ITest>();\n\n        Assert.IsType<Test>(inst);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void NamedScope_Dependency_Resolve_Prefer_Named(CompilerType compilerType)\n    {\n        var inst = new StashboxContainer(config => config.WithCompiler(compilerType))\n            .Register<Test2>()\n            .Register<ITest, Test11>()\n            .Register<ITest, Test>(config => config.InNamedScope(\"A\"))\n            .Register<ITest, Test1>()\n            .BeginScope(\"A\")\n            .Resolve<Test2>();\n\n        Assert.IsType<Test>(inst.Test);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void NamedScope_Simple_Resolve_Wrapper_Prefer_Named(CompilerType compilerType)\n    {\n        using var scope = new StashboxContainer(config => config.WithCompiler(compilerType))\n            .Register<ITest, Test11>(c => c.WithMetadata(new object()))\n            .Register<ITest, Test>(config => config.InNamedScope(\"A\").WithMetadata(new object()))\n            .Register<ITest, Test1>(c => c.WithMetadata(new object()))\n            .BeginScope(\"A\");\n\n        var func = scope.Resolve<Func<ITest>>();\n        var lazy = scope.Resolve<Lazy<ITest>>();\n        var tuple = scope.Resolve<Tuple<ITest, object>>();\n        var enumerable = scope.Resolve<IEnumerable<ITest>>();\n        var all = scope.ResolveAll<ITest>();\n\n        Assert.IsType<Test>(func());\n        Assert.IsType<Test>(lazy.Value);\n        Assert.IsType<Test>(tuple.Item1);\n        Assert.IsType<Test>(enumerable.Last());\n        Assert.IsType<Test>(all.First());\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void NamedScope_Dependency_Resolve_Wrapper_Prefer_Named(CompilerType compilerType)\n    {\n        var inst = new StashboxContainer(config => config.WithCompiler(compilerType))\n            .Register<Test3>()\n            .Register<ITest, Test11>(c => c.WithMetadata(new object()))\n            .Register<ITest, Test>(config => config.InNamedScope(\"A\").WithMetadata(new object()))\n            .Register<ITest, Test1>(c => c.WithMetadata(new object()))\n            .BeginScope(\"A\")\n            .Resolve<Test3>();\n\n        Assert.IsType<Test>(inst.Func());\n        Assert.IsType<Test>(inst.Lazy.Value);\n        Assert.IsType<Test>(inst.Enumerable.Last());\n        Assert.IsType<Test>(inst.Tuple.Item1);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void NamedScope_Simple_Resolve_Prefer_Named_Last(CompilerType compilerType)\n    {\n        var inst = new StashboxContainer(config => config.WithCompiler(compilerType))\n            .Register<ITest, Test11>(config => config.InNamedScope(\"A\"))\n            .Register<ITest, Test>()\n            .Register<ITest, Test1>(config => config.InNamedScope(\"A\"))\n            .BeginScope(\"A\")\n            .Resolve<ITest>();\n\n        Assert.IsType<Test1>(inst);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void NamedScope_Simple_Resolve_Gets_Same_Within_Scope(CompilerType compilerType)\n    {\n        using var scope = new StashboxContainer(config => config.WithCompiler(compilerType))\n            .Register<ITest, Test>()\n            .Register<ITest, Test1>(config => config.InNamedScope(\"A\"))\n            .BeginScope(\"A\");\n\n        var a = scope.Resolve<ITest>();\n        var b = scope.Resolve<ITest>();\n\n        Assert.Same(a, b);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void NamedScope_Simple_Resolve_Gets_Named_Within_Scope(CompilerType compilerType)\n    {\n        using var scope = new StashboxContainer(config => config.WithCompiler(compilerType))\n            .Register<ITest, Test11>(config => config.InNamedScope(\"A\"))\n            .Register<ITest, Test>(config => config.InNamedScope(\"A\").WithName(\"T\"))\n            .Register<ITest, Test1>(config => config.InNamedScope(\"A\"))\n            .BeginScope(\"A\");\n\n        var a = scope.Resolve<ITest>(\"T\");\n        var b = scope.Resolve<ITest>(\"T\");\n        var c = scope.Resolve<ITest>();\n\n        Assert.Same(a, b);\n        Assert.NotSame(a, c);\n        Assert.IsType<Test>(a);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void NamedScope_Simple_Resolve_Gets_Named_When_Scoped_Doesnt_Exist(CompilerType compilerType)\n    {\n        using var scope = new StashboxContainer(config => config.WithCompiler(compilerType))\n            .Register<ITest, Test11>()\n            .Register<ITest, Test>(config => config.WithName(\"T\"))\n            .Register<ITest, Test1>()\n            .BeginScope(\"A\");\n\n        var a = scope.Resolve<ITest>(\"T\");\n        var b = scope.Resolve<ITest>(\"T\");\n        var c = scope.Resolve<ITest>();\n\n        Assert.IsType<Test1>(c);\n        Assert.IsType<Test>(b);\n        Assert.IsType<Test>(a);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void NamedScope_Dependency_Resolve_Wrapper_Gets_Same_Within_Scope(CompilerType compilerType)\n    {\n        var inst = new StashboxContainer(c => c.WithCompiler(compilerType))\n            .Register<Test3>()\n            .Register<ITest, Test>(config => config.InNamedScope(\"A\").WithMetadata(new object()))\n            .Register<ITest, Test1>(c => c.WithMetadata(new object()))\n            .BeginScope(\"A\")\n            .Resolve<Test3>();\n\n        Assert.Same(inst.Func(), inst.Lazy.Value);\n        Assert.Same(inst.Lazy.Value, inst.Enumerable.Last());\n        Assert.Same(inst.Enumerable.Last(), inst.Tuple.Item1);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void NamedScope_Simple_Resolve_Get_Last_If_Scoped_Doesnt_Exist(CompilerType compilerType)\n    {\n        var inst = new StashboxContainer(c => c.WithCompiler(compilerType))\n            .Register<ITest, Test>()\n            .Register<ITest, Test1>()\n            .BeginScope(\"A\")\n            .Resolve<ITest>();\n\n        Assert.IsType<Test1>(inst);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void NamedScope_Dependency_Get_Last_If_Scoped_Doesnt_Exist(CompilerType compilerType)\n    {\n        var inst = new StashboxContainer(c => c.WithCompiler(compilerType))\n            .Register<Test3>()\n            .Register<ITest, Test>(c => c.WithMetadata(new object()))\n            .Register<ITest, Test1>(c => c.WithMetadata(new object()))\n            .BeginScope(\"A\")\n            .Resolve<Test3>();\n\n        Assert.IsType<Test1>(inst.Func());\n        Assert.IsType<Test1>(inst.Lazy.Value);\n        Assert.IsType<Test1>(inst.Enumerable.Last());\n        Assert.IsType<Test1>(inst.Tuple.Item1);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void NamedScope_Defines_Scope_Prefer_Named(CompilerType compilerType)\n    {\n        var inst = new StashboxContainer(c => c.WithCompiler(compilerType))\n            .Register<Test3>(config => config.DefinesScope(\"A\"))\n            .Register<ITest, Test11>(c => c.WithMetadata(new object()))\n            .Register<ITest, Test>(config => config.InNamedScope(\"A\").WithMetadata(new object()))\n            .Register<ITest, Test1>(c => c.WithMetadata(new object()))\n            .Resolve<Test3>();\n\n        Assert.IsType<Test>(inst.Func());\n        Assert.IsType<Test>(inst.Lazy.Value);\n        Assert.IsType<Test>(inst.Enumerable.Last());\n        Assert.IsType<Test>(inst.Tuple.Item1);\n\n        Assert.Same(inst.Func(), inst.Lazy.Value);\n        Assert.Same(inst.Lazy.Value, inst.Enumerable.Last());\n        Assert.Same(inst.Enumerable.Last(), inst.Tuple.Item1);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void NamedScope_Preserve_Instance_Through_Nested_Scopes(CompilerType compilerType)\n    {\n        var container = new StashboxContainer(c => c.WithCompiler(compilerType))\n            .Register<ITest, Test>(config => config.InNamedScope(\"A\"));\n\n        using var s1 = container.BeginScope(\"A\");\n        var i1 = s1.Resolve<ITest>();\n        using var s2 = s1.BeginScope(\"C\");\n        var i2 = s2.Resolve<ITest>();\n\n        Assert.Same(i2, i1);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void NamedScope_Dispose_Instance_Through_Nested_Scopes(CompilerType compilerType)\n    {\n        var container = new StashboxContainer(c => c.WithCompiler(compilerType))\n            .Register<ITest, Test12>(config => config.InNamedScope(\"A\"));\n\n        ITest i1;\n        using (var s1 = container.BeginScope(\"A\"))\n        {\n            i1 = s1.Resolve<ITest>();\n            using (var s2 = s1.BeginScope())\n            {\n                var i2 = s2.Resolve<ITest>();\n\n                Assert.Same(i2, i1);\n            }\n\n            Assert.False(((Test12)i1).Disposed);\n        }\n\n        Assert.True(((Test12)i1).Disposed);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void NamedScope_Dispose_Instance_Defines_Named_Scope(CompilerType compilerType)\n    {\n        var container = new StashboxContainer(c => c.WithCompiler(compilerType))\n            .Register<ITest, Test12>(config => config.InNamedScope(\"A\"))\n            .Register<Test2>(config => config.DefinesScope(\"A\"));\n\n        Test2 i1;\n        using (var s1 = container.BeginScope())\n        {\n            i1 = s1.Resolve<Test2>();\n        }\n\n        Assert.True(((Test12)i1.Test).Disposed);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void NamedScope_Lifetime_Check(CompilerType compilerType)\n    {\n        var inst = new StashboxContainer(c => c.WithCompiler(compilerType))\n            .Register<ITest, Test>(config => config.InNamedScope(\"A\"))\n            .ContainerContext.RegistrationRepository.GetRegistrationMappings().First(reg => reg.Key == typeof(ITest));\n\n        Assert.IsType<NamedScopeLifetime>(inst.Value.Lifetime);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void NamedScope_Throws_ResolutionFailedException_Without_Scope(CompilerType compilerType)\n    {\n        var container = new StashboxContainer(c => c.WithCompiler(compilerType))\n            .Register<ITest, Test>(config => config.InNamedScope(\"A\"));\n\n        Assert.Throws<ResolutionFailedException>(() => container.Resolve<ITest>());\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void NamedScope_Throws_ResolutionFailedException_Wrong_Scope(CompilerType compilerType)\n    {\n        var container = new StashboxContainer(c => c.WithCompiler(compilerType))\n            .Register<ITest, Test>(config => config.InNamedScope(\"A\"));\n\n        using var scope = container.BeginScope(\"B\");\n        Assert.Throws<ResolutionFailedException>(() => scope.Resolve<ITest>());\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void NamedScope_Throws_ResolutionFailedException_Wrong_Scope_Null(CompilerType compilerType)\n    {\n        var container = new StashboxContainer(c => c.WithCompiler(compilerType))\n            .Register<ITest, Test>(config => config.InNamedScope(\"A\"));\n\n        using var scope = container.BeginScope(\"B\");\n        Assert.Null(scope.ResolveOrDefault<ITest>());\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void NamedScope_WithNull(CompilerType compilerType)\n    {\n        var container = new StashboxContainer(c => c.WithCompiler(compilerType))\n            .Register<Test2>(config => config.InNamedScope(\"A\"));\n\n        Assert.Null(container.BeginScope(\"A\").ResolveOrDefault<Test2>());\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void NamedScope_ChildContainer_Chain(CompilerType compilerType)\n    {\n        var container = new StashboxContainer(c => c.WithCompiler(compilerType))\n            .Register<Test2>(config => config.DefinesScope(\"B\").InNamedScope(\"A\"));\n\n        var child = container.CreateChildContainer()\n            .Register<ITest, Test1>(config => config.InNamedScope(\"B\"))\n            .Register<Test4>(config => config.DefinesScope(\"A\"));\n\n        var inst = child.Resolve<Test4>();\n\n        Assert.NotNull(inst.Test);\n        Assert.NotNull(inst.Test.Test);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void NamedScope_ChildContainer(CompilerType compilerType)\n    {\n        var container = new StashboxContainer(c => c.WithCompiler(compilerType))\n            .Register<Test2>(config => config.DefinesScope(\"A\"))\n            .Register<ITest, Test>(config => config.InNamedScope(\"A\"));\n\n        var child = container.CreateChildContainer()\n            .Register<ITest, Test1>(config => config.InNamedScope(\"A\"));\n\n        var inst = child.Resolve<Test2>();\n\n        Assert.IsType<Test1>(inst.Test);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void NamedScope_Chain(CompilerType compilerType)\n    {\n        var container = new StashboxContainer(c => c.WithCompiler(compilerType))\n            .Register<Test2>(config => config.DefinesScope(\"B\").InNamedScope(\"A\"))\n            .Register<ITest, Test1>(config => config.InNamedScope(\"B\"))\n            .Register<Test4>(config => config.DefinesScope(\"A\"));\n\n        var inst = container.Resolve<Test4>();\n\n        Assert.NotNull(inst.Test);\n        Assert.NotNull(inst.Test.Test);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void NamedScope_ChildContainer_Chain_Reverse(CompilerType compilerType)\n    {\n        var container = new StashboxContainer(c => c.WithCompiler(compilerType))\n            .Register(typeof(Test4), config => config.DefinesScope(\"A\"))\n            .Register<ITest, Test1>(config => config.InNamedScope(\"B\"));\n\n        var child = container.CreateChildContainer()\n            .Register<Test2>(config => config.DefinesScope(\"B\").InNamedScope(\"A\"));\n\n        var inst = child.Resolve<Test4>();\n\n        Assert.NotNull(inst.Test);\n        Assert.NotNull(inst.Test.Test);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void NamedScope_Cache(CompilerType compilerType)\n    {\n        var container = new StashboxContainer(c => c.WithCompiler(compilerType))\n            .Register<ITest, Test>(config => config.InNamedScope(\"A\"))\n            .Register<ITest, Test1>();\n\n        using var scope = container.BeginScope();\n        var inst = scope.Resolve<ITest>();\n\n        Assert.IsType<Test1>(inst);\n\n        using var scope1 = container.BeginScope(\"A\");\n        inst = scope1.Resolve<ITest>();\n\n        Assert.IsType<Test>(inst);\n    }\n\n    interface ITest;\n\n    class Test : ITest;\n\n    class Test1 : ITest;\n\n    class Test11 : ITest;\n\n    class Test12 : ITest, IDisposable\n    {\n        public bool Disposed { get; private set; }\n\n        public void Dispose()\n        {\n            if (this.Disposed)\n                throw new ObjectDisposedException(\"\");\n\n            this.Disposed = true;\n        }\n    }\n\n    class Test2\n    {\n        public Test2(ITest test)\n        {\n            Test = test;\n        }\n\n        public ITest Test { get; }\n    }\n\n    class Test4\n    {\n        public Test4(Test2 test)\n        {\n            Test = test;\n        }\n\n        public Test2 Test { get; }\n    }\n\n    class Test3\n    {\n        public Test3(Func<ITest> func, Lazy<ITest> lazy, IEnumerable<ITest> enumerable, Tuple<ITest, object> tuple)\n        {\n            Func = func;\n            Lazy = lazy;\n            Enumerable = enumerable;\n            Tuple = tuple;\n        }\n\n        public Func<ITest> Func { get; }\n        public Lazy<ITest> Lazy { get; }\n        public IEnumerable<ITest> Enumerable { get; }\n        public Tuple<ITest, object> Tuple { get; }\n    }\n}"
  },
  {
    "path": "test/OverrideTests.cs",
    "content": "﻿using Stashbox.Attributes;\nusing Stashbox.Utils;\nusing System;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing Stashbox.Exceptions;\nusing Xunit;\n\nnamespace Stashbox.Tests;\n\npublic class OverrideTests\n{\n    [Fact]\n    public void OverrideTests_Resolve()\n    {\n        IStashboxContainer container = new StashboxContainer();\n        container.Register<ITest1, Test1>();\n        container.Register<ITest2, Test2>(context =>\n            context.WithInjectionParameter(\"test1\", new Test1 { Name = \"fakeName\" }));\n        var inst2 = container.Resolve<ITest2>();\n\n        Assert.IsType<Test2>(inst2);\n        Assert.Equal(\"fakeName\", inst2.Name);\n\n        container.Register<ITest3, Test3>();\n\n        var inst1 = container.Resolve<ITest1>();\n        inst1.Name = \"test1\";\n        container.Resolve<ITest3>();\n\n        var factory = container.Resolve<Func<ITest1, ITest2, ITest3>>();\n        var inst3 = factory(inst1, inst2);\n\n        Assert.NotNull(inst3);\n        Assert.IsType<Test3>(inst3);\n        Assert.Equal(\"test1fakeNametest1\", inst3.Name);\n    }\n\n    [Fact]\n    public void OverrideTests_Resolve_Parallel()\n    {\n        IStashboxContainer container = new StashboxContainer();\n        container.Register<ITest1, Test1>();\n        container.Register<ITest2, Test2>(context =>\n            context.WithInjectionParameter(\"test1\", new Test1 { Name = \"fakeName\" }));\n        var inst2 = container.Resolve<ITest2>();\n\n        Assert.IsType<Test2>(inst2);\n        Assert.Equal(\"fakeName\", inst2.Name);\n\n        container.Register<ITest3, Test3>();\n\n        Parallel.For(0, 50000, (i) =>\n        {\n            var inst1 = container.Resolve<ITest1>();\n            inst1.Name = \"test1\";\n            var factory = container.Resolve<Func<ITest1, ITest2, ITest3>>();\n            var inst3 = factory(inst1, inst2);\n\n            Assert.NotNull(inst3);\n            Assert.IsType<Test3>(inst3);\n            Assert.Equal(\"test1fakeNametest1\", inst3.Name);\n        });\n    }\n\n    [Fact]\n    public void OverrideTests_Resolve_Factory_NonGeneric()\n    {\n        IStashboxContainer container = new StashboxContainer();\n        container.Register<ITest1, Test1>();\n        container.Register<ITest2, Test2>();\n\n        var inst1 = container.Resolve<ITest1>();\n        inst1.Name = \"test1\";\n        container.Resolve<ITest2>();\n\n        var factory = container.ResolveFactory(typeof(ITest2), parameterTypes: typeof(ITest1));\n        var inst2 = ((Func<ITest1, ITest2>)factory)(inst1);\n\n        Assert.NotNull(inst2);\n        Assert.IsType<Test2>(inst2);\n        Assert.Equal(\"test1\", inst2.Name);\n    }\n\n    [Fact]\n    public void OverrideTests_Resolve_Factory_NonGeneric_DerivedParam()\n    {\n        IStashboxContainer container = new StashboxContainer();\n        container.Register<ITest2, Test2>();\n\n        var inst1 = new Test1 { Name = \"test\" };\n\n        var factory = container.ResolveFactory(typeof(ITest2), parameterTypes: inst1.GetType());\n        var inst2 = (ITest2)factory.DynamicInvoke(inst1);\n\n        Assert.NotNull(inst2);\n        Assert.Equal(\"test\", inst2.Name);\n    }\n\n    [Fact]\n    public void OverrideTests_Resolve_Factory()\n    {\n        IStashboxContainer container = new StashboxContainer();\n        container.Register<ITest1, Test1>();\n        container.Register<ITest2, Test2>();\n\n        var inst1 = container.Resolve<ITest1>();\n        inst1.Name = \"test1\";\n        container.Resolve<ITest2>();\n\n        var factory = container.Resolve<Func<ITest1, ITest2>>();\n        var inst2 = factory(inst1);\n\n        Assert.NotNull(inst2);\n        Assert.IsType<Test2>(inst2);\n        Assert.Equal(\"test1\", inst2.Name);\n    }\n\n    [Fact]\n    public void OverrideTests_Resolve_Factory_NonGeneric_Lazy()\n    {\n        IStashboxContainer container = new StashboxContainer();\n        container.Register<ITest1, Test1>();\n        container.Register<ITest2, Test2>();\n\n        var inst1 = container.Resolve<ITest1>();\n        inst1.Name = \"test1\";\n        container.Resolve<ITest2>();\n\n        var factory = container.ResolveFactory(typeof(Lazy<ITest2>), parameterTypes: typeof(ITest1));\n        var inst2 = ((Func<ITest1, Lazy<ITest2>>)factory)(inst1);\n\n        Assert.NotNull(inst2);\n        Assert.IsType<Lazy<ITest2>>(inst2);\n        Assert.Equal(\"test1\", inst2.Value.Name);\n    }\n\n    [Fact]\n    public void OverrideTests_Resolve_Factory_Lazy()\n    {\n        IStashboxContainer container = new StashboxContainer();\n        container.Register<ITest1, Test1>();\n        container.Register<ITest2, Test2>();\n\n        var inst1 = container.Resolve<ITest1>();\n        inst1.Name = \"test1\";\n        container.Resolve<ITest2>();\n\n        var factory = container.Resolve<Func<ITest1, Lazy<ITest2>>>();\n        var inst2 = factory(inst1);\n\n        Assert.NotNull(inst2);\n        Assert.IsType<Lazy<ITest2>>(inst2);\n        Assert.Equal(\"test1\", inst2.Value.Name);\n    }\n\n    [Fact]\n    public void OverrideTests_Resolve_Parallel_Lazy()\n    {\n        IStashboxContainer container = new StashboxContainer();\n        container.Register<ITest1, Test1>();\n        container.Register<ITest2, Test2>(context =>\n            context.WithInjectionParameter(\"test1\", new Test1 { Name = \"fakeName\" }));\n        var inst2 = container.Resolve<Lazy<ITest2>>();\n\n        Assert.IsType<Test2>(inst2.Value);\n        Assert.Equal(\"fakeName\", inst2.Value.Name);\n\n        container.Register<ITest3, Test3>();\n\n        Parallel.For(0, 50000, (i) =>\n        {\n            var inst1 = container.Resolve<Lazy<ITest1>>();\n            inst1.Value.Name = \"test1\";\n\n            var factory = container.Resolve<Func<ITest1, ITest2, Lazy<ITest3>>>();\n            var inst3 = factory(inst1.Value, inst2.Value);\n\n            Assert.NotNull(inst3);\n            Assert.IsType<Test3>(inst3.Value);\n            Assert.Equal(\"test1fakeNametest1\", inst3.Value.Name);\n            Assert.True(inst3.Value.MethodInvoked);\n        });\n    }\n\n    [Fact]\n    public void OverrideTests_Resolve_Multiple()\n    {\n        IStashboxContainer container = new StashboxContainer();\n        container.Register<ITest2, Test2>();\n        container.Register<ITest4, Test4>();\n        container.Register<ITest6, Test6>();\n\n        var inst4 = container.Resolve<ITest4>();\n\n        Assert.NotNull(inst4);\n        Assert.IsType<Test4>(inst4);\n        Assert.Equal(\"test2Test6\", inst4.Name);\n    }\n\n    [Fact]\n    public void OverrideTests_Resolve_DependencyOverride()\n    {\n        IStashboxContainer container = new StashboxContainer();\n        container.Register<ITest2, Test2>();\n\n        var inst = container.Resolve<ITest2>(dependencyOverrides: [new Test1 { Name = \"test\" }]);\n\n        Assert.NotNull(inst);\n        Assert.IsType<Test2>(inst);\n        Assert.Equal(\"test\", inst.Name);\n    }\n\n    [Fact]\n    public void OverrideTests_Resolve_DependencyOverride_Should_Not_Cached()\n    {\n        IStashboxContainer container = new StashboxContainer();\n        container.Register<ITest2, Test2>();\n\n        var inst = container.Resolve<ITest2>(dependencyOverrides: [new Test1 { Name = \"test\" }]);\n\n        Assert.NotNull(inst);\n        Assert.IsType<Test2>(inst);\n        Assert.Equal(\"test\", inst.Name);\n\n        var inst2 = container.Resolve<ITest2>(dependencyOverrides: [new Test1 { Name = \"test2\" }]);\n\n        Assert.NotNull(inst2);\n        Assert.IsType<Test2>(inst2);\n        Assert.Equal(\"test2\", inst2.Name);\n    }\n    \n    [Fact]\n    public void OverrideTests_Resolve_DependencyOverride_Named()\n    {\n        IStashboxContainer container = new StashboxContainer();\n        container.Register<ITest2, Test2>(c => c.WithDependencyBinding<ITest1>(\"test\"));\n\n        var inst = container.Resolve<ITest2>( \n        [\n            Override.Of(typeof(ITest1), new Test1 { Name = \"test\" }, \"test\"), \n            Override.Of<ITest1>(new Test1 { Name = \"test2\" }, \"test2\")\n        ]);\n\n        Assert.NotNull(inst);\n        Assert.IsType<Test2>(inst);\n        Assert.Equal(\"test\", inst.Name);\n\n        Assert.Throws<ResolutionFailedException>(() =>\n        {\n            container.Resolve<ITest2>(\n            [\n                Override.Of<ITest1>(new Test1 { Name = \"test\" }), \n                Override.Of<ITest1>(new Test1 { Name = \"test2\" })\n            ]);\n        });\n    }\n    \n    [Fact]\n    public void OverrideTests_Resolve_DependencyOverride_NotNamed()\n    {\n        IStashboxContainer container = new StashboxContainer();\n        container.Register<ITest2, Test2>();\n\n        var inst = container.Resolve<ITest2>(dependencyOverrides: \n        [\n            Override.Of<ITest1>(new Test1 { Name = \"test\" })\n        ]);\n\n        Assert.NotNull(inst);\n        Assert.IsType<Test2>(inst);\n        Assert.Equal(\"test\", inst.Name);\n    }\n\n    [Fact]\n    public void OverrideTests_Resolve_DependencyOverride_NonGeneric()\n    {\n        IStashboxContainer container = new StashboxContainer();\n        container.Register<ITest2, Test2>();\n\n        var inst = (ITest2)container.Resolve(typeof(ITest2), dependencyOverrides: [new Test1 { Name = \"test\" }]);\n\n        Assert.NotNull(inst);\n        Assert.IsType<Test2>(inst);\n        Assert.Equal(\"test\", inst.Name);\n    }\n\n    [Fact]\n    public void OverrideTests_Resolve_DependencyOverride_All()\n    {\n        IStashboxContainer container = new StashboxContainer();\n        container.Register<ITest2, Test2>();\n\n        var inst = container.ResolveAll<ITest2>([new Test1 { Name = \"test\" }]).First();\n\n        Assert.NotNull(inst);\n        Assert.IsType<Test2>(inst);\n        Assert.Equal(\"test\", inst.Name);\n    }\n\n    [Fact]\n    public void OverrideTests_Resolve_DependencyOverride_All_NonGeneric()\n    {\n        IStashboxContainer container = new StashboxContainer();\n        container.Register<ITest2, Test2>();\n\n        var inst = (ITest2)container.ResolveAll(typeof(ITest2), [new Test1 { Name = \"test\" }]).First();\n\n        Assert.NotNull(inst);\n        Assert.IsType<Test2>(inst);\n        Assert.Equal(\"test\", inst.Name);\n    }\n\n    [Fact]\n    public void OverrideTests_Resolve_Func()\n    {\n        using var container = new StashboxContainer();\n        container.RegisterFunc<string, ITest1>((name, dr) => new Test1 { Name = name });\n        container.Register<Test7>();\n\n        var inst = container.Resolve<Test7>();\n\n        Assert.NotNull(inst);\n        Assert.Equal(\"testfromfunc\", inst.Name);\n    }\n\n    [Fact]\n    public void OverrideTests_Resolve_Func_From_Parameter()\n    {\n        using var container = new StashboxContainer();\n        container.Register<Test8>().Register<Test9>();\n\n        container.Resolve<Test8>();\n        var inst = container.Resolve<Test9>();\n\n        Assert.NotNull(inst);\n        Assert.Equal(nameof(Test9), inst.Name);\n    }\n\n    private interface ITest1 { string Name { get; set; } }\n\n    private interface ITest2 { string Name { get; set; } }\n\n    private interface ITest3 { string Name { get; set; } bool MethodInvoked { get; } }\n\n    private interface ITest4 { string Name { get; set; } }\n\n    private interface ITest5 { string Name { get; set; } }\n\n    private interface ITest6 { string Name { get; set; } }\n\n    private class Test4 : ITest4\n    {\n        public string Name { get; set; }\n\n        public Test4(Func<ITest1, ITest2> test1, Func<ITest5, ITest6> test2)\n        {\n            this.Name = test1(new Test1 { Name = \"test2\" }).Name + test2(new Test5 { Name = \"Test6\" }).Name;\n        }\n    }\n\n    private class Test5 : ITest5\n    {\n        public string Name { get; set; }\n    }\n\n    private class Test6 : ITest6\n    {\n        public string Name { get; set; }\n\n        public Test6(ITest5 test1)\n        {\n            this.Name = test1.Name;\n        }\n    }\n\n    private class Test1 : ITest1\n    {\n        public string Name { get; set; }\n    }\n\n    private class Test2 : ITest2\n    {\n        public string Name { get; set; }\n\n        public Test2(ITest1 test1)\n        {\n            this.Name = test1.Name;\n        }\n    }\n\n    private class Test3 : ITest3\n    {\n        public string Name { get; set; }\n\n        public bool MethodInvoked { get; set; }\n\n        public Test3(ITest1 test1, ITest2 test2)\n        {\n            Name = test1.Name + test2.Name;\n        }\n\n        [InjectionMethod]\n        public void Inject(ITest1 test)\n        {\n            Shield.EnsureNotNull(test, nameof(test));\n            this.MethodInvoked = true;\n            Name += test.Name;\n        }\n    }\n\n    private class Test7\n    {\n        public string Name { get; set; }\n\n        public Test7(Func<string, ITest1> func)\n        {\n            this.Name = func(\"testfromfunc\").Name;\n        }\n    }\n\n    private class Test8\n    {\n        public string Name { get; set; }\n\n        public Test8(string name = \"\")\n        {\n            this.Name = name;\n        }\n    }\n\n    private class Test9\n    {\n        public string Name { get; set; }\n\n        public Test9(Func<string, Test8> func)\n        {\n            this.Name = func(nameof(Test9)).Name;\n        }\n    }\n}"
  },
  {
    "path": "test/PerRequestResolutionTests.cs",
    "content": "﻿using Stashbox.Configuration;\nusing Stashbox.Tests.Utils;\nusing System.Linq;\nusing Xunit;\n\nnamespace Stashbox.Tests;\n\npublic class PerRequestResolutionTests\n{\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void FromScope_PerRequest(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<IA, A1>(c => c.WithPerRequestLifetime()).Register<B>().Register<C>();\n\n        using var scope = container.BeginScope();\n        var c1 = scope.Resolve<C>();\n        var c2 = scope.Resolve<C>();\n        IA preA = new A2();\n        var c3 = scope.Resolve<C>(dependencyOverrides: [preA]);\n\n        Assert.IsType<A1>(c1.A);\n        Assert.IsType<A1>(c1.B.A);\n        Assert.IsType<A1>(c2.A);\n        Assert.IsType<A1>(c2.B.A);\n        Assert.IsType<A2>(c3.A);\n        Assert.IsType<A2>(c3.B.A);\n\n        Assert.Same(c1.A, c1.B.A);\n        Assert.Same(c2.A, c2.B.A);\n        Assert.NotSame(c1.A, c2.A);\n\n        Assert.Same(c3.A, c3.B.A);\n        Assert.Same(c3.A, preA);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void FromContainer_PerRequest(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<IA, A1>(c => c.WithPerRequestLifetime()).Register<B>().Register<C>();\n\n        var c1 = container.Resolve<C>();\n        var c2 = container.Resolve<C>();\n        IA preA = new A2();\n        var c3 = container.Resolve<C>(dependencyOverrides: [preA]);\n\n        Assert.IsType<A1>(c1.A);\n        Assert.IsType<A1>(c1.B.A);\n        Assert.IsType<A1>(c2.A);\n        Assert.IsType<A1>(c2.B.A);\n        Assert.IsType<A2>(c3.A);\n        Assert.IsType<A2>(c3.B.A);\n\n        Assert.Same(c1.A, c1.B.A);\n        Assert.Same(c2.A, c2.B.A);\n        Assert.NotSame(c1.A, c2.A);\n\n        Assert.Same(c3.A, c3.B.A);\n        Assert.Same(c3.A, preA);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void FromScope_PerRequest_Named(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<IA, A1>(c => c.WithPerRequestLifetime().WithName(\"A1\"))\n            .Register<IA, A2>(c => c.WithPerRequestLifetime().WithName(\"A2\"))\n            .Register<B>(c => c.WithDependencyBinding(\"a\", \"A1\"))\n            .Register<C>(c => c.WithName(\"C\").WithDependencyBinding(\"a\", \"A1\"));\n\n        using var scope = container.BeginScope();\n        var c1 = scope.Resolve<C>(\"C\");\n        var c2 = scope.Resolve<C>(\"C\");\n        IA preA = new A2();\n        var c3 = scope.Resolve<C>(\"C\", dependencyOverrides: [preA]);\n\n        Assert.IsType<A1>(c1.A);\n        Assert.IsType<A1>(c1.B.A);\n        Assert.IsType<A1>(c2.A);\n        Assert.IsType<A1>(c2.B.A);\n        Assert.IsType<A1>(c3.A);\n        Assert.IsType<A1>(c3.B.A);\n\n        Assert.Same(c1.A, c1.B.A);\n        Assert.Same(c2.A, c2.B.A);\n        Assert.NotSame(c1.A, c2.A);\n\n        Assert.Same(c3.A, c3.B.A);\n        Assert.NotSame(c3.A, preA);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void FromContainer_PerRequest_Named(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<IA, A1>(c => c.WithPerRequestLifetime().WithName(\"A1\"))\n            .Register<IA, A2>(c => c.WithPerRequestLifetime().WithName(\"A2\"))\n            .Register<B>(c => c.WithDependencyBinding(\"a\", \"A1\"))\n            .Register<C>(c => c.WithName(\"C\").WithDependencyBinding(\"a\", \"A1\"));\n\n        var c1 = container.Resolve<C>(\"C\");\n        var c2 = container.Resolve<C>(\"C\");\n        IA preA = new A2();\n        var c3 = container.Resolve<C>(\"C\", dependencyOverrides: [preA]);\n\n        Assert.IsType<A1>(c1.A);\n        Assert.IsType<A1>(c1.B.A);\n        Assert.IsType<A1>(c2.A);\n        Assert.IsType<A1>(c2.B.A);\n        Assert.IsType<A1>(c3.A);\n        Assert.IsType<A1>(c3.B.A);\n\n        Assert.Same(c1.A, c1.B.A);\n        Assert.Same(c2.A, c2.B.A);\n        Assert.NotSame(c1.A, c2.A);\n\n        Assert.Same(c3.A, c3.B.A);\n        Assert.NotSame(c3.A, preA);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void FromScope_GetService(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<IA, A1>()\n            .Register<B>()\n            .Register<C>();\n\n        using var scope = container.BeginScope();\n\n        var c1 = (C)scope.GetService(typeof(C));\n        var c2 = (C)scope.GetService(typeof(C));\n\n        Assert.NotSame(c1.A, c1.B.A);\n        Assert.NotSame(c2.A, c2.B.A);\n        Assert.NotSame(c1.A, c2.A);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void FromScope_GetService_Null(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<C>();\n\n        using var scope = container.BeginScope();\n        Assert.Null(scope.GetService(typeof(C)));\n    }\n\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void FromScope_PerRequest_GetService(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<IA, A1>(c => c.WithPerRequestLifetime())\n            .Register<B>()\n            .Register<C>();\n\n        using var scope = container.BeginScope();\n\n        var c1 = (C)scope.GetService(typeof(C));\n        var c2 = (C)scope.GetService(typeof(C));\n\n        Assert.IsType<A1>(c1.A);\n        Assert.IsType<A1>(c1.B.A);\n        Assert.IsType<A1>(c2.A);\n        Assert.IsType<A1>(c2.B.A);\n\n        Assert.Same(c1.A, c1.B.A);\n        Assert.Same(c2.A, c2.B.A);\n        Assert.NotSame(c1.A, c2.A);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void FromContainer_GetService(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<IA, A1>()\n            .Register<B>()\n            .Register<C>();\n\n        var c1 = (C)container.GetService(typeof(C));\n        var c2 = (C)container.GetService(typeof(C));\n\n        Assert.NotSame(c1.A, c1.B.A);\n        Assert.NotSame(c2.A, c2.B.A);\n        Assert.NotSame(c1.A, c2.A);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void FromContainer_GetService_Null(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<C>();\n\n        Assert.Null(container.GetService(typeof(C)));\n    }\n\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void FromContainer_PerRequest_GetService(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<IA, A1>(c => c.WithPerRequestLifetime())\n            .Register<B>()\n            .Register<C>();\n\n        var c1 = (C)container.GetService(typeof(C));\n        var c2 = (C)container.GetService(typeof(C));\n\n        Assert.IsType<A1>(c1.A);\n        Assert.IsType<A1>(c1.B.A);\n        Assert.IsType<A1>(c2.A);\n        Assert.IsType<A1>(c2.B.A);\n\n        Assert.Same(c1.A, c1.B.A);\n        Assert.Same(c2.A, c2.B.A);\n        Assert.NotSame(c1.A, c2.A);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void FromScope_PerRequest_ResolveAll(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<IA, A1>(c => c.WithPerRequestLifetime())\n            .Register<B>()\n            .Register<C>();\n\n        using var scope = container.BeginScope();\n\n        var each = scope.ResolveAll(typeof(C)).Cast<C>().ToArray();\n\n        Assert.Same(each[0].A, each[0].B.A);\n\n        IA preA = new A2();\n\n        each = scope.ResolveAll(typeof(C), [preA]).Cast<C>().ToArray();\n\n        Assert.IsType<A2>(each[0].A);\n        Assert.Same(each[0].A, each[0].B.A);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void FromScope_PerRequest_ResolveAll_Generic(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<IA, A1>(c => c.WithPerRequestLifetime())\n            .Register<B>()\n            .Register<C>();\n\n        using var scope = container.BeginScope();\n\n        var each = scope.ResolveAll<C>().ToArray();\n\n        Assert.Same(each[0].A, each[0].B.A);\n\n        IA preA = new A2();\n\n        each = scope.ResolveAll<C>([preA]).ToArray();\n\n        Assert.IsType<A2>(each[0].A);\n        Assert.Same(each[0].A, each[0].B.A);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void FromContainer_PerRequest_ResolveAll(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<IA, A1>(c => c.WithPerRequestLifetime())\n            .Register<B>()\n            .Register<C>();\n\n        var each = container.ResolveAll(typeof(C)).Cast<C>().ToArray();\n\n        Assert.Same(each[0].A, each[0].B.A);\n\n        IA preA = new A2();\n\n        each = container.ResolveAll(typeof(C), [preA]).Cast<C>().ToArray();\n\n        Assert.IsType<A2>(each[0].A);\n        Assert.Same(each[0].A, each[0].B.A);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void FromContainer_PerRequest_ResolveAll_Generic(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<IA, A1>(c => c.WithPerRequestLifetime())\n            .Register<B>()\n            .Register<C>();\n\n        var each = container.ResolveAll<C>().ToArray();\n\n        Assert.Same(each[0].A, each[0].B.A);\n\n        IA preA = new A2();\n\n        each = container.ResolveAll<C>([preA]).ToArray();\n\n        Assert.IsType<A2>(each[0].A);\n        Assert.Same(each[0].A, each[0].B.A);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void FromScope_PerRequest_Activate(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<IA, A1>(c => c.WithPerRequestLifetime())\n            .Register<B>();\n\n        using var scope = container.BeginScope();\n\n        var c = scope.Activate<C>();\n\n        Assert.IsType<A1>(c.A);\n        Assert.IsType<A1>(c.B.A);\n\n        Assert.Same(c.A, c.B.A);\n\n        IA preA = new A2();\n\n        c = scope.Activate<C>([preA]);\n\n        Assert.IsType<A2>(c.A);\n        Assert.IsType<A2>(c.B.A);\n\n        Assert.Same(c.A, c.B.A);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void FromContainer_PerRequest_Activate(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<IA, A1>(c => c.WithPerRequestLifetime())\n            .Register<B>();\n\n        var c = container.Activate<C>();\n\n        Assert.IsType<A1>(c.A);\n        Assert.IsType<A1>(c.B.A);\n\n        Assert.Same(c.A, c.B.A);\n\n        IA preA = new A2();\n\n        c = container.Activate<C>([preA]);\n\n        Assert.IsType<A2>(c.A);\n        Assert.IsType<A2>(c.B.A);\n\n        Assert.Same(c.A, c.B.A);\n    }\n\n    interface IA;\n\n    class A1 : IA;\n\n    class A2 : IA;\n\n    class B\n    {\n        public B(IA a)\n        {\n            A = a;\n        }\n\n        public IA A { get; }\n    }\n\n    class C\n    {\n        public C(B b, IA a)\n        {\n            B = b;\n            A = a;\n        }\n\n        public B B { get; }\n        public IA A { get; }\n    }\n}"
  },
  {
    "path": "test/ReMapTests.cs",
    "content": "﻿using Stashbox.Exceptions;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing Xunit;\n\nnamespace Stashbox.Tests;\n\npublic class ReMapTests\n{\n    [Fact]\n    public void ReMapTests_Replace_SingleResolve()\n    {\n        using var container = new StashboxContainer();\n        container.Register<ITest1, Test1>(context => context.WithName(\"test\"));\n        container.Register<ITest1, Test12>(context => context.WithName(\"test2\"));\n\n        var test1 = container.Resolve<ITest1>(\"test\");\n        var test2 = container.Resolve<ITest1>(\"test2\");\n\n        Assert.IsType<Test1>(test1);\n        Assert.IsType<Test12>(test2);\n\n        container.Register<ITest1, Test11>(context => context.WithName(\"test\").ReplaceExisting());\n\n        var test11 = container.Resolve<ITest1>(\"test\");\n        var test12 = container.Resolve<ITest1>(\"test2\");\n\n        Assert.IsType<Test11>(test11);\n        Assert.IsType<Test12>(test12);\n    }\n\n    [Fact]\n    public void ReMapTests_Replace_PreserveOrder()\n    {\n        using var container = new StashboxContainer();\n        container.Register<ITest1, Test1>(context => context.WithName(\"test\"));\n        container.Register<ITest1, Test12>(context => context.WithName(\"test2\"));\n\n        var toReplace = container.GetRegistrationMappings()\n            .Single(r => \"test\".Equals(r.Value.Name));\n\n        container.Register<ITest1, Test11>(context => context.WithName(\"test\").ReplaceExisting());\n\n        var newReg = container.GetRegistrationMappings()\n            .Single(r => \"test\".Equals(r.Value.Name));\n\n        Assert.Equal(toReplace.Value.RegistrationOrder, newReg.Value.RegistrationOrder);\n    }\n\n    [Fact]\n    public void ReMapTests_Replace_Enumerable_Named()\n    {\n        using var container = new StashboxContainer();\n        container.Register<ITest1, Test1>(context => context.WithName(\"test\"));\n        container.Register<ITest1, Test12>(context => context.WithName(\"test2\"));\n\n        var coll = container.Resolve<IEnumerable<ITest1>>().ToArray();\n\n        Assert.IsType<Test1>(coll[0]);\n        Assert.IsType<Test12>(coll[1]);\n\n        container.Register<ITest1, Test11>(context => context.WithName(\"test\").ReplaceExisting());\n\n        var coll2 = container.Resolve<IEnumerable<ITest1>>().ToArray();\n\n        Assert.IsType<Test11>(coll2[0]);\n        Assert.IsType<Test12>(coll2[1]);\n    }\n\n    [Fact]\n    public void ReMapTests_ReMap_Replace_Only_If_Exists()\n    {\n        using var container = new StashboxContainer();\n        container.Register<ITest1, Test1>(context => context.WithName(\"test\"));\n        container.Register<ITest1, Test12>(context => context.WithName(\"test2\"));\n\n        var test1 = container.Resolve<ITest1>(\"test\");\n        var test2 = container.Resolve<ITest1>(\"test2\");\n\n        Assert.IsType<Test1>(test1);\n        Assert.IsType<Test12>(test2);\n\n        container.ReMap<ITest1, Test11>(context => context.WithName(\"test\").ReplaceOnlyIfExists());\n\n        Assert.Throws<ResolutionFailedException>(() => container.Resolve<ITest1>(\"test2\"));\n\n        var test11 = container.Resolve<ITest1>(\"test\");\n        Assert.IsType<Test11>(test11);\n    }\n\n    [Fact]\n    public void ReMapTests_Replace_Only_If_Exists()\n    {\n        using var container = new StashboxContainer();\n        container.Register<ITest1, Test1>(context => context.WithName(\"test\"));\n        container.Register<ITest1, Test12>(context => context.WithName(\"test2\"));\n\n        var test1 = container.Resolve<ITest1>(\"test\");\n        var test2 = container.Resolve<ITest1>(\"test2\");\n\n        Assert.IsType<Test1>(test1);\n        Assert.IsType<Test12>(test2);\n\n        container.Register<ITest1, Test11>(context => context.WithName(\"test\").ReplaceOnlyIfExists());\n\n        var test11 = container.Resolve<ITest1>(\"test\");\n        var test12 = container.Resolve<ITest1>(\"test2\");\n\n        Assert.IsType<Test11>(test11);\n        Assert.IsType<Test12>(test12);\n    }\n\n    [Fact]\n    public void ReMapTests_Dont_Replace_If_Not_Exists()\n    {\n        using var container = new StashboxContainer();\n        container.Register<ITest1, Test1>(context => context.WithName(\"test\"));\n\n        var test1 = container.Resolve<ITest1>(\"test\");\n        Assert.IsType<Test1>(test1);\n\n        container.Register<ITest1, Test11>(context => context.WithName(\"test2\").ReplaceOnlyIfExists());\n\n        var test11 = container.Resolve<ITest1>(\"test\");\n        Assert.IsType<Test1>(test11);\n\n        Assert.Throws<ResolutionFailedException>(() => container.Resolve<ITest1>(\"test2\"));\n    }\n\n    [Fact]\n    public void ReMapTests_ReMap_Replaces_Every_Registration()\n    {\n        using var container = new StashboxContainer();\n        container.Register<ITest1, Test1>(context => context.WithName(\"test\"));\n\n        var test1 = container.Resolve<ITest1>(\"test\");\n        Assert.IsType<Test1>(test1);\n\n        container.ReMap<ITest1, Test11>(context => context.WithName(\"test2\").ReplaceOnlyIfExists());\n\n        Assert.Throws<ResolutionFailedException>(() => container.Resolve<ITest1>(\"test\"));\n\n        var test11 = container.Resolve<ITest1>(\"test2\");\n        Assert.IsType<Test11>(test11);\n    }\n\n    [Fact]\n    public void ReMapTests_ReMap_Without_Name()\n    {\n        using var container = new StashboxContainer();\n        container.Register<ITest1, Test1>();\n\n        var test1 = container.Resolve<ITest1>();\n        Assert.IsType<Test1>(test1);\n\n        container.ReMap<ITest1, Test11>(context => context.ReplaceOnlyIfExists());\n\n        var test11 = container.Resolve<ITest1>();\n        Assert.IsType<Test11>(test11);\n    }\n\n    [Fact]\n    public void ReMapTests_Replace_Only_If_Exists_Instance()\n    {\n        using var container = new StashboxContainer();\n        var t1 = new Test1();\n        container.Register<ITest1>(c => c.WithInstance(t1));\n\n        var i1 = container.Resolve<ITest1>();\n        var i2 = container.Resolve<ITest1>();\n\n        Assert.Same(t1, i1);\n        Assert.Same(i1, i2);\n\n        var t2 = new Test1();\n        container.Register<ITest1>(c => c.WithInstance(t2).ReplaceOnlyIfExists());\n\n        i1 = container.Resolve<ITest1>();\n        i2 = container.Resolve<ITest1>();\n\n        Assert.Same(t2, i1);\n        Assert.Same(i1, i2);\n\n        Assert.NotSame(t1, i1);\n        Assert.NotSame(t1, i2);\n    }\n\n    [Fact]\n    public void ReMapTests_ReMap_Replace_Only_If_Exists_Instance()\n    {\n        using var container = new StashboxContainer();\n        var t1 = new Test1();\n        container.Register<ITest1>(c => c.WithInstance(t1));\n\n        var i1 = container.Resolve<ITest1>();\n        var i2 = container.Resolve<ITest1>();\n\n        Assert.Same(t1, i1);\n        Assert.Same(i1, i2);\n\n        var t2 = new Test1();\n        container.ReMap<ITest1>(c => c.WithInstance(t2).ReplaceOnlyIfExists());\n\n        i1 = container.Resolve<ITest1>();\n        i2 = container.Resolve<ITest1>();\n\n        Assert.Same(t2, i1);\n        Assert.Same(i1, i2);\n\n        Assert.NotSame(t1, i1);\n        Assert.NotSame(t1, i2);\n    }\n\n    [Fact]\n    public void ReMapTests_Dont_Replace_If_Instance_Is_Not_Existing()\n    {\n        using var container = new StashboxContainer();\n        var t1 = new Test1();\n        container.Register<Test1>(c => c.WithInstance(t1).ReplaceOnlyIfExists());\n\n        Assert.Throws<ResolutionFailedException>(() => container.Resolve<Test1>());\n    }\n\n    [Fact]\n    public void ReMapTests_ReMap_Dont_Replace_If_Instance_Is_Not_Existing()\n    {\n        using var container = new StashboxContainer();\n        var t1 = new Test1();\n        container.ReMap<Test1>(c => c.WithInstance(t1).ReplaceOnlyIfExists());\n\n        Assert.Throws<ResolutionFailedException>(() => container.Resolve<Test1>());\n    }\n\n    [Fact]\n    public void ReMapTests_Enumerable_Named()\n    {\n        using var container = new StashboxContainer();\n        container.Register<ITest1, Test1>(context => context.WithName(\"test\"));\n        container.Register<ITest1, Test12>(context => context.WithName(\"test2\"));\n\n        var coll = container.Resolve<IEnumerable<ITest1>>().ToArray();\n\n        Assert.Equal(2, coll.Length);\n        Assert.IsType<Test1>(coll[0]);\n        Assert.IsType<Test12>(coll[1]);\n\n        container.ReMap<ITest1, Test11>();\n\n        var coll2 = container.Resolve<IEnumerable<ITest1>>().ToArray();\n\n        Assert.Single(coll2);\n        Assert.IsType<Test11>(coll2[0]);\n    }\n\n    [Fact]\n    public void ReMapTests_Func_Named()\n    {\n        using var container = new StashboxContainer();\n        container.Register<ITest1, Test12>(context => context.WithName(\"test2\"));\n        container.Register<ITest1, Test1>(context => context.WithName(\"test\"));\n\n        container.Resolve<Func<ITest1>>(\"test2\");\n\n        var func = container.Resolve<Func<ITest1>>(\"test\");\n\n        Assert.IsType<Test1>(func());\n\n        container.ReMap<ITest1, Test11>(context => context.WithName(\"test\"));\n\n        var func2 = container.Resolve<Func<ITest1>>(\"test\");\n\n        Assert.IsType<Test11>(func2());\n    }\n\n    [Fact]\n    public void ReMapTests_Lazy_Named()\n    {\n        using var container = new StashboxContainer();\n        container.Register<ITest1, Test12>(context => context.WithName(\"test2\"));\n        container.Register<ITest1, Test1>(context => context.WithName(\"test\"));\n\n        container.Resolve<Lazy<ITest1>>(\"test\");\n\n        var lazy = container.Resolve<Lazy<ITest1>>(\"test\");\n\n        Assert.IsType<Test1>(lazy.Value);\n\n        container.ReMap<ITest1, Test11>(config => config.WithName(\"test\"));\n\n        var lazy2 = container.Resolve<Lazy<ITest1>>(\"test\");\n\n        Assert.IsType<Test11>(lazy2.Value);\n    }\n\n    [Fact]\n    public void ReMapTests_Enumerable()\n    {\n        using var container = new StashboxContainer();\n        container.Register<ITest1, Test1>();\n\n        var coll = container.Resolve<IEnumerable<ITest1>>().ToArray();\n\n        Assert.IsType<Test1>(coll[0]);\n\n        container.ReMap<ITest1, Test11>();\n\n        var coll2 = container.Resolve<IEnumerable<ITest1>>().ToArray();\n\n        Assert.IsType<Test11>(coll2[0]);\n    }\n\n    [Fact]\n    public void ReMapTests_Func()\n    {\n        using var container = new StashboxContainer();\n        container.Register<ITest1, Test1>();\n\n        var func = container.Resolve<Func<ITest1>>();\n\n        Assert.IsType<Test1>(func());\n\n        container.ReMap<ITest1, Test11>();\n\n        var func2 = container.Resolve<Func<ITest1>>();\n\n        Assert.IsType<Test11>(func2());\n    }\n\n    [Fact]\n    public void ReMapTests_Lazy()\n    {\n        using var container = new StashboxContainer();\n        container.Register<ITest1, Test1>();\n\n        var lazy = container.Resolve<Lazy<ITest1>>();\n\n        Assert.IsType<Test1>(lazy.Value);\n\n        container.ReMap<ITest1, Test11>();\n\n        var lazy2 = container.Resolve<Lazy<ITest1>>();\n\n        Assert.IsType<Test11>(lazy2.Value);\n    }\n\n    [Fact]\n    public void ReMapTests_DependencyResolve()\n    {\n        using var container = new StashboxContainer();\n        container.Register<ITest1, Test1>();\n        container.Register<ITest2, Test2>();\n\n        var test2 = container.Resolve<ITest2>();\n\n        Assert.NotNull(test2.Test1);\n        Assert.IsType<Test1>(test2.Test1);\n\n        container.ReMap<ITest1>(typeof(Test11));\n\n        var test22 = container.Resolve<ITest2>();\n\n        Assert.NotNull(test22.Test1);\n        Assert.IsType<Test11>(test22.Test1);\n    }\n\n    [Fact]\n    public void ReMapTests_DependencyResolve_WithoutService()\n    {\n        using var container = new StashboxContainer();\n        container.RegisterSingleton<Test11>();\n        container.Register<Test3>();\n\n        var inst = container.Resolve<Test3>();\n\n        var dep = inst.Test1;\n\n        Assert.NotNull(dep);\n        Assert.IsType<Test11>(dep);\n\n        container.ReMap<Test11>();\n\n        inst = container.Resolve<Test3>();\n\n        Assert.NotNull(inst.Test1);\n        Assert.IsType<Test11>(inst.Test1);\n\n        Assert.NotSame(dep, inst.Test1);\n    }\n\n    [Fact]\n    public void ReMapTests_DependencyResolve_Fluent()\n    {\n        using var container = new StashboxContainer();\n        container.Register<ITest1>(typeof(Test1));\n        container.Register<ITest2, Test2>();\n\n        var test2 = container.Resolve<ITest2>();\n\n        Assert.NotNull(test2.Test1);\n        Assert.IsType<Test1>(test2.Test1);\n\n        container.ReMap<ITest1>(typeof(Test11));\n\n        var test22 = container.Resolve<ITest2>();\n\n        Assert.NotNull(test22.Test1);\n        Assert.IsType<Test11>(test22.Test1);\n    }\n\n    [Fact]\n    public void ReMapTests_Throws_When_TypeMap_Invalid()\n    {\n        using var container = new StashboxContainer();\n        Assert.Throws<InvalidRegistrationException>(() => container.ReMap<ITest1>(typeof(Test2)));\n        Assert.Throws<InvalidRegistrationException>(() => container.ReMap(typeof(ITest1), typeof(Test2)));\n        Assert.Throws<InvalidRegistrationException>(() => container.ReMap<ITest1>());\n        Assert.Throws<InvalidRegistrationException>(() => container.ReMapDecorator(typeof(ITest1), typeof(Test2)));\n    }\n\n    interface ITest1;\n\n    interface ITest2\n    {\n        ITest1 Test1 { get; }\n    }\n\n    class Test1 : ITest1;\n\n    class Test11 : ITest1;\n\n    class Test12 : ITest1;\n\n    class Test2 : ITest2\n    {\n        public ITest1 Test1 { get; }\n\n        public Test2(ITest1 test1)\n        {\n            this.Test1 = test1;\n        }\n    }\n\n    class Test3\n    {\n        public Test11 Test1 { get; }\n\n        public Test3(Test11 test1)\n        {\n            this.Test1 = test1;\n        }\n    }\n}"
  },
  {
    "path": "test/RegisterTypesTests.cs",
    "content": "﻿using Stashbox.Exceptions;\nusing Stashbox.Lifetime;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing Xunit;\n\nnamespace Stashbox.Tests;\n\npublic class RegistersTests\n{\n    [Fact]\n    public void RegistersTests_RegistersAs()\n    {\n        IStashboxContainer container = new StashboxContainer();\n        container.RegisterTypesAs<ITest1>(new[] { typeof(Test1), typeof(Test11), typeof(Test12) });\n\n        var all = container.Resolve<IEnumerable<ITest1>>();\n\n        Assert.Equal(3, all.Count());\n    }\n\n    [Fact]\n    public void RegistersTests_RegistersAs_Assembly()\n    {\n        IStashboxContainer container = new StashboxContainer();\n        container.RegisterTypesAs<ITest1>(typeof(ITest1).Assembly,\n            t => t == typeof(Test1) || t == typeof(Test11) || t == typeof(Test12));\n\n        var all = container.Resolve<IEnumerable<ITest1>>();\n\n        Assert.Equal(3, all.Count());\n    }\n\n    [Fact]\n    public void RegistersTests_RegistersAs_Selector()\n    {\n        IStashboxContainer container = new StashboxContainer();\n        container.RegisterTypesAs<ITest1>(new[] { typeof(Test1), typeof(Test11), typeof(Test12) }, type => type == typeof(Test12));\n\n        var all = container.Resolve<IEnumerable<ITest1>>();\n\n        Assert.Single(all);\n    }\n\n    [Fact]\n    public void RegistersTests_RegistersAsSelf_Selector()\n    {\n        IStashboxContainer container = new StashboxContainer();\n        container.RegisterTypes(new[] { typeof(Test1), typeof(Test11), typeof(Test12) }, type => type == typeof(Test12));\n\n        Assert.NotNull(container.Resolve<Test12>());\n    }\n\n    [Fact]\n    public void RegistersTests_RegistersAs_Scoped()\n    {\n        IStashboxContainer container = new StashboxContainer();\n        container.RegisterTypesAs<ITest1>(new[] { typeof(Test1), typeof(Test11), typeof(Test12), typeof(Test2) }, configurator: context => context.WithScopedLifetime());\n\n        var regs = container.ContainerContext.RegistrationRepository.GetRegistrationMappings().ToArray();\n\n        Assert.Equal(3, regs.Length);\n        Assert.True(regs.All(reg => reg.Value.Lifetime is ScopedLifetime));\n    }\n\n    [Fact]\n    public void RegistersTests_RegistersAsSelf_Scoped_Selector()\n    {\n        IStashboxContainer container = new StashboxContainer();\n        container.RegisterTypes(new[] { typeof(Test1), typeof(Test11), typeof(Test12) }, type => type == typeof(Test12), configurator: context => context.WithScopedLifetime());\n\n        var regs = container.ContainerContext.RegistrationRepository.GetRegistrationMappings().ToArray();\n\n        Assert.Equal(4, regs.Length);\n        Assert.True(regs.All(reg => reg.Value.Lifetime is ScopedLifetime));\n    }\n\n    [Fact]\n    public void RegistersTests_Registers()\n    {\n        IStashboxContainer container = new StashboxContainer();\n        container.RegisterTypes(new[] { typeof(Test), typeof(Test1), typeof(Test11), typeof(Test12) });\n\n        var test = container.ResolveAll<ITest>();\n        var test1 = container.ResolveAll<ITest1>();\n        var test2 = container.ResolveAll<ITest2>();\n\n        Assert.Equal(3, test.Count());\n        Assert.Equal(3, test1.Count());\n        Assert.Equal(2, test2.Count());\n    }\n\n    [Fact]\n    public void RegistersTests_Registers_Selector()\n    {\n        IStashboxContainer container = new StashboxContainer();\n        container.RegisterTypes(new[] { typeof(Test), typeof(Test1), typeof(Test11), typeof(Test12) }, type => type == typeof(Test12));\n\n        var test = container.ResolveAll<ITest>();\n        var test1 = container.ResolveAll<ITest1>();\n        var test2 = container.ResolveAll<ITest2>();\n\n        Assert.Single(test);\n        Assert.Single(test1);\n        Assert.Single(test2);\n    }\n\n    [Fact]\n    public void RegistersTests_Registers_Configurator()\n    {\n        IStashboxContainer container = new StashboxContainer();\n        container.RegisterTypes(new[] { typeof(Test), typeof(Test1), typeof(Test11), typeof(Test12) }, configurator: context =>\n        {\n            if (context.HasServiceType(typeof(ITest2)))\n                context.WithScopedLifetime();\n        });\n\n        using var scope = container.BeginScope();\n\n        var test = scope.ResolveAll<ITest>();\n        var test1 = scope.ResolveAll<ITest1>();\n        var test2 = scope.ResolveAll<ITest2>();\n\n        var scopeds = container.ContainerContext.RegistrationRepository.GetRegistrationMappings()\n            .Where(r => r.Value.Lifetime is ScopedLifetime).ToArray();\n\n        Assert.Equal(3, test.Count());\n        Assert.Equal(3, test1.Count());\n        Assert.Equal(2, test2.Count());\n        Assert.Equal(7, scopeds.Length);\n    }\n\n    [Fact]\n    public void RegistersTests_ComposeBy()\n    {\n        IStashboxContainer container = new StashboxContainer();\n        container.ComposeBy(typeof(TestCompositionRoot));\n\n        var regs = container.ContainerContext.RegistrationRepository.GetRegistrationMappings()\n            .OrderBy(r => r.Value.RegistrationId).ToArray();\n\n        Assert.Equal(2, regs.Length);\n        Assert.Same(regs[0].Value.ImplementationType, typeof(Test));\n        Assert.Same(regs[1].Value.ImplementationType, typeof(Test1));\n    }\n\n    [Fact]\n    public void RegistersTests_ComposeBy_Throw_DoesntImplement_ICompositionRoot()\n    {\n        IStashboxContainer container = new StashboxContainer();\n        Assert.Throws<ArgumentException>(() => container.ComposeBy(typeof(Test)));\n    }\n\n    [Fact]\n    public void RegistersTests_ComposeBy_Generic()\n    {\n        IStashboxContainer container = new StashboxContainer();\n        container.ComposeBy<TestCompositionRoot>();\n\n        var regs = container.ContainerContext.RegistrationRepository.GetRegistrationMappings()\n            .OrderBy(r => r.Value.RegistrationId).ToArray();\n\n        Assert.Equal(2, regs.Length);\n        Assert.Same(regs[0].Value.ImplementationType, typeof(Test));\n        Assert.Same(regs[1].Value.ImplementationType, typeof(Test1));\n    }\n\n    [Fact]\n    public void RegistersTests_ComposeAssembly()\n    {\n        IStashboxContainer container = new StashboxContainer();\n        container.ComposeAssembly(this.GetType().Assembly, type => !type.FullName.Contains(\"IssueTests\"));\n\n        var regs = container\n            .GetRegistrationMappings()\n            .OrderBy(r => r.Value.RegistrationId)\n            .ToArray();\n\n        Assert.Equal(4, regs.Length);\n        Assert.Same(regs[0].Value.ImplementationType, typeof(Test));\n        Assert.Same(regs[1].Value.ImplementationType, typeof(Test1));\n        Assert.Same(regs[2].Value.ImplementationType, typeof(Test11));\n        Assert.Same(regs[3].Value.ImplementationType, typeof(Test12));\n    }\n\n    [Fact]\n    public void RegistersTests_ComposeAssemblies()\n    {\n        IStashboxContainer container = new StashboxContainer();\n        container.ComposeAssemblies(new[] { this.GetType().Assembly }, type => !type.FullName.Contains(\"IssueTests\"));\n\n        var regs = container.ContainerContext.RegistrationRepository\n            .GetRegistrationMappings()\n            .OrderBy(r => r.Value.RegistrationId)\n            .ToArray();\n\n        Assert.Equal(4, regs.Length);\n        Assert.Same(regs[0].Value.ImplementationType, typeof(Test));\n        Assert.Same(regs[1].Value.ImplementationType, typeof(Test1));\n        Assert.Same(regs[2].Value.ImplementationType, typeof(Test11));\n        Assert.Same(regs[3].Value.ImplementationType, typeof(Test12));\n    }\n\n    [Fact]\n    public void RegistersTests_ComposeAssembly_CompositionRootNotFound()\n    {\n        IStashboxContainer container = new StashboxContainer();\n        Assert.Throws<CompositionRootNotFoundException>(() =>\n            container.ComposeAssemblies(new[] { typeof(IStashboxContainer).Assembly }));\n    }\n\n    [Fact]\n    public void RegistersTests_AsImplementedTypes_Interfaces()\n    {\n        var container = new StashboxContainer();\n        container.Register<Test12>(context => context.AsImplementedTypes());\n\n        var regs = container.ContainerContext.RegistrationRepository.GetRegistrationMappings()\n            .OrderBy(r => r.Key.Name).ToArray();\n\n        Assert.Equal(4, regs.Length);\n        Assert.Same(regs[0].Key, typeof(ITest));\n        Assert.Same(regs[1].Key, typeof(ITest1));\n        Assert.Same(regs[2].Key, typeof(ITest2));\n        Assert.Same(regs[3].Key, typeof(Test12));\n    }\n\n    [Fact]\n    public void RegistersTests_AsImplementedTypes_Interfaces_NoDuplicate()\n    {\n        var container = new StashboxContainer();\n        container.Register<Test12>(context => context\n            .AsImplementedTypes().AsImplementedTypes().AsServiceAlso<ITest1>().AsImplementedTypes());\n\n        var regs = container.ContainerContext.RegistrationRepository.GetRegistrationMappings()\n            .OrderBy(r => r.Key.Name).ToArray();\n\n        Assert.Equal(4, regs.Length);\n        Assert.Same(regs[0].Key, typeof(ITest));\n        Assert.Same(regs[1].Key, typeof(ITest1));\n        Assert.Same(regs[2].Key, typeof(ITest2));\n        Assert.Same(regs[3].Key, typeof(Test12));\n    }\n\n    [Fact]\n    public void RegistersTests_AsImplementedTypes_Interfaces_ReMap()\n    {\n        var container = new StashboxContainer();\n        container.Register<Test12>(context => context.AsImplementedTypes());\n\n        var regs = container.ContainerContext.RegistrationRepository.GetRegistrationMappings().OrderBy(r => r.Key.Name).ToArray();\n\n        container.ReMap<Test12>(context => context.AsImplementedTypes());\n\n        var regs2 = container.ContainerContext.RegistrationRepository.GetRegistrationMappings().OrderBy(r => r.Key.Name).ToArray();\n\n        Assert.Equal(regs.Length, regs2.Length);\n        Assert.NotEqual(regs[0].Value.RegistrationId, regs2[0].Value.RegistrationId);\n        Assert.NotEqual(regs[1].Value.RegistrationId, regs2[1].Value.RegistrationId);\n        Assert.NotEqual(regs[2].Value.RegistrationId, regs2[2].Value.RegistrationId);\n        Assert.NotEqual(regs[3].Value.RegistrationId, regs2[3].Value.RegistrationId);\n    }\n\n    [Fact]\n    public void RegistersTests_AsImplementedTypes_BaseType()\n    {\n        var container = new StashboxContainer();\n        container.Register(typeof(Test14), context => context.AsImplementedTypes());\n\n        var regs = container.ContainerContext.RegistrationRepository.GetRegistrationMappings()\n            .OrderBy(r => r.Key.Name).ToArray();\n\n        Assert.Equal(6, regs.Length);\n        Assert.Same(regs[0].Key, typeof(ITest));\n        Assert.Same(regs[1].Key, typeof(ITest1));\n        Assert.Same(regs[2].Key, typeof(ITest2));\n        Assert.Same(regs[3].Key, typeof(Test12));\n        Assert.Same(regs[4].Key, typeof(Test13));\n        Assert.Same(regs[5].Key, typeof(Test14));\n    }\n\n    [Fact]\n    public void RegistersTests_AsImplementedTypes_BaseType_ReMap()\n    {\n        var container = new StashboxContainer();\n        container.Register<Test14>(context => context.AsImplementedTypes());\n\n        var regs = container.ContainerContext.RegistrationRepository.GetRegistrationMappings()\n            .OrderBy(r => r.Key.Name).ToArray();\n\n        container.ReMap<Test14>(context => context.AsImplementedTypes());\n\n        var regs2 = container.ContainerContext.RegistrationRepository.GetRegistrationMappings()\n            .OrderBy(r => r.Key.Name).ToArray();\n\n        Assert.Equal(regs.Length, regs2.Length);\n        Assert.NotEqual(regs[0].Value.RegistrationId, regs2[0].Value.RegistrationId);\n        Assert.NotEqual(regs[1].Value.RegistrationId, regs2[1].Value.RegistrationId);\n        Assert.NotEqual(regs[2].Value.RegistrationId, regs2[2].Value.RegistrationId);\n        Assert.NotEqual(regs[3].Value.RegistrationId, regs2[3].Value.RegistrationId);\n        Assert.NotEqual(regs[4].Value.RegistrationId, regs2[4].Value.RegistrationId);\n        Assert.NotEqual(regs[5].Value.RegistrationId, regs2[5].Value.RegistrationId);\n    }\n\n    [Fact]\n    public void RegistersTests_Generic_ByInterface()\n    {\n        var container = new StashboxContainer();\n        container.RegisterTypesAs(typeof(IGenTest<>), typeof(IGenTest<>).Assembly);\n\n        var regs = container.ContainerContext.RegistrationRepository.GetRegistrationMappings().OrderBy(r => r.Value.RegistrationId).ToArray();\n\n        Assert.Equal(7, regs.Length);\n        Assert.Equal(typeof(IGenTest<>), regs[0].Key);\n        Assert.Equal(typeof(IGenTest<int>), regs[1].Key);\n        Assert.Equal(typeof(IGenTest<double>), regs[2].Key);\n        Assert.Equal(typeof(IGenTest<object>), regs[3].Key);\n        Assert.Equal(typeof(IGenTest<int>), regs[4].Key);\n        Assert.Equal(typeof(IGenTest<double>), regs[5].Key);\n        Assert.Equal(typeof(IGenTest<object>), regs[6].Key);\n\n        Assert.Equal(typeof(GenTest<>), regs[0].Value.ImplementationType);\n        Assert.Equal(typeof(GenTest1), regs[1].Value.ImplementationType);\n        Assert.Equal(typeof(GenTest2), regs[2].Value.ImplementationType);\n        Assert.Equal(typeof(GenTest3), regs[3].Value.ImplementationType);\n        Assert.Equal(typeof(GenTest4), regs[4].Value.ImplementationType);\n        Assert.Equal(typeof(GenTest5), regs[5].Value.ImplementationType);\n        Assert.Equal(typeof(GenTest6), regs[6].Value.ImplementationType);\n    }\n\n    [Fact]\n    public void RegistersTests_Generic_ByBase()\n    {\n        var container = new StashboxContainer();\n        container.RegisterTypesAs(typeof(GenTest<>), typeof(IGenTest<>).Assembly);\n\n        var regs = container.ContainerContext.RegistrationRepository.GetRegistrationMappings().OrderBy(r => r.Value.RegistrationId).ToArray();\n\n        Assert.Equal(4, regs.Length);\n        Assert.Equal(typeof(GenTest<>), regs[0].Key);\n        Assert.Equal(typeof(GenTest<int>), regs[1].Key);\n        Assert.Equal(typeof(GenTest<double>), regs[2].Key);\n        Assert.Equal(typeof(GenTest<object>), regs[3].Key);\n\n        Assert.Equal(typeof(GenTest<>), regs[0].Value.ImplementationType);\n        Assert.Equal(typeof(GenTest1), regs[1].Value.ImplementationType);\n        Assert.Equal(typeof(GenTest2), regs[2].Value.ImplementationType);\n        Assert.Equal(typeof(GenTest3), regs[3].Value.ImplementationType);\n    }\n\n    [Fact]\n    public void RegistersTests_AsServiceAlso_Generic_Fail()\n    {\n        var container = new StashboxContainer();\n        Assert.Throws<ArgumentException>(() => container.Register<Test1>(context => context.AsServiceAlso<Test2>()));\n    }\n\n    [Fact]\n    public void RegistersTests_AsServiceAlso_Fail()\n    {\n        var container = new StashboxContainer();\n        Assert.Throws<ArgumentException>(() => container.Register(typeof(Test1), context => context.AsServiceAlso<Test2>()));\n    }\n\n    [Fact]\n    public void RegistersTests_AsServiceAlso_Transient()\n    {\n        var container = new StashboxContainer();\n        container.Register<ITest, Test1>(context => context.AsServiceAlso<ITest1>());\n\n        var inst = container.Resolve<ITest>();\n        var inst1 = container.Resolve<ITest1>();\n        Assert.NotNull(inst);\n        Assert.NotNull(inst1);\n        Assert.IsType<Test1>(inst);\n        Assert.IsType<Test1>(inst1);\n    }\n\n    [Fact]\n    public void RegistersTests_AsServiceAlso_Singleton()\n    {\n        var container = new StashboxContainer();\n        container.Register(typeof(ITest), typeof(Test1), context => context.AsServiceAlso<ITest1>().WithSingletonLifetime());\n\n        var inst = container.Resolve<ITest>();\n        var inst1 = container.Resolve<ITest1>();\n        Assert.Same(inst, inst1);\n    }\n\n    interface ITest;\n\n    interface ITest1;\n\n    interface ITest2;\n\n    class Test : ITest;\n\n    interface IGenTest<T>;\n\n    class GenTest<T> : IGenTest<T>;\n\n    class GenTest1 : GenTest<int>;\n\n    class GenTest2 : GenTest<double>;\n\n    class GenTest3 : GenTest<object>;\n\n    class GenTest4 : IGenTest<int>;\n\n    class GenTest5 : IGenTest<double>;\n\n    class GenTest6 : IGenTest<object>;\n\n    class Test2;\n\n    class Test1 : ITest, ITest1;\n\n    class Test11 : ITest1, ITest2;\n\n    class Test12 : ITest, ITest1, ITest2;\n\n    class Test13 : Test12;\n\n    class Test14 : Test13;\n\n    class TestCompositionRoot : ICompositionRoot\n    {\n        public void Compose(IStashboxContainer container)\n        {\n            container.Register<ITest, Test>();\n            container.Register<ITest1, Test1>();\n        }\n    }\n\n    class TestCompositionRoot2 : ICompositionRoot\n    {\n        public void Compose(IStashboxContainer container)\n        {\n            container.Register<ITest1, Test11>();\n            container.Register<ITest2, Test12>();\n        }\n    }\n}"
  },
  {
    "path": "test/ResolveFactoryTests.cs",
    "content": "﻿using Stashbox.Configuration;\nusing Stashbox.Tests.Utils;\nusing System;\nusing Xunit;\n\nnamespace Stashbox.Tests;\n\npublic class ResolveFactoryTests\n{\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void ResolveFactoryTests_ParameterLess(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<Test>();\n        var factory = container.Resolve<Func<Test>>();\n\n        Assert.NotNull(factory());\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void ResolveFactoryTests_ParameterLess_Named(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<IService, Service>(c => c.WithName(\"service\"));\n        container.Register<IService, Service1>(c => c.WithName(\"service1\"));\n        var factory = container.Resolve<Func<IService>>(\"service\");\n\n        Assert.IsType<Service>(factory());\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void ResolveFactoryTests_ParameterLess_Scoped(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<Test>();\n\n        using var scope = container.BeginScope();\n        var factory = scope.Resolve<Func<Test>>();\n\n        Assert.NotNull(factory());\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void ResolveFactoryTests_OneParam(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<Test1>();\n        var factory = container.Resolve<Func<Test, Test1>>();\n\n        var test = new Test();\n        var inst = factory(test);\n\n        Assert.Same(test, inst.Test);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void ResolveFactoryTests_OneParam_Scoped(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<Test1>();\n\n        using var scope = container.BeginScope();\n        var factory = scope.Resolve<Func<Test, Test1>>();\n\n        var test = new Test();\n        var inst = factory(test);\n\n        Assert.Same(test, inst.Test);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void ResolveFactoryTests_TwoParams(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<Test2>();\n        var factory = container.Resolve<Func<Test, Test1, Test2>>();\n\n        var test = new Test();\n        var test1 = new Test1(test);\n        var inst = factory(test, test1);\n\n        Assert.Same(test, inst.Test);\n        Assert.Same(test1, inst.Test1);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void ResolveFactoryTests_TwoParams_Scoped(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<Test2>();\n\n        using var scope = container.BeginScope();\n        var factory = scope.Resolve<Func<Test, Test1, Test2>>();\n\n        var test = new Test();\n        var test1 = new Test1(test);\n        var inst = factory(test, test1);\n\n        Assert.Same(test, inst.Test);\n        Assert.Same(test1, inst.Test1);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void ResolveFactoryTests_ThreeParams(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<Test3>();\n        var factory = container.Resolve<Func<Test, Test1, Test2, Test3>>();\n\n        var test = new Test();\n        var test1 = new Test1(test);\n        var test2 = new Test2(test1, test);\n        var inst = factory(test, test1, test2);\n\n        Assert.Same(test, inst.Test);\n        Assert.Same(test1, inst.Test1);\n        Assert.Same(test2, inst.Test2);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void ResolveFactoryTests_ThreeParams_Scoped(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<Test3>();\n\n        using var scope = container.BeginScope();\n        var factory = scope.Resolve<Func<Test, Test1, Test2, Test3>>();\n\n        var test = new Test();\n        var test1 = new Test1(test);\n        var test2 = new Test2(test1, test);\n        var inst = factory(test, test1, test2);\n\n        Assert.Same(test, inst.Test);\n        Assert.Same(test1, inst.Test1);\n        Assert.Same(test2, inst.Test2);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void ResolveFactoryTests_FourParams(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<Test4>();\n        var factory = container.Resolve<Func<Test, Test1, Test2, Test3, Test4>>();\n\n        var test = new Test();\n        var test1 = new Test1(test);\n        var test2 = new Test2(test1, test);\n        var test3 = new Test3(test1, test, test2);\n        var inst = factory(test, test1, test2, test3);\n\n        Assert.Same(test, inst.Test);\n        Assert.Same(test1, inst.Test1);\n        Assert.Same(test2, inst.Test2);\n        Assert.Same(test3, inst.Test3);\n    }\n\n    [Theory]\n    [ClassData(typeof(CompilerTypeTestData))]\n    public void ResolveFactoryTests_FourParams_Scoped(CompilerType compilerType)\n    {\n        using var container = new StashboxContainer(c => c.WithCompiler(compilerType));\n        container.Register<Test4>();\n\n        using var scope = container.BeginScope();\n        var factory = scope.Resolve<Func<Test, Test1, Test2, Test3, Test4>>();\n\n        var test = new Test();\n        var test1 = new Test1(test);\n        var test2 = new Test2(test1, test);\n        var test3 = new Test3(test1, test, test2);\n        var inst = factory(test, test1, test2, test3);\n\n        Assert.Same(test, inst.Test);\n        Assert.Same(test1, inst.Test1);\n        Assert.Same(test2, inst.Test2);\n        Assert.Same(test3, inst.Test3);\n    }\n\n    interface IService;\n\n    class Service : IService;\n\n    class Service1 : IService;\n\n    class Test;\n\n    class Test1\n    {\n        public Test1(Test test)\n        {\n            this.Test = test;\n        }\n\n        public Test Test { get; }\n    }\n\n    class Test2\n    {\n        public Test2(Test1 test1, Test test)\n        {\n            this.Test1 = test1;\n            this.Test = test;\n        }\n\n        public Test1 Test1 { get; }\n        public Test Test { get; }\n    }\n\n    class Test3\n    {\n        public Test3(Test1 test1, Test test, Test2 test2)\n        {\n            this.Test1 = test1;\n            this.Test = test;\n            this.Test2 = test2;\n        }\n\n        public Test1 Test1 { get; }\n        public Test Test { get; }\n        public Test2 Test2 { get; }\n    }\n\n    class Test4\n    {\n        public Test4(Test1 test1, Test test, Test2 test2, Test3 test3)\n        {\n            this.Test1 = test1;\n            this.Test = test;\n            this.Test2 = test2;\n            this.Test3 = test3;\n        }\n\n        public Test1 Test1 { get; }\n        public Test Test { get; }\n        public Test2 Test2 { get; }\n        public Test3 Test3 { get; }\n    }\n}"
  },
  {
    "path": "test/ResolverTests.cs",
    "content": "﻿using Stashbox.Attributes;\nusing Stashbox.Configuration;\nusing Stashbox.Exceptions;\nusing System.Linq;\nusing Xunit;\n\nnamespace Stashbox.Tests;\n\npublic class ResolverTests\n{\n    [Fact]\n    public void ResolverTests_DefaultValue()\n    {\n        using var container = new StashboxContainer(config => config.WithDefaultValueInjection());\n        container.Register<Test>();\n        var inst = container.Resolve<Test>();\n\n        Assert.Equal(default, inst.I);\n    }\n\n    [Fact]\n    public void ResolverTests_DefaultValue_WithOptional()\n    {\n        using var container = new StashboxContainer();\n        container.Register<Test1>();\n        var inst = container.Resolve<Test1>();\n\n        Assert.Equal(5, inst.I);\n    }\n\n    [Fact]\n    public void ResolverTests_DefaultValue_WithOptional_LateConfig()\n    {\n        using var container = new StashboxContainer();\n        container.Register<Test1>();\n        container.Configure(config => config\n            .WithDefaultValueInjection());\n        var inst = container.Resolve<Test1>();\n\n        Assert.Equal(5, inst.I);\n    }\n\n    [Fact]\n    public void ResolverTests_DefaultValue_RefType_WithOptional()\n    {\n        using var container = new StashboxContainer(config => config.WithDefaultValueInjection());\n        container.Register<Test2>();\n        var inst = container.Resolve<Test2>();\n\n        Assert.Null(inst.I);\n    }\n\n    [Fact]\n    public void ResolverTests_DefaultValue_RefType_WithOutOptional()\n    {\n        using var container = new StashboxContainer(config => config.WithDefaultValueInjection());\n        container.Register<Test3>();\n        Assert.Throws<ResolutionFailedException>(() => container.Resolve<Test3>());\n    }\n\n    [Fact]\n    public void ResolverTests_DefaultValue_RefType_WithOutOptional_AllowNull()\n    {\n        using var container = new StashboxContainer(config => config.WithDefaultValueInjection());\n        container.Register<Test3>();\n        var result = container.ResolveOrDefault<Test3>();\n\n        Assert.Null(result);\n    }\n\n    [Fact]\n    public void ResolverTests_DefaultValue_String()\n    {\n        using var container = new StashboxContainer(config => config.WithDefaultValueInjection());\n        container.Register<Test4>();\n        var inst = container.Resolve<Test4>();\n\n        Assert.Null(inst.I);\n    }\n\n    [Fact]\n    public void ResolverTests_DefaultValue_Null()\n    {\n        using var container = new StashboxContainer();\n        container.Register<Test4>();\n        var inst = container.ResolveOrDefault<Test4>();\n\n        Assert.Null(inst);\n    }\n\n    [Fact]\n    public void ResolverTests_DefaultValue_Nullable()\n    {\n        using var container = new StashboxContainer(config => config.WithDefaultValueInjection());\n        container.Register<Test9>();\n        var inst = container.Resolve<Test9>();\n\n        Assert.Null(inst.I);\n    }\n\n    [Fact]\n    public void ResolverTests_UnknownType()\n    {\n        using var container = new StashboxContainer(config => config.WithUnknownTypeResolution());\n        var inst = container.Resolve<RefDep>();\n\n        Assert.NotNull(inst);\n    }\n\n    [Fact]\n    public void ResolverTests_UnknownType_ChildContainer()\n    {\n        using var container = new StashboxContainer(config => config.WithUnknownTypeResolution());\n        using var child = container.CreateChildContainer();\n        var inst = child.Resolve<RefDep>();\n\n        Assert.Single(child.ContainerContext.RegistrationRepository.GetRegistrationMappings());\n        Assert.Empty(container.ContainerContext.RegistrationRepository.GetRegistrationMappings());\n    }\n\n    [Fact]\n    public void ResolverTests_UnknownType_Dependency()\n    {\n        using var container = new StashboxContainer(config => config.WithUnknownTypeResolution());\n        container.Register<Test3>();\n        var inst = container.Resolve<Test3>();\n\n        Assert.NotNull(inst.I);\n    }\n\n    [Fact]\n    public void ResolverTests_UnknownType_Respects_Name()\n    {\n        using var container = new StashboxContainer(config => config.WithUnknownTypeResolution()).Register<Test10>();\n        container.Resolve<Test10>();\n\n        var reg = container.GetRegistrationMappings().First(r => r.Value.ImplementationType == typeof(RefDep));\n\n        Assert.Equal(\"Ref\", reg.Value.Name);\n    }\n\n    [Fact]\n    public void ResolverTests_UnknownType_Respects_Name_Config_Override()\n    {\n        using var container = new StashboxContainer(config => config.WithUnknownTypeResolution(c =>\n        {\n            if (c.ImplementationType == typeof(RefDep))\n                c.WithName(\"fromUnknownConfig\");\n        })).Register<Test10>();\n        container.Resolve<Test10>();\n\n        var reg = container.GetRegistrationMappings().First(r => r.Value.ImplementationType == typeof(RefDep));\n\n        Assert.Equal(\"fromUnknownConfig\", reg.Value.Name);\n    }\n\n    [Fact]\n    public void ResolverTests_PreferDefaultValueOverUnknownType()\n    {\n        using var container = new StashboxContainer(config => config.WithUnknownTypeResolution().WithDefaultValueInjection());\n        container.Register<Test2>();\n        var inst = container.Resolve<Test2>();\n\n        Assert.Null(inst.I);\n    }\n\n    [Fact]\n    public void ResolverTests_MemberInject_WithoutAnnotation()\n    {\n        using var container = new StashboxContainer(config => config\n            .WithAutoMemberInjection()\n            .WithUnknownTypeResolution());\n        container.Register<Test5>();\n        var inst = container.Resolve<Test5>();\n\n        Assert.NotNull(inst.I);\n    }\n\n    [Fact]\n    public void ResolverTests_MemberInject_WithoutAnnotation_LateConfig()\n    {\n        using var container = new StashboxContainer();\n        container.Register<Test5>();\n        container.Configure(config => config.WithUnknownTypeResolution().WithAutoMemberInjection());\n        var inst = container.Resolve<Test5>();\n\n        Assert.NotNull(inst.I);\n    }\n\n    [Fact]\n    public void ResolverTests_MemberInject_WithAutoMemberInjection()\n    {\n        using var container = new StashboxContainer(config => config.WithUnknownTypeResolution());\n        container.Register<Test5>(context => context.WithAutoMemberInjection());\n        var inst = container.Resolve<Test5>();\n\n        Assert.NotNull(inst.I);\n    }\n\n    [Fact]\n    public void ResolverTests_MemberInject_WithAutoMemberInjection_Field()\n    {\n        using var container = new StashboxContainer(config => config.WithUnknownTypeResolution());\n        container.Register<Test6>(context => context.WithName(\"fail\").WithAutoMemberInjection());\n        var inst = container.Resolve<Test6>(\"fail\");\n\n        Assert.Null(inst.I);\n\n        container.Register<Test6>(context => context.WithName(\"success\").WithAutoMemberInjection(Rules.AutoMemberInjectionRules.PrivateFields));\n        var inst1 = container.Resolve<Test6>(\"success\");\n\n        Assert.NotNull(inst1.I);\n    }\n\n    [Fact]\n    public void ResolverTests_MemberInject_WithAutoMemberInjection_PrivateSetter()\n    {\n        using var container = new StashboxContainer(config => config.WithUnknownTypeResolution());\n        container.Register<Test7>(context => context.WithName(\"fail\").WithAutoMemberInjection());\n        var inst = container.Resolve<Test7>(\"fail\");\n\n        Assert.Null(inst.I);\n\n        container.Register<Test7>(context => context.WithName(\"success\").WithAutoMemberInjection(Rules.AutoMemberInjectionRules.PropertiesWithLimitedAccess));\n        var inst1 = container.Resolve<Test7>(\"success\");\n\n        Assert.NotNull(inst1.I);\n    }\n\n    [Fact]\n    public void ResolverTests_MemberInject_WithAutoMemberInjection_Mixed()\n    {\n        using var container = new StashboxContainer(config => config.WithUnknownTypeResolution());\n        container.Register<Test8>(context => context.WithName(\"justfield\").WithAutoMemberInjection(Rules.AutoMemberInjectionRules.PrivateFields));\n        var inst = container.Resolve<Test8>(\"justfield\");\n\n        Assert.NotNull(inst.I);\n        Assert.Null(inst.I1);\n\n        container.Register<Test8>(context => context.WithName(\"justprivatesetter\").WithAutoMemberInjection(Rules.AutoMemberInjectionRules.PropertiesWithLimitedAccess));\n        var inst1 = container.Resolve<Test8>(\"justprivatesetter\");\n\n        Assert.NotNull(inst1.I1);\n        Assert.Null(inst1.I);\n\n        container.Register<Test8>(context => context.WithName(\"mixed\")\n            .WithAutoMemberInjection(Rules.AutoMemberInjectionRules.PropertiesWithLimitedAccess | Rules.AutoMemberInjectionRules.PrivateFields));\n        var inst2 = container.Resolve<Test8>(\"mixed\");\n\n        Assert.NotNull(inst2.I1);\n        Assert.NotNull(inst2.I);\n    }\n\n    [Fact]\n    public void ResolverTests_MemberInject_WithAutoMemberInjection_Mixed_ContainerConfig()\n    {\n        using var container = new StashboxContainer(config => config\n            .WithUnknownTypeResolution()\n            .WithAutoMemberInjection(Rules.AutoMemberInjectionRules.PropertiesWithLimitedAccess | Rules.AutoMemberInjectionRules.PrivateFields));\n        container.Register<Test8>(context => context.WithAutoMemberInjection(Rules.AutoMemberInjectionRules.PropertiesWithLimitedAccess | Rules.AutoMemberInjectionRules.PrivateFields));\n        var inst2 = container.Resolve<Test8>();\n\n        Assert.NotNull(inst2.I1);\n        Assert.NotNull(inst2.I);\n    }\n\n    [Fact]\n    public void ResolverTests_MemberInject_WithAutoMemberInjection_Mixed_PreferRegistrationRuleOverContainerRule()\n    {\n        using var container = new StashboxContainer(config => config\n            .WithUnknownTypeResolution()\n            .WithAutoMemberInjection(Rules.AutoMemberInjectionRules.PropertiesWithLimitedAccess | Rules.AutoMemberInjectionRules.PrivateFields));\n        container.Register<Test8>(context => context.WithAutoMemberInjection(Rules.AutoMemberInjectionRules.PrivateFields));\n        var inst2 = container.Resolve<Test8>();\n\n        Assert.Null(inst2.I1);\n        Assert.NotNull(inst2.I);\n    }\n\n    class Test\n    {\n        public int I { get; set; }\n\n        public Test(int i)\n        {\n            this.I = i;\n        }\n    }\n\n    class Test1\n    {\n        public int I { get; private set; }\n\n        public Test1(int i = 5)\n        {\n            this.I = i;\n        }\n    }\n\n    class Test2\n    {\n        public RefDep I { get; set; }\n\n        public Test2(RefDep i = null)\n        {\n            this.I = i;\n        }\n    }\n\n    class Test3\n    {\n        public RefDep I { get; set; }\n\n        public Test3(RefDep i)\n        {\n            this.I = i;\n        }\n    }\n\n    class Test4\n    {\n        public string I { get; set; }\n\n        public Test4(string i)\n        {\n            this.I = i;\n        }\n    }\n\n    class Test5\n    {\n        public RefDep I { get; set; }\n    }\n\n    class Test6\n    {\n        public RefDep I => this.i;\n\n        private RefDep i = null;\n    }\n\n    class Test7\n    {\n        public RefDep I { get; private set; }\n    }\n\n    class Test8\n    {\n        public RefDep I1 { get; private set; }\n\n        public RefDep I => this.i;\n\n        private RefDep i = null;\n    }\n\n    class Test9\n    {\n        public Test9(int? i = null)\n        {\n            this.I = i;\n        }\n\n        public int? I { get; private set; }\n    }\n\n    class Test10\n    {\n        public Test10([Dependency(\"Ref\")] RefDep refDep)\n        { }\n    }\n\n    class RefDep;\n}"
  },
  {
    "path": "test/ScopeTests.cs",
    "content": "﻿using System.Linq;\nusing System.Threading.Tasks;\nusing Xunit;\n\nnamespace Stashbox.Tests;\n\npublic class ScopeTests\n{\n    [Fact]\n    public void GetOrAdd_Ensure_Evaluator_DoesNotThrow()\n    {\n        for (int i = 0; i < 5000; i++)\n        {\n            using var scope = (IResolutionScope)new StashboxContainer().BeginScope();\n            Parallel.For(0, 50, i =>\n            {\n                var inst = scope.GetOrAddScopedObject(1, (_, _) => new object(), null, typeof(object));\n                Assert.NotNull(inst);\n            });\n        }\n    }\n\n    [Fact]\n    public void Enusre_Put_Instance_Creates_New_Cache()\n    {\n        using var container = new StashboxContainer();\n        using var scope = container.BeginScope();\n\n        scope.PutInstanceInScope(new A());\n        scope.PutInstanceInScope(new B());\n\n        var cache = scope.GetDelegateCacheEntries();\n        Assert.Empty(cache);\n\n        scope.Resolve<A>();\n        scope.Resolve<B>();\n\n        cache = scope.GetDelegateCacheEntries();\n        Assert.Equal(2, cache.ToArray().Length);\n\n        scope.Resolve<A>();\n        scope.Resolve<B>();\n\n        cache = scope.GetDelegateCacheEntries();\n        Assert.Equal(2, cache.ToArray().Length);\n\n        scope.PutInstanceInScope(new C());\n\n        cache = scope.GetDelegateCacheEntries();\n        Assert.Empty(cache);\n\n        scope.Resolve<A>();\n        scope.Resolve<A>();\n        scope.Resolve<B>();\n        scope.Resolve<B>();\n        scope.Resolve<C>();\n        scope.Resolve<C>();\n\n        cache = scope.GetDelegateCacheEntries();\n        Assert.Equal(3, cache.ToArray().Length);\n    }\n\n    [Fact]\n    public void Enusre_Put_Instance_Creates_New_Cache_ResolveOrDefault()\n    {\n        using var container = new StashboxContainer();\n        using var scope = container.BeginScope();\n\n        scope.PutInstanceInScope(new A());\n        scope.PutInstanceInScope(new B());\n\n        var cache = scope.GetDelegateCacheEntries();\n        Assert.Empty(cache);\n\n        scope.ResolveOrDefault<A>();\n        scope.ResolveOrDefault<B>();\n\n        cache = scope.GetDelegateCacheEntries();\n        Assert.Equal(2, cache.ToArray().Length);\n\n        scope.ResolveOrDefault<A>();\n        scope.ResolveOrDefault<B>();\n\n        cache = scope.GetDelegateCacheEntries();\n        Assert.Equal(2, cache.ToArray().Length);\n\n        scope.PutInstanceInScope(new C());\n\n        cache = scope.GetDelegateCacheEntries();\n        Assert.Empty(cache);\n\n        scope.ResolveOrDefault<A>();\n        scope.ResolveOrDefault<A>();\n        scope.ResolveOrDefault<B>();\n        scope.ResolveOrDefault<B>();\n        scope.ResolveOrDefault<C>();\n        scope.ResolveOrDefault<C>();\n\n        cache = scope.GetDelegateCacheEntries();\n        Assert.Equal(3, cache.ToArray().Length);\n    }\n\n    [Fact]\n    public void Enusre_Dependency_Overrides_Disables_Cache()\n    {\n        using var container = new StashboxContainer().Register<A>();\n        using var scope = container.BeginScope();\n        var cache = scope.GetDelegateCacheEntries();\n\n        Assert.Empty(cache);\n\n        scope.Resolve<A>();\n        cache = scope.GetDelegateCacheEntries();\n\n        Assert.Single(cache);\n    }\n\n    [Fact]\n    public void Enusre_Dependency_Overrides_Disables_Cache_ResolveOrDefault()\n    {\n        using var container = new StashboxContainer().Register<A>();\n        using var scope = container.BeginScope();\n        scope.ResolveOrDefault<A>(dependencyOverrides: [new A()]);\n\n        var cache = scope.GetDelegateCacheEntries();\n        Assert.Empty(cache);\n\n        scope.ResolveOrDefault<A>();\n        cache = scope.GetDelegateCacheEntries();\n\n        Assert.Single(cache);\n    }\n\n    private class A;\n    private class B;\n    private class C;\n}"
  },
  {
    "path": "test/ServiceProviderTests.cs",
    "content": "﻿using System;\nusing Xunit;\n\nnamespace Stashbox.Tests;\n\npublic class ServiceProviderTests\n{\n    [Fact]\n    public void ServiceProviderTests_Resolve_Self()\n    {\n        using IStashboxContainer container = new StashboxContainer();\n        \n        Assert.Same(container.ContainerContext.RootScope, container.Resolve<IServiceProvider>());\n\n        using var scope = container.BeginScope();\n        \n        Assert.Same(scope, scope.Resolve<IServiceProvider>());\n    }\n    \n    [Fact]\n    public void ServiceProviderTests_Resolve_Override()\n    {\n        using var container = new StashboxContainer()\n            .Register<IServiceProvider, CustomSp>(c => c.WithFactory(dr => new CustomSp(dr)).AsServiceAlso<ITest>().AsServiceAlso<ITest2>())\n            .Register<SpAware>();\n\n        Assert.IsType<CustomSp>(container.Resolve<IServiceProvider>());\n        Assert.Same(container.ContainerContext.RootScope, ((CustomSp)container.Resolve<IServiceProvider>()).DependencyResolver);\n\n        using var scope = container.BeginScope();\n        \n        Assert.IsType<CustomSp>(scope.Resolve<IServiceProvider>());\n        Assert.Same(scope, ((CustomSp)scope.Resolve<IServiceProvider>()).DependencyResolver);\n\n        Assert.IsType<CustomSp>(container.Resolve<SpAware>().Test);\n    }\n    \n    [Fact]\n    public void ServiceProviderTests_Resolve_MultiReg()\n    {\n        using var container = new StashboxContainer(c => c.WithDisposableTransientTracking())\n            .Register<IServiceProvider, CustomSp>(c => c.WithFactory(dr => new CustomSp(dr)).AsServiceAlso<ITest>().AsServiceAlso<ITest2>())\n            .Register<SpAware>();\n\n        Assert.IsType<CustomSp>(container.Resolve<SpAware>().Test);\n        Assert.IsType<CustomSp>(container.Resolve<SpAware>().Test2);\n    }\n    \n    [Fact]\n    public void ServiceProviderTests_Resolve_MultiReg_AllImplemented()\n    {\n        using var container = new StashboxContainer(c => c.WithDisposableTransientTracking())\n            .Register<IServiceProvider, CustomSp>(c => c.WithFactory(dr => new CustomSp(dr)).AsImplementedTypes())\n            .Register<SpAware>();\n\n        Assert.IsType<CustomSp>(container.Resolve<SpAware>().Test);\n        Assert.IsType<CustomSp>(container.Resolve<SpAware>().Test2);\n    }\n\n    interface ITest;\n    interface ITest2;\n    \n    class CustomSp : IServiceProvider, ITest, ITest2, IDisposable\n    {\n        public IDependencyResolver DependencyResolver { get; }\n\n        public CustomSp(IDependencyResolver dependencyResolver)\n        {\n            DependencyResolver = dependencyResolver;\n        }\n        \n        public object GetService(Type serviceType)\n        {\n            return null;\n        }\n        \n        public void Dispose() { }\n    }\n\n    class SpAware\n    {\n        public IServiceProvider ServiceProvider { get; }\n        public ITest Test { get; }\n        public ITest2 Test2 { get; }\n\n        public SpAware(IServiceProvider serviceProvider, ITest test, ITest2 test2)\n        {\n            ServiceProvider = serviceProvider;\n            Test = test;\n            Test2 = test2;\n        }\n    }\n}"
  },
  {
    "path": "test/StandardResolveTests.cs",
    "content": "﻿using Stashbox.Attributes;\nusing Stashbox.Configuration;\nusing Stashbox.Exceptions;\nusing Stashbox.Utils;\nusing System;\nusing System.Threading.Tasks;\nusing Xunit;\n\nnamespace Stashbox.Tests;\n\npublic class StandardResolveTests\n{\n    [Fact]\n    public void StandardResolveTests_Resolve()\n    {\n        using IStashboxContainer container = new StashboxContainer();\n        container.Register<ITest1, Test1>();\n        container.Register<ITest2, Test2>();\n        container.Register<ITest3, Test3>();\n\n        var test3 = container.Resolve<ITest3>();\n        var test2 = container.Resolve<ITest2>();\n        var test1 = container.Resolve<ITest1>();\n\n        Assert.NotNull(test3);\n        Assert.NotNull(test2);\n        Assert.NotNull(test1);\n\n        Assert.IsType<Test1>(test1);\n        Assert.IsType<Test2>(test2);\n        Assert.IsType<Test3>(test3);\n    }\n\n    [Fact]\n    public void StandardResolveTests_Ensure_DependencyResolver_CanBeResolved()\n    {\n        using IStashboxContainer container = new StashboxContainer();\n        container.RegisterScoped<ResolverTest>();\n\n        using var scope = container.BeginScope();\n        var resolver = scope.Resolve<IDependencyResolver>();\n\n        var test = scope.Resolve<ResolverTest>();\n\n        Assert.Same(resolver, test.DependencyResolver);\n\n        using var scope1 = container.BeginScope();\n        var scopedResolver = scope1.Resolve<IDependencyResolver>();\n        var test1 = scope1.Resolve<ResolverTest>();\n\n        Assert.Same(scope1, scopedResolver);\n        Assert.Same(scope1, test1.DependencyResolver);\n    }\n\n    [Fact]\n    public void StandardResolveTests_Ensure_DependencyResolver_CanBeResolved_FromRoot()\n    {\n        using IStashboxContainer container = new StashboxContainer();\n        container.Register<ResolverTest>();\n        var resolver = container.Resolve<IDependencyResolver>();\n        var test = container.Resolve<ResolverTest>();\n\n        Assert.Same(resolver, test.DependencyResolver);\n        Assert.Same(test.DependencyResolver, container.ContainerContext.RootScope);\n    }\n\n    [Fact]\n    public void StandardResolveTests_Factory()\n    {\n        using IStashboxContainer container = new StashboxContainer();\n        container.Register<ITest1, Test1>();\n        var test1 = container.ResolveFactory(typeof(ITest1)).DynamicInvoke();\n\n        Assert.NotNull(test1);\n        Assert.IsType<Test1>(test1);\n    }\n\n    [Fact]\n    public void StandardResolveTests_Factory_Scoped()\n    {\n        using IStashboxContainer container = new StashboxContainer();\n        container.Register<ITest1, Test1>();\n        using var child = container.BeginScope();\n        var test1 = child.ResolveFactory(typeof(ITest1)).DynamicInvoke();\n\n        Assert.NotNull(test1);\n        Assert.IsType<Test1>(test1);\n    }\n\n    [Fact]\n    public void StandardResolveTests_Factory_ResolutionFailed()\n    {\n        using IStashboxContainer container = new StashboxContainer();\n        Assert.Throws<ResolutionFailedException>(() => container.ResolveFactory(typeof(ITest1)).DynamicInvoke());\n    }\n\n    [Fact]\n    public void StandardResolveTests_Factory_ResolutionFailed_Null()\n    {\n        using IStashboxContainer container = new StashboxContainer();\n        var factory = container.ResolveFactoryOrDefault(typeof(ITest1));\n\n        Assert.Null(factory);\n    }\n\n    [Fact]\n    public void StandardResolveTests_DependencyResolve_ResolutionFailed()\n    {\n        using IStashboxContainer container = new StashboxContainer();\n        container.Register<ITest2, Test2>();\n        Assert.Throws<ResolutionFailedException>(() => container.Resolve<ITest2>());\n    }\n\n    [Fact]\n    public void StandardResolveTests_DependencyResolve_ResolutionFailed_AllowNull()\n    {\n        using IStashboxContainer container = new StashboxContainer();\n        container.Register<ITest2, Test2>();\n        var result = container.ResolveOrDefault<ITest2>();\n\n        Assert.Null(result);\n    }\n\n    [Fact]\n    public void StandardResolveTests_Resolve_ResolutionFailed()\n    {\n        using IStashboxContainer container = new StashboxContainer();\n        Assert.Throws<ResolutionFailedException>(() => container.Resolve<ITest1>());\n    }\n\n    [Fact]\n    public void StandardResolveTests_Resolve_ResolutionFailed_AllowNull()\n    {\n        using IStashboxContainer container = new StashboxContainer();\n\n        Assert.Null(container.ResolveOrDefault<ITest1>());\n    }\n\n    [Fact]\n    public void StandardResolveTests_Resolve_ResolutionSuccess_AllowNull()\n    {\n        using IStashboxContainer container = new StashboxContainer().Register<ITest1, Test1>();\n\n        Assert.NotNull(container.ResolveOrDefault<ITest1>());\n        Assert.NotNull(container.ResolveOrDefault<ITest1>());\n    }\n\n    [Fact]\n    public void StandardResolveTests_Resolve_ResolutionFailed_AllowNull_Override()\n    {\n        using IStashboxContainer container = new StashboxContainer();\n\n        Assert.Null(container.ResolveOrDefault<ITest1>([new Dummy()]));\n    }\n\n    [Fact]\n    public void StandardResolveTests_Resolve_ResolutionSuccess_AllowNull_Override()\n    {\n        using IStashboxContainer container = new StashboxContainer().Register<ITest2, Test2>();\n\n        Assert.NotNull(container.ResolveOrDefault<ITest2>([new Test1()]));\n        Assert.NotNull(container.ResolveOrDefault<ITest2>([new Test1()]));\n    }\n\n    [Fact]\n    public void StandardResolveTests_DependencyResolve_ResolutionFailed_NullName()\n    {\n        using IStashboxContainer container = new StashboxContainer();\n        container.Register<ITest2, Test2>();\n        Assert.Throws<ResolutionFailedException>(() => container.Resolve<ITest2>((object)null));\n    }\n\n    [Fact]\n    public void StandardResolveTests_DependencyResolve_ResolutionFailed_AllowNull_NullName()\n    {\n        using IStashboxContainer container = new StashboxContainer();\n        container.Register<ITest2, Test2>();\n        var result = container.ResolveOrDefault<ITest2>((object)null);\n\n        Assert.Null(result);\n    }\n\n    [Fact]\n    public void StandardResolveTests_Resolve_ResolutionFailed_NullName()\n    {\n        using IStashboxContainer container = new StashboxContainer();\n        Assert.Throws<ResolutionFailedException>(() => container.Resolve<ITest1>((object)null));\n    }\n\n    [Fact]\n    public void StandardResolveTests_Resolve_ResolutionFailed_AllowNull_NullName()\n    {\n        using IStashboxContainer container = new StashboxContainer();\n\n        Assert.Null(container.ResolveOrDefault<ITest1>((object)null));\n    }\n\n    [Fact]\n    public void StandardResolveTests_Resolve_ResolutionSuccess_AllowNull_NullName()\n    {\n        using IStashboxContainer container = new StashboxContainer().Register<ITest1, Test1>();\n\n        Assert.NotNull(container.ResolveOrDefault<ITest1>((object)null));\n        Assert.NotNull(container.ResolveOrDefault<ITest1>((object)null));\n    }\n\n    [Fact]\n    public void StandardResolveTests_Resolve_ResolutionFailed_AllowNull_Override_NullName()\n    {\n        using IStashboxContainer container = new StashboxContainer();\n\n        Assert.Null(container.ResolveOrDefault<ITest1>(null, [new Dummy()]));\n    }\n\n    [Fact]\n    public void StandardResolveTests_Resolve_ResolutionSuccess_AllowNull_Override_NullName()\n    {\n        using IStashboxContainer container = new StashboxContainer().Register<ITest2, Test2>();\n\n        Assert.NotNull(container.ResolveOrDefault<ITest2>(null, [new Test1()]));\n        Assert.NotNull(container.ResolveOrDefault<ITest2>(null, [new Test1()]));\n    }\n\n    [Fact]\n    public void StandardResolveTests_Resolve_ResolutionFailed_AllowNull_Named()\n    {\n        using IStashboxContainer container = new StashboxContainer();\n\n        Assert.Null(container.ResolveOrDefault<ITest1>(\"test\"));\n    }\n\n    [Fact]\n    public void StandardResolveTests_Resolve_ResolutionSuccess_AllowNull_Named()\n    {\n        using IStashboxContainer container = new StashboxContainer().Register<ITest1, Test1>();\n\n        Assert.Null(container.ResolveOrDefault<ITest1>(\"test\"));\n        Assert.Null(container.ResolveOrDefault<ITest1>(\"test\"));\n    }\n\n    [Fact]\n    public void StandardResolveTests_Resolve_ResolutionFailed_AllowNull_Named_Override()\n    {\n        using IStashboxContainer container = new StashboxContainer();\n\n        Assert.Null(container.ResolveOrDefault<ITest1>(\"test\", [new Dummy()]));\n    }\n\n    [Fact]\n    public void StandardResolveTests_Resolve_ResolutionSuccess_AllowNull_Named_Override()\n    {\n        using IStashboxContainer container = new StashboxContainer().Register<ITest2, Test2>();\n\n        Assert.Null(container.ResolveOrDefault<ITest2>(\"test\", [new Test1()]));\n        Assert.Null(container.ResolveOrDefault<ITest2>(\"test\", [new Test1()]));\n    }\n\n\n    [Fact]\n    public void StandardResolveTests_Scope_Resolve_ResolutionFailed_AllowNull()\n    {\n        using var scope = new StashboxContainer().BeginScope();\n\n        Assert.Null(scope.ResolveOrDefault<ITest1>());\n    }\n\n    [Fact]\n    public void StandardResolveTests_Scope_Resolve_ResolutionSuccess_AllowNull()\n    {\n        using var scope = new StashboxContainer().Register<ITest1, Test1>().BeginScope();\n\n        Assert.NotNull(scope.ResolveOrDefault<ITest1>());\n        Assert.NotNull(scope.ResolveOrDefault<ITest1>());\n    }\n\n    [Fact]\n    public void StandardResolveTests_Scope_Resolve_ResolutionFailed_AllowNull_Override()\n    {\n        using var scope = new StashboxContainer().BeginScope();\n\n        Assert.Null(scope.ResolveOrDefault<ITest1>([new Dummy()]));\n    }\n\n    [Fact]\n    public void StandardResolveTests_Scope_Resolve_ResolutionSuccess_AllowNull_Override()\n    {\n        using var scope = new StashboxContainer().Register<ITest2, Test2>().BeginScope();\n\n        Assert.NotNull(scope.ResolveOrDefault<ITest2>([new Test1()]));\n        Assert.NotNull(scope.ResolveOrDefault<ITest2>([new Test1()]));\n    }\n\n    [Fact]\n    public void StandardResolveTests_Scope_Resolve_ResolutionFailed_AllowNull_NullName()\n    {\n        using var scope = new StashboxContainer().BeginScope();\n\n        Assert.Null(scope.ResolveOrDefault<ITest1>((object)null));\n    }\n\n    [Fact]\n    public void StandardResolveTests_Scope_Resolve_ResolutionSuccess_AllowNull_NullName()\n    {\n        using var scope = new StashboxContainer().Register<ITest1, Test1>().BeginScope();\n\n        Assert.NotNull(scope.ResolveOrDefault<ITest1>((object)null));\n        Assert.NotNull(scope.ResolveOrDefault<ITest1>((object)null));\n    }\n\n    [Fact]\n    public void StandardResolveTests_Scope_Resolve_ResolutionFailed_AllowNull_Override_NullName()\n    {\n        using var scope = new StashboxContainer().BeginScope();\n\n        Assert.Null(scope.ResolveOrDefault<ITest1>(null, [new Dummy()]));\n    }\n\n    [Fact]\n    public void StandardResolveTests_Scope_Resolve_ResolutionSuccess_AllowNull_Override_NullName()\n    {\n        using var scope = new StashboxContainer().Register<ITest2, Test2>().BeginScope();\n\n        Assert.NotNull(scope.ResolveOrDefault<ITest2>(null, [new Test1()]));\n        Assert.NotNull(scope.ResolveOrDefault<ITest2>(null, [new Test1()]));\n    }\n\n    [Fact]\n    public void StandardResolveTests_Scope_Resolve_ResolutionFailed_AllowNull_Named()\n    {\n        using var scope = new StashboxContainer().BeginScope();\n\n        Assert.Null(scope.ResolveOrDefault<ITest1>(\"test\"));\n    }\n\n    [Fact]\n    public void StandardResolveTests_Scope_Resolve_ResolutionSuccess_AllowNull_Named()\n    {\n        using var scope = new StashboxContainer().Register<ITest1, Test1>().BeginScope();\n\n        Assert.Null(scope.ResolveOrDefault<ITest1>(\"test\"));\n        Assert.Null(scope.ResolveOrDefault<ITest1>(\"test\"));\n    }\n\n    [Fact]\n    public void StandardResolveTests_Scope_Resolve_ResolutionFailed_AllowNull_Named_Override()\n    {\n        using var scope = new StashboxContainer().BeginScope();\n\n        Assert.Null(scope.ResolveOrDefault<ITest1>(\"test\", [new Dummy()]));\n    }\n\n    [Fact]\n    public void StandardResolveTests_Scope_Resolve_ResolutionSuccess_AllowNull_Named_Override()\n    {\n        using var scope = new StashboxContainer().Register<ITest2, Test2>().BeginScope();\n\n        Assert.Null(scope.ResolveOrDefault<ITest2>(\"test\", [new Test1()]));\n        Assert.Null(scope.ResolveOrDefault<ITest2>(\"test\", [new Test1()]));\n    }\n\n    [Fact]\n    public void StandardResolveTests_Resolve_Parallel()\n    {\n        IStashboxContainer container = new StashboxContainer();\n        container.Register<ITest1, Test1>();\n        container.Register<ITest2, Test2>();\n        container.Register<ITest3, Test3>();\n\n        Parallel.For(0, 50000, (i) =>\n        {\n            if (i % 100 == 0)\n            {\n                container.Register<ITest1, Test1>(context => context.WithName(i.ToString()));\n                container.Register<ITest3, Test3>(context => context.WithName($\"ITest3{i}\"));\n                var test33 = container.Resolve<ITest3>($\"ITest3{i}\");\n                var test11 = container.Resolve(typeof(ITest1), i.ToString());\n                Assert.NotNull(test33);\n                Assert.NotNull(test11);\n\n                Assert.IsType<Test1>(test11);\n                Assert.IsType<Test3>(test33);\n            }\n\n            var test3 = container.Resolve<ITest3>();\n            var test2 = container.Resolve<ITest2>();\n            var test1 = container.Resolve<ITest1>();\n\n            Assert.NotNull(test3);\n            Assert.NotNull(test2);\n            Assert.NotNull(test1);\n\n            Assert.IsType<Test1>(test1);\n            Assert.IsType<Test2>(test2);\n            Assert.IsType<Test3>(test3);\n        });\n    }\n\n    [Fact]\n    public void StandardResolveTests_Resolve_Parallel_Lazy()\n    {\n        var container = new StashboxContainer();\n        container.Register<ITest1, Test1>();\n        container.Register<ITest2, Test2>();\n        container.Register<ITest3, Test3>();\n\n        Parallel.For(0, 50000, (i) =>\n        {\n            if (i % 100 == 0)\n            {\n                container.Register<ITest1, Test1>();\n                container.Register<ITest3, Test3>();\n            }\n\n            var test3 = container.Resolve<Lazy<ITest3>>();\n            var test2 = container.Resolve<Lazy<ITest2>>();\n            var test1 = container.Resolve<Lazy<ITest1>>();\n\n            Assert.NotNull(test3.Value);\n            Assert.NotNull(test2.Value);\n            Assert.NotNull(test1.Value);\n        });\n    }\n\n    [Fact]\n    public void StandardResolveTests_Resolve_Singleton()\n    {\n        using IStashboxContainer container = new StashboxContainer();\n        container.RegisterSingleton<ITest1, Test1>();\n\n        var inst = container.Resolve<ITest1>();\n        var inst2 = container.Resolve<ITest1>();\n\n        Assert.Same(inst, inst2);\n    }\n\n    [Fact]\n    public void StandardResolveTests_Resolve_Singleton_Named()\n    {\n        using IStashboxContainer container = new StashboxContainer();\n        container.RegisterSingleton<ITest1, Test1>(\"A\");\n\n        var inst = container.Resolve<ITest1>(\"A\");\n        var inst2 = container.Resolve<ITest1>(\"A\");\n\n        Assert.Same(inst, inst2);\n    }\n\n    [Fact]\n    public void StandardResolveTests_Resolve_Singleton_Self()\n    {\n        using IStashboxContainer container = new StashboxContainer();\n        container.RegisterSingleton<Test1>();\n\n        var inst = container.Resolve<Test1>();\n        var inst2 = container.Resolve<Test1>();\n\n        Assert.Same(inst, inst2);\n    }\n\n    [Fact]\n    public void StandardResolveTests_Resolve_Singleton_Self_Named()\n    {\n        using IStashboxContainer container = new StashboxContainer();\n        container.RegisterSingleton<Test1>(\"A\");\n\n        var inst = container.Resolve<Test1>(\"A\");\n        var inst2 = container.Resolve<Test1>(\"A\");\n\n        Assert.Same(inst, inst2);\n    }\n\n    [Fact]\n    public void StandardResolveTests_Resolve_Scoped()\n    {\n        using IStashboxContainer container = new StashboxContainer();\n        container.RegisterScoped<ITest1, Test1>();\n\n        using var scope = container.BeginScope();\n\n        var inst = scope.Resolve<ITest1>();\n        var inst2 = scope.Resolve<ITest1>();\n\n        Assert.Same(inst, inst2);\n\n        using var child = container.BeginScope();\n        var inst3 = child.Resolve<ITest1>();\n        var inst4 = child.Resolve<ITest1>();\n\n        Assert.NotSame(inst, inst3);\n        Assert.Same(inst3, inst4);\n    }\n\n    [Fact]\n    public void StandardResolveTests_Resolve_Scoped_Self()\n    {\n        using IStashboxContainer container = new StashboxContainer();\n        container.RegisterScoped<Test1>();\n\n        using var scope = container.BeginScope();\n\n        var inst = scope.Resolve<Test1>();\n        var inst2 = scope.Resolve<Test1>();\n\n        Assert.Same(inst, inst2);\n\n        using var child = container.BeginScope();\n        var inst3 = child.Resolve<Test1>();\n        var inst4 = child.Resolve<Test1>();\n\n        Assert.NotSame(inst, inst3);\n        Assert.Same(inst3, inst4);\n    }\n\n    [Fact]\n    public void StandardResolveTests_Resolve_Scoped_Self_Named()\n    {\n        using IStashboxContainer container = new StashboxContainer();\n        container.RegisterScoped<Test1>(\"A\");\n\n        using var scope = container.BeginScope();\n\n        var inst = scope.Resolve<Test1>(\"A\");\n        var inst2 = scope.Resolve<Test1>(\"A\");\n\n        Assert.Same(inst, inst2);\n\n        using var child = container.BeginScope();\n        var inst3 = child.Resolve<Test1>(\"A\");\n        var inst4 = child.Resolve<Test1>(\"A\");\n\n        Assert.NotSame(inst, inst3);\n        Assert.Same(inst3, inst4);\n    }\n\n    [Fact]\n    public void StandardResolveTests_Resolve_Scoped_Named()\n    {\n        using IStashboxContainer container = new StashboxContainer();\n        container.RegisterScoped<ITest1, Test1>(\"A\");\n\n        using var scope = container.BeginScope();\n\n        var inst = scope.Resolve<ITest1>(\"A\");\n        var inst2 = scope.Resolve<ITest1>(\"A\");\n\n        Assert.Same(inst, inst2);\n\n        using var child = container.BeginScope();\n        var inst3 = child.Resolve<ITest1>(\"A\");\n        var inst4 = child.Resolve<ITest1>(\"A\");\n\n        Assert.NotSame(inst, inst3);\n        Assert.Same(inst3, inst4);\n    }\n\n    [Fact]\n    public void StandardResolveTests_Register_Scoped_Named_Non_Generic()\n    {\n        using IStashboxContainer container = new StashboxContainer();\n        container.RegisterScoped(typeof(ITest1), typeof(Test1), \"A\");\n\n        using var scope = container.BeginScope();\n\n        var inst = scope.Resolve<ITest1>(\"A\");\n        var inst2 = scope.Resolve<ITest1>(\"A\");\n\n        Assert.Same(inst, inst2);\n\n        using var child = container.BeginScope();\n        var inst3 = child.Resolve<ITest1>(\"A\");\n        var inst4 = child.Resolve<ITest1>(\"A\");\n\n        Assert.NotSame(inst, inst3);\n        Assert.Same(inst3, inst4);\n    }\n\n    [Fact]\n    public void StandardResolveTests_Resolve_Scoped_Factory()\n    {\n        using IStashboxContainer container = new StashboxContainer();\n        container.RegisterScoped<ITest1, Test1>();\n\n        using var scope = container.BeginScope();\n        var factory = scope.Resolve<Func<ITest1>>();\n\n        var inst = factory();\n        var inst2 = factory();\n\n        Assert.Same(inst, inst2);\n\n        using var child = container.BeginScope();\n        var scopeFactory = child.Resolve<Func<ITest1>>();\n        var inst3 = scopeFactory();\n        var inst4 = scopeFactory();\n\n        Assert.NotSame(inst, inst3);\n        Assert.Same(inst3, inst4);\n    }\n\n    [Fact]\n    public void StandardResolveTests_Resolve_Scoped_Injection()\n    {\n        using IStashboxContainer container = new StashboxContainer();\n        container.RegisterScoped(typeof(ITest1), typeof(Test1));\n        container.RegisterScoped<ITest4, Test4>();\n\n        using var scope = container.BeginScope();\n\n        var inst = scope.Resolve<ITest4>();\n        var inst2 = scope.Resolve<ITest4>();\n\n        Assert.Same(inst.Test, inst2.Test);\n        Assert.Same(inst.Test2, inst2.Test2);\n        Assert.Same(inst.Test, inst2.Test2);\n\n        using var child = container.BeginScope();\n        var inst3 = child.Resolve<ITest4>();\n        var inst4 = child.Resolve<ITest4>();\n\n        Assert.NotSame(inst.Test, inst4.Test);\n        Assert.NotSame(inst.Test2, inst4.Test2);\n        Assert.NotSame(inst.Test, inst4.Test2);\n\n        Assert.Same(inst3.Test, inst4.Test);\n        Assert.Same(inst3.Test2, inst4.Test2);\n        Assert.Same(inst3.Test, inst4.Test2);\n    }\n\n    [Fact]\n    public void StandardResolveTests_Resolve_Scoped_Injection_Factory()\n    {\n        using IStashboxContainer container = new StashboxContainer();\n        container.RegisterScoped(typeof(ITest1), typeof(Test1));\n        container.RegisterScoped<ITest4, Test4>();\n\n        using var scope = container.BeginScope();\n        var factory = scope.Resolve<Func<ITest4>>();\n\n        var inst = factory();\n        var inst2 = factory();\n\n        Assert.Same(inst.Test, inst2.Test);\n        Assert.Same(inst.Test2, inst2.Test2);\n        Assert.Same(inst.Test, inst2.Test2);\n\n        using var child = container.BeginScope();\n        var scopedFactory = child.Resolve<Func<ITest4>>();\n\n        var inst3 = scopedFactory();\n        var inst4 = scopedFactory();\n\n        Assert.NotSame(inst.Test, inst4.Test);\n        Assert.NotSame(inst.Test2, inst4.Test2);\n        Assert.NotSame(inst.Test, inst4.Test2);\n\n        Assert.Same(inst3.Test, inst4.Test);\n        Assert.Same(inst3.Test2, inst4.Test2);\n        Assert.Same(inst3.Test, inst4.Test2);\n    }\n\n    [Fact]\n    public void StandardResolveTests_Resolve_LastService()\n    {\n        using IStashboxContainer container = new StashboxContainer();\n        container.Register(typeof(ITest1), typeof(Test1));\n        container.Register(typeof(ITest1), typeof(Test11));\n        container.Register(typeof(ITest1), typeof(Test12));\n\n        var inst = container.Resolve<ITest1>();\n\n        Assert.IsType<Test12>(inst);\n    }\n\n    [Fact]\n    public void StandardResolveTests_Resolve_MostParametersConstructor_WithoutDefault()\n    {\n        using IStashboxContainer container = new StashboxContainer(config =>\n            config.WithConstructorSelectionRule(Rules.ConstructorSelection.PreferMostParameters));\n        container.Register(typeof(ITest1), typeof(Test1));\n        container.Register(typeof(ITest2), typeof(Test22));\n\n        Assert.NotNull(container.Resolve<ITest2>());\n    }\n\n    [Fact]\n    public void StandardResolveTests_Resolve_MostParametersConstructor()\n    {\n        using IStashboxContainer container = new StashboxContainer(config =>\n            config.WithConstructorSelectionRule(Rules.ConstructorSelection.PreferMostParameters));\n        container.Register(typeof(ITest1), typeof(Test1), context => context.WithName(\"test1\"));\n        container.Register(typeof(ITest1), typeof(Test12), context => context.WithName(\"test12\"));\n        container.Register(typeof(ITest2), typeof(Test222));\n\n        Assert.NotNull(container.Resolve<ITest2>());\n    }\n\n    [Fact]\n    public void StandardResolveTests_Resolve_LeastParametersConstructor()\n    {\n        using IStashboxContainer container = new StashboxContainer(config =>\n            config.WithConstructorSelectionRule(Rules.ConstructorSelection.PreferLeastParameters));\n        container.Register(typeof(ITest1), typeof(Test1));\n        container.Register(typeof(ITest2), typeof(Test2222));\n\n        Assert.NotNull(container.Resolve<ITest2>());\n    }\n\n    [Fact]\n    public void StandardResolveTests_Resolve_None_Of_The_Constructors_Selected()\n    {\n        using IStashboxContainer container = new StashboxContainer(config =>\n            config.WithConstructorSelectionRule(Rules.ConstructorSelection.PreferLeastParameters));\n        container.Register(typeof(ITest2), typeof(Test222));\n\n        var exception = Assert.Throws<ResolutionFailedException>(() => container.Resolve<ITest2>());\n        Assert.Equal(typeof(Test222), exception.Type);\n    }\n\n    [Fact]\n    public void StandardResolveTests_Resolve_Scoped_Ok()\n    {\n        using IStashboxContainer container = new StashboxContainer(config => config.WithLifetimeValidation());\n        container.RegisterScoped<Test1>();\n        var inst = container.BeginScope().ResolveOrDefault<Test1>();\n\n        Assert.NotNull(inst);\n    }\n    \n    [Fact]\n    public void StandardResolveTests_Resolve_Scoped_NullDependency()\n    {\n        using IStashboxContainer container = new StashboxContainer();\n        container.RegisterScoped<Test5>();\n        var inst = container.ResolveOrDefault<Test5>();\n\n        Assert.Null(inst);\n    }\n\n    [Fact]\n    public void StandardResolveTests_Resolve_Singleton_NullDependency()\n    {\n        using IStashboxContainer container = new StashboxContainer();\n        container.RegisterSingleton<Test5>();\n        var inst = container.ResolveOrDefault<Test5>();\n\n        Assert.Null(inst);\n    }\n\n    [Fact]\n    public void StandardResolveTests_Resolve_WithFinalizer()\n    {\n        var finalized = false;\n        using (IStashboxContainer container = new StashboxContainer())\n        {\n            container.Register<Test1>(context => context.WithFinalizer(_ => finalized = true));\n            container.Resolve<Test1>();\n        }\n\n        Assert.True(finalized);\n    }\n\n    [Fact]\n    public void StandardResolveTests_ResolveAll_Returns_Empty_When_No_Registered()\n    {\n        using var container = new StashboxContainer().Register<Test1>(c => c.InNamedScope(\"A\"));\n        Assert.Empty(container.ResolveAll<Test1>());\n    }\n\n    [Fact]\n    public void StandardResolveTests_ServiceProvider()\n    {\n        var inst = new StashboxContainer()\n            .Register<ITest1, Test1>()\n            .GetService(typeof(ITest1));\n\n        Assert.NotNull(inst);\n        Assert.IsType<Test1>(inst);\n    }\n\n    [Fact]\n    public void StandardResolveTests_ServiceProvider_Scope_Self()\n    {\n        var scope = new StashboxContainer()\n            .Register<ScopeDependent>()\n            .BeginScope();\n\n        Assert.Same(scope, scope.Resolve<IServiceProvider>());\n        Assert.Same(scope, scope.Resolve<ScopeDependent>().ServiceProvider);\n    }\n\n    class ScopeDependent\n    {\n        public ScopeDependent(IServiceProvider serviceProvider)\n        {\n            ServiceProvider = serviceProvider;\n        }\n\n        public IServiceProvider ServiceProvider { get; }\n    }\n\n    interface ITest1\n    {\n        string Name { get; set; }\n    }\n\n    interface ITest2\n    {\n        string Name { get; set; }\n    }\n\n    interface ITest3\n    {\n        string Name { get; set; }\n    }\n\n    interface ITest4\n    {\n        ITest1 Test { get; }\n        ITest1 Test2 { get; }\n    }\n\n    class Test1 : ITest1\n    {\n        public string Name { get; set; }\n    }\n\n    class Test11 : ITest1\n    {\n        public string Name { get; set; }\n    }\n\n    class Test12 : ITest1\n    {\n        public string Name { get; set; }\n    }\n\n    class Test2 : ITest2\n    {\n        public string Name { get; set; }\n\n        public Test2(ITest1 test1)\n        {\n            Shield.EnsureNotNull(test1, nameof(test1));\n            Shield.EnsureTypeOf<Test1>(test1);\n        }\n    }\n\n    class Test22 : ITest2\n    {\n        public string Name { get; set; }\n\n        public Test22(ITest1 test1)\n        {\n            Shield.EnsureNotNull(test1, nameof(test1));\n            Shield.EnsureTypeOf<Test1>(test1);\n        }\n\n        public Test22(ITest1 test1, int index)\n        {\n            Assert.True(false, \"Wrong constructor selected.\");\n        }\n    }\n\n    class Test222 : ITest2\n    {\n        public string Name { get; set; }\n\n        public Test222(ITest1 test1)\n        {\n            Assert.True(false, \"Wrong constructor selected.\");\n        }\n\n        public Test222([Dependency(\"test1\")] ITest1 test1, [Dependency(\"test12\")] ITest1 test2)\n        {\n            Shield.EnsureNotNull(test1, nameof(test1));\n            Shield.EnsureNotNull(test2, nameof(test2));\n            Shield.EnsureTypeOf<Test1>(test1);\n            Shield.EnsureTypeOf<Test12>(test2);\n        }\n    }\n\n    class Test2222 : ITest2\n    {\n        public string Name { get; set; }\n\n        public Test2222(ITest1 test1)\n        {\n            Shield.EnsureNotNull(test1, nameof(test1));\n            Shield.EnsureTypeOf<Test1>(test1);\n        }\n\n        public Test2222(ITest1 test1, [Dependency(\"test12\")] ITest1 test2)\n        {\n            Assert.True(false, \"Wrong constructor selected.\");\n        }\n    }\n\n    class Test3 : ITest3\n    {\n        public string Name { get; set; }\n\n        public Test3(ITest1 test1, ITest2 test2)\n        {\n            Shield.EnsureNotNull(test1, nameof(test1));\n            Shield.EnsureNotNull(test2, nameof(test2));\n            Shield.EnsureTypeOf<Test1>(test1);\n            Shield.EnsureTypeOf<Test2>(test2);\n        }\n    }\n\n    class Test4 : ITest4\n    {\n        public ITest1 Test { get; }\n\n        [Dependency] public ITest1 Test2 { get; set; }\n\n        public Test4(ITest1 test)\n        {\n            this.Test = test;\n        }\n    }\n\n    class Test5\n    {\n        public Test5(ITest1 test)\n        {\n        }\n    }\n\n    class ResolverTest\n    {\n        public IDependencyResolver DependencyResolver { get; }\n\n        public ResolverTest(IDependencyResolver dependencyResolver)\n        {\n            this.DependencyResolver = dependencyResolver;\n        }\n    }\n\n    class Dummy;\n}"
  },
  {
    "path": "test/Utils/CompilerType.cs",
    "content": "﻿namespace Stashbox.Tests.Utils;\n\npublic enum CompilerType\n{\n    Default,\n    Microsoft,\n    Stashbox,\n    FastExpressionCompiler,\n}"
  },
  {
    "path": "test/Utils/CompilerTypeTestData.cs",
    "content": "﻿using System.Collections;\nusing System.Collections.Generic;\n\nnamespace Stashbox.Tests.Utils;\n\npublic class CompilerTypeTestData : IEnumerable<object[]>\n{\n    public IEnumerator<object[]> GetEnumerator()\n    {\n        yield return [CompilerType.Default];\n        yield return [CompilerType.Microsoft];\n        yield return [CompilerType.Stashbox];\n        yield return [CompilerType.FastExpressionCompiler];\n    }\n\n    IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();\n}"
  },
  {
    "path": "test/Utils/ContainerConfiguratorExtensions.cs",
    "content": "﻿using FastExpressionCompiler;\nusing Stashbox.Tests.Utils;\n\nnamespace Stashbox.Configuration;\n\npublic static class ContainerConfiguratorExtensions\n{\n    public static ContainerConfigurator WithCompiler(this ContainerConfigurator configurator, CompilerType compilerType)\n    {\n        return compilerType switch\n        {\n            CompilerType.Microsoft => configurator.WithExpressionCompiler(Rules.ExpressionCompilers.MicrosoftExpressionCompiler),\n            CompilerType.Stashbox => configurator.WithExpressionCompiler(Rules.ExpressionCompilers.StashboxExpressionCompiler),\n            CompilerType.FastExpressionCompiler => configurator.WithExpressionCompiler(lambda => lambda.CompileFast()),\n            _ => configurator,\n        };\n    }\n}"
  },
  {
    "path": "test/Utils/TypeGen.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\n\nnamespace Stashbox.Tests.Utils;\n\npublic static class TypeGen\n{\n    public static (Type, Type) GetCollidingTypes()\n    {\n        var hashes = new Dictionary<int, Type>();\n        uint n = 0;\n        while (true)\n        {\n            var type = GenerateType(n++);\n            var hash = System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode(type);\n            if (hashes.TryGetValue(hash, out var hash1))\n            {\n                return (hash1, type);\n            }\n\n            hashes.Add(hash, type);\n        }\n    }\n\n    private static Type GenerateType(uint n)\n    {\n        var current = typeof(Nil);\n        for (var i=0; i < sizeof(uint) * 8; i++)\n        {\n            var leading = n >> i;\n            if (leading == 0) {\n                return current;\n            }\n\n            var bit = (n >> i) & 0x01;\n            current = bit == 0 ? typeof(Zero<>).MakeGenericType(current) : typeof(One<>).MakeGenericType(current);\n        }\n        return current;\n    }\n    \n    private class Nil;\n    private class Zero<T>;\n    private class One<T>;\n}"
  },
  {
    "path": "test/WireUpTests.cs",
    "content": "﻿using Stashbox.Attributes;\nusing Stashbox.Utils;\nusing Xunit;\n\nnamespace Stashbox.Tests;\n\npublic class WireUpTests\n{\n    [Fact]\n    public void WireUp_Multiple()\n    {\n        using var container = new StashboxContainer();\n        var test1 = new Test1();\n        container.WireUp<ITest1>(test1);\n\n        var test2 = new Test();\n        container.WireUp<ITest>(test2);\n\n        var inst = container.Resolve<ITest1>();\n        var inst2 = container.Resolve<ITest>();\n\n        Assert.Same(test1, inst);\n        Assert.Same(test2, inst2);\n    }\n\n    [Fact]\n    public void WireUp_Multiple_Named()\n    {\n        using var container = new StashboxContainer();\n        var test1 = new Test();\n        container.WireUp<ITest>(test1, \"test1\");\n\n        var test2 = new Test();\n        container.WireUp<ITest>(test2, \"test2\");\n\n        var inst = container.Resolve<ITest>(\"test1\");\n        var inst2 = container.Resolve<ITest>(\"test2\");\n\n        Assert.Same(test1, inst);\n        Assert.Same(test2, inst2);\n    }\n\n    [Fact]\n    public void WireUpTests_InjectionMember()\n    {\n        using var container = new StashboxContainer();\n        container.RegisterSingleton<ITest, Test>();\n\n        var test1 = new Test1();\n        container.WireUp<ITest1>(test1);\n\n        container.Register<Test2>();\n\n        var inst = container.Resolve<Test2>();\n\n        Assert.NotNull(inst);\n        Assert.NotNull(inst.Test1);\n        Assert.IsType<Test2>(inst);\n        Assert.IsType<Test1>(inst.Test1);\n        Assert.IsType<Test>(inst.Test1.Test);\n    }\n\n    [Fact]\n    public void WireUpTests_InjectionMember_ServiceUpdated()\n    {\n        using var container = new StashboxContainer();\n        container.RegisterSingleton<ITest, Test>();\n\n        var test1 = new Test1();\n        container.WireUp<ITest1>(test1);\n\n        container.ReMap<ITest, Test>(c => c.WithSingletonLifetime());\n\n        container.Register<Test2>();\n\n        var inst = container.Resolve<Test2>();\n\n        Assert.NotNull(inst);\n        Assert.NotNull(inst.Test1);\n        Assert.IsType<Test2>(inst);\n        Assert.IsType<Test1>(inst.Test1);\n        Assert.IsType<Test>(inst.Test1.Test);\n    }\n\n    [Fact]\n    public void WireUpTests_InjectionMember_WithoutService()\n    {\n        using var container = new StashboxContainer();\n        container.RegisterSingleton<ITest, Test>();\n        var test1 = new Test1();\n        container.WireUp(test1);\n        var inst = container.Resolve<Test1>();\n\n        Assert.NotNull(inst);\n        Assert.NotNull(inst.Test);\n        Assert.IsType<Test1>(inst);\n        Assert.IsType<Test>(inst.Test);\n    }\n\n    [Fact]\n    public void WireUpTests_WithoutService_NonGeneric()\n    {\n        using var container = new StashboxContainer();\n        container.RegisterSingleton<ITest, Test>();\n        object test1 = new Test1();\n        container.WireUp(test1, typeof(Test1));\n        var inst = container.Resolve<Test1>();\n\n        Assert.NotNull(inst);\n        Assert.NotNull(inst.Test);\n        Assert.NotNull(inst.test);\n        Assert.IsType<Test1>(inst);\n        Assert.IsType<Test>(inst.Test);\n        Assert.IsType<Test>(inst.test);\n    }\n\n    interface ITest;\n\n    interface ITest1 { ITest Test { get; } }\n\n    class Test : ITest;\n\n    class Test1 : ITest1\n    {\n        [Dependency]\n#pragma warning disable 649\n        public ITest test;\n#pragma warning restore 649\n\n        [Dependency]\n        public ITest Test { get; set; }\n\n        [InjectionMethod]\n        public void Init()\n        {\n            Shield.EnsureNotNull(Test, nameof(Test));\n        }\n    }\n\n    class Test2\n    {\n        public ITest1 Test1 { get; set; }\n\n        public Test2(ITest1 test1)\n        {\n            this.Test1 = test1;\n        }\n    }\n}"
  },
  {
    "path": "test/WithDynamicResolutionTests.cs",
    "content": "﻿using System;\nusing Xunit;\n\nnamespace Stashbox.Tests;\n\npublic class WithDynamicResolutionTests\n{\n    [Fact]\n    public void WithDynamicResolutionTests_TopRequest()\n    {\n        using var container = new StashboxContainer()\n            .Register<A>(c => c.WithDynamicResolution());\n\n        Assert.NotNull(container.Resolve<A>());\n    }\n\n    [Fact]\n    public void WithDynamicResolutionTests_Dependency()\n    {\n        using var container = new StashboxContainer()\n            .Register<A>(c => c.WithDynamicResolution())\n            .Register<B>(c => c.WithDependencyBinding(\"A\"));\n\n        Assert.NotNull(container.Resolve<B>().A);\n    }\n\n    [Fact]\n    public void WithDynamicResolutionTests_Dependency_Override()\n    {\n        using var container = new StashboxContainer()\n            .Register<B>(c => c.WithDependencyBinding(\"A\").WithDynamicResolution())\n            .Register<C>(c => c.WithDependencyBinding(\"B\"));\n\n        var @override = new A();\n        var inst = container.Resolve<C>([@override]);\n\n        Assert.Same(@override, inst.B.A);\n    }\n\n    [Fact]\n    public void WithDynamicResolutionTests_Circle()\n    {\n        using var container = new StashboxContainer()\n            .Register<Circle1>(c => c.WithDependencyBinding(\"Circle2\").WithDynamicResolution())\n            .Register<Circle2>(c => c.WithDependencyBinding(\"Circle1\").WithDynamicResolution());\n\n        var circle1 = container.Resolve<Circle1>();\n        var circle2 = container.Resolve<Circle2>();\n\n        Assert.NotNull(circle1.Circle2.Value);\n        Assert.NotNull(circle1.Circle2.Value.Circle1);\n        Assert.NotNull(circle2.Circle1.Value);\n        Assert.NotNull(circle2.Circle1.Value.Circle2);\n    }\n\n    class A;\n\n    class B\n    {\n        public A A { get; set; }\n    }\n\n    class C\n    {\n        public B B { get; set; }\n    }\n\n    class Circle1\n    {\n        public Lazy<Circle2> Circle2 { get; set; }\n    }\n\n    class Circle2\n    {\n        public Lazy<Circle1> Circle1 { get; set; }\n    }\n}"
  },
  {
    "path": "test/stashbox.tests.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>    \n    <TargetFrameworks>net5.0;net6.0;net7.0;net8.0;net9.0;net10.0</TargetFrameworks>    \n    <AssemblyName>Stashbox.Tests</AssemblyName>    \n    <RootNamespace>Stashbox.Tests</RootNamespace>\n    <SignAssembly>true</SignAssembly>\n    <AssemblyOriginatorKeyFile>../sn.snk</AssemblyOriginatorKeyFile>\n    <LangVersion>latest</LangVersion>\n    <GenerateAssemblyInfo>false</GenerateAssemblyInfo>\n  </PropertyGroup>\n\n  <PropertyGroup Condition=\"'$(TargetFramework)' == 'net5.0' Or '$(TargetFramework)' == 'net6.0'\">\n    <DefineConstants>HAS_ASYNC_DISPOSABLE</DefineConstants>\n  </PropertyGroup>\n\n  <PropertyGroup Condition=\"'$(TargetFramework)' == 'net7.0' Or '$(TargetFramework)' == 'net8.0' Or '$(TargetFramework)' == 'net9.0' Or '$(TargetFramework)' == 'net10.0'\">\n    <DefineConstants>HAS_ASYNC_DISPOSABLE;HAS_REQUIRED</DefineConstants>\n  </PropertyGroup>\n  \n  <ItemGroup>\n    <Compile Remove=\"testassembly\\**\" />\n    <EmbeddedResource Remove=\"testassembly\\**\" />\n    <None Remove=\"testassembly\\**\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"coverlet.collector\" Version=\"3.1.2\">\n      <PrivateAssets>all</PrivateAssets>\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n    </PackageReference>\n    <PackageReference Include=\"FastExpressionCompiler\" Version=\"3.2.2\" />\n    <PackageReference Include=\"Microsoft.NET.Test.Sdk\" Version=\"17.1.0\" />\n    <PackageReference Include=\"Moq\" Version=\"4.17.1\" />\n    <PackageReference Include=\"xunit\" Version=\"2.4.1\" />\n    <PackageReference Include=\"xunit.runner.visualstudio\" Version=\"2.4.3\">\n      <PrivateAssets>all</PrivateAssets>\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>\n    </PackageReference>\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\src\\stashbox.csproj\" />\n    <ProjectReference Include=\"testassembly\\testassembly.csproj\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <Service Include=\"{82a7f48d-3b50-4b1e-b82e-3ada8210c358}\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "test/testassembly/Composition.cs",
    "content": "﻿using Stashbox;\n\nnamespace TestAssembly\n{\n    public class Composition : ICompositionRoot\n    {\n        public void Compose(IStashboxContainer container)\n        {\n            container.Register<IComp, Comp>(c => c.WithName(\"Comp\"));\n        }\n    }\n\n    public interface IComp { }\n\n    class Comp : IComp { }\n}\n"
  },
  {
    "path": "test/testassembly/TestClasses.cs",
    "content": "﻿namespace TestAssembly\n{\n    public interface ITA_T1 { }\n\n    public interface ITA_T2 { }\n\n    public interface ITA_TG<T> { }\n\n    public abstract class TA_A { }\n\n    public interface ITA_TGM<T1, T2> { }\n\n    public class TA_T1 : ITA_T1 { }\n\n    public class TA_TM1 : ITA_T1 { }\n\n    public class TA_TM2 : ITA_T1 { }\n\n    public class TA_TM3 : ITA_T1 { }\n\n    public class TA_T2 : ITA_T1, ITA_T2 { }\n\n    public class TA_T3 : ITA_T1, ITA_T2 { }\n\n    public class TA_TG<T> : ITA_TG<T> { }\n\n    public class TA_TGC1 : ITA_TG<int> { }\n\n    public class TA_TGC2 : ITA_TG<string> { }\n\n    public class TA_TGC3 : ITA_TG<double> { }\n\n    public class TA_TGM<T1, T2> : ITA_TGM<T1, T2> { }\n\n    public class TA_TGMI<T1> : ITA_TGM<T1, int> { }\n\n    public class TA_AI1 : TA_A { }\n\n    public class TA_AI2 : TA_A, ITA_T1 { }\n}\n"
  },
  {
    "path": "test/testassembly/testassembly.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <TargetFramework>netstandard2.0</TargetFramework>\n    <AssemblyName>TestAssembly</AssemblyName>\n    <RootNamespace>TestAssembly</RootNamespace>\n    <SignAssembly>true</SignAssembly>\n    <AssemblyOriginatorKeyFile>../../sn.snk</AssemblyOriginatorKeyFile>\n  </PropertyGroup>\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\src\\stashbox.csproj\" />\n  </ItemGroup>\n</Project>\n"
  }
]