Skip to content

Latest commit

 

History

History
208 lines (181 loc) · 6.02 KB

File metadata and controls

208 lines (181 loc) · 6.02 KB

Enumerable generics

Shows how generic middleware pipelines collect all matching implementations.

using Shouldly;
using Pure.DI;
using System.Collections.Immutable;

DI.Setup(nameof(Composition))
    // Register generic middleware components.
    // LoggingMiddleware<T> is registered as the default implementation.
    .Bind<IMiddleware<TT>>().To<LoggingMiddleware<TT>>()
    // MetricsMiddleware<T> is registered with the "Metrics" tag.
    .Bind<IMiddleware<TT>>("Metrics").To<MetricsMiddleware<TT>>()

    // Register the pipeline that takes the collection of all middleware.
    .Bind<IPipeline<TT>>().To<Pipeline<TT>>()

    // Composition roots for different data types (int and string)
    .Root<IPipeline<int>>("IntPipeline")
    .Root<IPipeline<string>>("StringPipeline");

var composition = new Composition();

// Validate the pipeline for int
var intPipeline = composition.IntPipeline;
intPipeline.Middlewares.Length.ShouldBe(2);
intPipeline.Middlewares[0].ShouldBeOfType<LoggingMiddleware<int>>();
intPipeline.Middlewares[1].ShouldBeOfType<MetricsMiddleware<int>>();

// Validate the pipeline for string
var stringPipeline = composition.StringPipeline;
stringPipeline.Middlewares.Length.ShouldBe(2);
stringPipeline.Middlewares[0].ShouldBeOfType<LoggingMiddleware<string>>();
stringPipeline.Middlewares[1].ShouldBeOfType<MetricsMiddleware<string>>();

// Middleware interface
interface IMiddleware<T>;

// Logging implementation
class LoggingMiddleware<T> : IMiddleware<T>;

// Metrics implementation
class MetricsMiddleware<T> : IMiddleware<T>;

// Pipeline interface
interface IPipeline<T>
{
    ImmutableArray<IMiddleware<T>> Middlewares { get; }
}

// Pipeline implementation that aggregates all available middleware
class Pipeline<T>(IEnumerable<IMiddleware<T>> middlewares) : IPipeline<T>
{
    public ImmutableArray<IMiddleware<T>> Middlewares { get; }
        = [..middlewares];
}
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

Generic enumerable injections are useful for implementing middleware patterns where multiple handlers need to be invoked in sequence.

The following partial class will be generated:

partial class Composition
{
  public IPipeline<string> StringPipeline
  {
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    get
    {
      [MethodImpl(MethodImplOptions.AggressiveInlining)]
      IEnumerable<IMiddleware<string>> EnumerationOf_perBlockIEnumerable388()
      {
        yield return new LoggingMiddleware<string>();
        yield return new MetricsMiddleware<string>();
      }

      return new Pipeline<string>(EnumerationOf_perBlockIEnumerable388());
    }
  }

  public IPipeline<int> IntPipeline
  {
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    get
    {
      [MethodImpl(MethodImplOptions.AggressiveInlining)]
      IEnumerable<IMiddleware<int>> EnumerationOf_perBlockIEnumerable392()
      {
        yield return new LoggingMiddleware<int>();
        yield return new MetricsMiddleware<int>();
      }

      return new Pipeline<int>(EnumerationOf_perBlockIEnumerable392());
    }
  }
}

Class diagram:

---
 config:
  maxTextSize: 2147483647
  maxEdges: 2147483647
  class:
   hideEmptyMembersBox: true
---
classDiagram
	PipelineᐸStringᐳ --|> IPipelineᐸStringᐳ
	PipelineᐸInt32ᐳ --|> IPipelineᐸInt32ᐳ
	LoggingMiddlewareᐸStringᐳ --|> IMiddlewareᐸStringᐳ
	MetricsMiddlewareᐸStringᐳ --|> IMiddlewareᐸStringᐳ : "Metrics" 
	LoggingMiddlewareᐸInt32ᐳ --|> IMiddlewareᐸInt32ᐳ
	MetricsMiddlewareᐸInt32ᐳ --|> IMiddlewareᐸInt32ᐳ : "Metrics" 
	Composition ..> PipelineᐸStringᐳ : IPipelineᐸStringᐳ StringPipeline
	Composition ..> PipelineᐸInt32ᐳ : IPipelineᐸInt32ᐳ IntPipeline
	PipelineᐸStringᐳ o-- "PerBlock" IEnumerableᐸIMiddlewareᐸStringᐳᐳ : IEnumerableᐸIMiddlewareᐸStringᐳᐳ
	PipelineᐸInt32ᐳ o-- "PerBlock" IEnumerableᐸIMiddlewareᐸInt32ᐳᐳ : IEnumerableᐸIMiddlewareᐸInt32ᐳᐳ
	IEnumerableᐸIMiddlewareᐸStringᐳᐳ *--  LoggingMiddlewareᐸStringᐳ : IMiddlewareᐸStringᐳ
	IEnumerableᐸIMiddlewareᐸStringᐳᐳ *--  MetricsMiddlewareᐸStringᐳ : "Metrics"  IMiddlewareᐸStringᐳ
	IEnumerableᐸIMiddlewareᐸInt32ᐳᐳ *--  LoggingMiddlewareᐸInt32ᐳ : IMiddlewareᐸInt32ᐳ
	IEnumerableᐸIMiddlewareᐸInt32ᐳᐳ *--  MetricsMiddlewareᐸInt32ᐳ : "Metrics"  IMiddlewareᐸInt32ᐳ
	namespace Pure.DI.UsageTests.BCL.EnumerableGenericsScenario {
		class Composition {
		<<partial>>
		+IPipelineᐸInt32ᐳ IntPipeline
		+IPipelineᐸStringᐳ StringPipeline
		}
		class IMiddlewareᐸInt32ᐳ {
			<<interface>>
		}
		class IMiddlewareᐸStringᐳ {
			<<interface>>
		}
		class IPipelineᐸInt32ᐳ {
			<<interface>>
		}
		class IPipelineᐸStringᐳ {
			<<interface>>
		}
		class LoggingMiddlewareᐸInt32ᐳ {
				<<class>>
			+LoggingMiddleware()
		}
		class LoggingMiddlewareᐸStringᐳ {
				<<class>>
			+LoggingMiddleware()
		}
		class MetricsMiddlewareᐸInt32ᐳ {
				<<class>>
			+MetricsMiddleware()
		}
		class MetricsMiddlewareᐸStringᐳ {
				<<class>>
			+MetricsMiddleware()
		}
		class PipelineᐸInt32ᐳ {
				<<class>>
			+Pipeline(IEnumerableᐸIMiddlewareᐸInt32ᐳᐳ middlewares)
		}
		class PipelineᐸStringᐳ {
				<<class>>
			+Pipeline(IEnumerableᐸIMiddlewareᐸStringᐳᐳ middlewares)
		}
	}
	namespace System.Collections.Generic {
		class IEnumerableᐸIMiddlewareᐸInt32ᐳᐳ {
				<<interface>>
		}
		class IEnumerableᐸIMiddlewareᐸStringᐳᐳ {
				<<interface>>
		}
	}
Loading