CodeChops.ImplementationDiscovery
1.8.8
dotnet add package CodeChops.ImplementationDiscovery --version 1.8.8
NuGet\Install-Package CodeChops.ImplementationDiscovery -Version 1.8.8
<PackageReference Include="CodeChops.ImplementationDiscovery" Version="1.8.8" />
paket add CodeChops.ImplementationDiscovery --version 1.8.8
#r "nuget: CodeChops.ImplementationDiscovery, 1.8.8"
// Install CodeChops.ImplementationDiscovery as a Cake Addin #addin nuget:?package=CodeChops.ImplementationDiscovery&version=1.8.8 // Install CodeChops.ImplementationDiscovery as a Cake Tool #tool nuget:?package=CodeChops.ImplementationDiscovery&version=1.8.8
Implementation discovery
Provides easy-accessible, design-time information about implementations throughout your code. Just place an attribute on a specific base class or interface whose implementations you want to discover. A source generator will create an eum at design time that contains instances of all implementations.
Check out CodeChops projects for more projects.
Advantages
- All implementations of a specific class or interface are centralized in one place.
- You have a simple and navigable overview over what is implemented.
- Does not use reflection. This improves startup time of your app.
- Assembly-level trimming can be implemented in your libraries with ease: Implementations will not be trimmed because the enum contains a hard link to each implementation.
- No need to manually implement logic to search for the correct implementation.
- Members can be found in a static context, so there is no need to pass around a collection of implementations.
Usage
- Make the
base class
orinterface
whose implementations you want to discoverpartial
. - Place the attribute
DiscoverImplementations
on the declaration and optionally provide the following parameters:EnumName
: The name of the enum that is being generated. If not provided, it will create one for you, see enum name creation.GenerateImplementationIds
: Iftrue
(default), all discovered implementations get an implementation ID property, see implementation IDs.GenerateProxies
: Iftrue
, implementations are discovered in assemblies that reference the base class / interface that has to be discovered. This is done by creating a proxy enum in the assembly of the implementation (under the namespace of the base class / interface. It is set tofalse
by default. For more information, see cross-assembly implementations.
Enum name creation
If no custom enum name has been provided to the attribute, a name will be created for you: The name of the base class or interface will be used without the leading 'I' (for interfaces) or trailing 'Base' for base classes.
Enum
will be placed at the end of the name. Examples:
AnimalBase
will becomeAnimalEnum
.IVehicle
will becomeVehicleEnum
.
The LightResources library makes use of this library to collect all the resources within an assemby.
The Geometry library makes use of this library to collect every
StrictDirection
implementation under one enum.
The Blame game engine library makes use of this library to discover implemented GameObjects (not released yet).
Concepts
Implementations enum
When the 2 steps above are executed, an enum will be source generated in the same namespace
as the base class / interface.
The enum is inherited from ImplementationsEnum
.
It contains a mapping from implementation class name (the value of the enum member) to a discovered object (the value of the enum member).
This enum can be used to iterate or look up members dynamically or statically, see API.
The implementations enum makes use of MagicEnums under the hood: a customizable and extendable way to implement enums. For more information, see the MagicEnums library.
Discovered object
The value of each enum member is a DiscoveredObject
.
This object contains the type, an instance, and a factory of the discovered implementation.
It can implicitly be casted to the the concrete type of the implementation or the base class / interface.
Implementation IDs
When setting GenerateImplementationIds
is enabled, each discovered implementation gets an implementation ID property when it is set to partial
.
A static
property named ImplementationId
will be generated which holds the corresponding implementation enum value.
It creates an easy way to reach the implementation enum and look up members dynamically.
API
Implementation discovery makes use of MagicEnums under the hood, so the base API is the same as the MagicEnum API:
Method | Description |
---|---|
CreateMember |
Creates a new discovered implementation member and returns it. |
GetEnumerator |
Gets an enumerator over the enum members. |
GetMembers |
Gets an enumerable over:<br/>- All enum members, or<br/>- Members of a specific value: Throws when no member has been found. |
GetValues |
Gets an enumerable over the member values. |
TryGetMembers |
Tries to get member(s) by value. |
TryGetSingleMember |
Tries to get a single member by name / value.<br/>Throws when multiple members of the same value have been found. |
GetSingleMember |
Gets a single member by name / value.<br/>Throws when not found or multiple members have been found. |
GetUniqueValueCount |
Gets the unique member value count. |
GetMemberCount |
Gets the member count. |
GetDefaultValue |
Gets the default value of the enum. |
GetOrCreateMember |
Creates a member or gets one if a member already exists. |
This API can be used to search for, or create implementations at runtime.
This package offers some extra methods and classes on the enum (ImplementationsEnum
) and on the value (DiscoveredObject
) of each member:
Member | Description |
---|---|
Instance |
The instance of the discovered implementation. Don't mutate this instance as it will be used by other processes. |
Type |
The type of the discovered implementation. |
Create() |
Creates a new instance of the discovered object. |
IsInitialized * |
Is false when the enum is still in static buildup and true if this is finished. This parameter can be used to detect cyclic references during buildup and act accordingly. |
GetInstances() * |
Gets an IEnumerable over the instances of all discovered implementations. |
Members marked with the * are only exposed on the
ImplementationsEnum
, not on theDiscoveredObject
.
Examples
This generates the following code:
// <auto-generated />
#nullable enable
#pragma warning disable CS0109
using CodeChops.ImplementationDiscovery;
using CodeChops.MagicEnums;
using CodeChops.MagicEnums.Core;
using System;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
/// <summary>
/// Discovered implementations: <see cref="AnimalEnum"/>.
/// </summary>
public partial record class Animal
{
public static IImplementationsEnum<Animal> ImplementationEnum { get; } = new AnimalEnum();
}
/// <summary>
/// Discovered implementations for <see cref="Animal"/>:
/// <list type="table">
/// <item><see cref="global::Cat"/></item>
/// <item><see cref="global::Dog"/></item>
/// </list>
/// </summary>
internal partial record AnimalEnum : ImplementationsEnum<AnimalEnum, Animal>, IInitializable
{
/// <summary>
/// <see cref="global::Cat"/>
/// </summary>
public static AnimalEnum Cat { get; } = CreateMember(new DiscoveredObject<Animal>(typeof(global::Cat)));
/// <summary>
/// <see cref="global::Dog"/>
/// </summary>
public static AnimalEnum Dog { get; } = CreateMember(new DiscoveredObject<Animal>(typeof(global::Dog)));
#region Initialization
/// <summary>
/// Is false when the enum is still in static buildup and true if this is finished.
/// This parameter can be used to detect cyclic references during buildup and act accordingly.
/// </summary>
public new static bool IsInitialized { get; }
static AnimalEnum()
{
IsInitialized = true;
}
#endregion
}
Global implementations
By default a global implementations enum will be generated in the root namespace of the assembly with the name AllDiscoveredImplementations
.
This enum contains all discovered enums as value and makes it easy to find base enums / interfaces whose implementations should be discovered.
You can navigate to the concrete implementations using these values.
Cross-assembly implementations
Implementations can also be discovered across different assemblies, resulting in proxy eums
.
This can be done by enabling setting generateProxies
. If this setting it set to true
and the base class / interface is implemented in a different assembly,
the referenced assembly will contain a proxy enum. Imagine the follow situation:
- The package
LightResources
contains an interfaceIResource
whose implementations are discoverable. This interface should be implemented by every resource. - Your website consumes that package and implements
IResource
.
What happens:
- A proxy implementation enum is now created in the project of your website under the
namespace
ofIResource
. - The name of the
proxy enum
ends withProxyEnum
. - When the resource package is being called you can easily hand over your implementations using dependency injection, so the
LightResources
library can consume it.
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net9.0 is compatible. |
-
net9.0
- CodeChops.DomainModeling (>= 2.18.4)
- CodeChops.MagicEnums (>= 3.9.2)
NuGet packages (3)
Showing the top 3 NuGet packages that depend on CodeChops.ImplementationDiscovery:
Package | Downloads |
---|---|
CodeChops.Geometry
Contains objects and helpers to help the calculation of objects in 2D-space and time. |
|
CodeChops.LightResources
Light and dynamic resources for your Blazor WebAssembly website. |
|
CodeChops.Contracts
Easy use of contracts, adapters and polymorphism, using JSON. |
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last updated |
---|---|---|
1.8.8 | 506 | 11/19/2024 |
1.8.7 | 416 | 9/29/2024 |
1.8.6 | 512 | 3/20/2023 |
1.8.5 | 387 | 3/10/2023 |
1.8.4 | 258 | 3/9/2023 |
1.8.3 | 394 | 3/6/2023 |
1.8.0 | 351 | 1/27/2023 |
1.7.0 | 354 | 1/22/2023 |
1.5.2 | 375 | 1/21/2023 |
1.5.1 | 377 | 1/21/2023 |
1.4.0 | 490 | 1/16/2023 |
1.3.2 | 329 | 1/10/2023 |
1.3.1 | 329 | 1/10/2023 |
1.2.0 | 371 | 1/10/2023 |
1.1.4 | 352 | 1/7/2023 |
1.1.3 | 353 | 1/7/2023 |
1.1.2 | 316 | 1/6/2023 |
1.1.1 | 483 | 1/6/2023 |
1.0.4 | 345 | 1/4/2023 |
1.0.2 | 356 | 1/4/2023 |
1.0.1 | 339 | 1/3/2023 |
1.0.0 | 331 | 1/2/2023 |
0.38.1 | 585 | 12/23/2022 |
0.20.8 | 466 | 9/17/2022 |
0.20.7 | 456 | 9/16/2022 |
0.20.5 | 458 | 9/16/2022 |
0.7.2 | 437 | 7/11/2022 |
0.7.1 | 616 | 7/11/2022 |
0.7.0 | 502 | 7/11/2022 |
0.6.9 | 733 | 7/10/2022 |
0.6.8 | 571 | 7/10/2022 |
0.6.7 | 441 | 7/10/2022 |
0.6.6 | 634 | 7/10/2022 |
0.6.5 | 428 | 7/8/2022 |
0.6.4 | 429 | 7/8/2022 |
0.6.3 | 419 | 7/7/2022 |
0.6.2 | 434 | 7/7/2022 |
0.6.1 | 433 | 7/6/2022 |
0.6.0 | 450 | 7/6/2022 |
0.5.7 | 470 | 7/5/2022 |
0.5.6 | 429 | 6/27/2022 |
0.4.5 | 582 | 6/23/2022 |
0.4.4 | 449 | 6/23/2022 |
0.4.2 | 714 | 6/21/2022 |
0.3.2 | 431 | 6/15/2022 |
0.3.1 | 419 | 6/15/2022 |
0.3.0 | 415 | 6/15/2022 |
0.2.2 | 418 | 6/14/2022 |
0.2.0 | 470 | 6/14/2022 |
0.1.9 | 459 | 6/14/2022 |
0.1.8 | 438 | 6/14/2022 |
0.1.7 | 430 | 6/14/2022 |
0.1.6 | 437 | 6/13/2022 |
0.1.5 | 445 | 6/13/2022 |
Updated packages 5.