Skip to content

Latest commit

 

History

History
125 lines (100 loc) · 3.03 KB

bind-generic-contract-attribute.md

File metadata and controls

125 lines (100 loc) · 3.03 KB

Bind generic contract attribute

Shows how the built-in BindAttribute can declare a generic contract with the TT marker on a generic implementation. One attribute on CardboardBox<TT> then satisfies every closed instantiation the graph asks for.

using Shouldly;
using Pure.DI;

DI.Setup(nameof(Composition))
    .Bind<ICat>().To<ShroedingersCat>()

    // Composition root
    .Root<IBox<ICat>>("Box");

var composition = new Composition();
var box = composition.Box;

box.ShouldBeOfType<CardboardBox<ICat>>();
box.Content.ShouldBeOfType<ShroedingersCat>();

interface IBox<out T>
{
    T Content { get; }
}

interface ICat;

[Bind(typeof(IBox<TT>))]
record CardboardBox<T>(T Content) : IBox<T>;

class ShroedingersCat : ICat;
Running this code sample locally
dotnet --list-sdk
  • Create a net10.0 (or later) console application
dotnet new console -n Sample
dotnet add package Pure.DI
dotnet add package Shouldly
  • Copy the example code into the Program.cs file

You are ready to run the example 🚀

dotnet run

Note

typeof(IBox<TT>) is a marker-based generic contract. It is different from the open generic typeof(IBox<>): Pure.DI uses TT to construct the matching implementation type, such as CardboardBox<TT>.

Because the marker follows the requested type argument, IBox<int> and IBox<string> are both built from the same declaration, and the generated code is concrete for each of them. There is no open-generic registration to look up at run time. The contract has to be declared with the marker, not with <>, or the generator cannot match the implementation's own type parameters. Keep the number and order of markers aligned between contract and implementation.

The following partial class will be generated
partial class Composition
{
  public IBox<ICat> Box
  {
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    get
    {
      return new CardboardBox<ICat>(new ShroedingersCat());
    }
  }
}

Class diagram:

---
 config:
  class:
   hideEmptyMembersBox: true
---
classDiagram
	ShroedingersCat --|> ICat
	CardboardBoxᐸICatᐳ --|> IBoxᐸICatᐳ
	Composition ..> CardboardBoxᐸICatᐳ : IBoxᐸICatᐳ Box
	CardboardBoxᐸICatᐳ *-- ShroedingersCat : ICat
	namespace Pure.DI.UsageTests.Attributes.BindGenericContractAttributeScenario {
		class CardboardBoxᐸICatᐳ {
				<<record>>
			+CardboardBox(ICat Content)
		}
		class Composition {
		<<partial>>
		+IBoxᐸICatᐳ Box
		}
		class IBoxᐸICatᐳ {
			<<interface>>
		}
		class ICat {
			<<interface>>
		}
		class ShroedingersCat {
				<<class>>
			+ShroedingersCat()
		}
	}
Loading

See also: