Compare commits

..

54 Commits

Author SHA1 Message Date
Simon G. a584095df2
Merge pull request #62 from SimonG96/UseIncrementalGenerator 2 days ago
Simon G. a3c244e8da
#62: extract and use more methods to keep type handling the same 2 days ago
Simon G. f0082da9e4
#62: add missing description 2 days ago
Simon G. 35250d4fa0
#62: add missing description 2 days ago
Simon G. a7c4e5ed12
#62: fix typo 2 days ago
Simon G. c67868db74
- remove unneeded references 2 days ago
Simon G. f16a6e4b2d
- update copyright 2 days ago
Simon G. fa20b72e01
- add beta version suffix 2 days ago
Simon G. d7ae46bb17
- cleanup csproj 2 days ago
Simon G. d7503ba68d
- add factoryGenerator nuget badges to readme 2 days ago
Simon G. cdc96ccb4c
- new constraint must be last 2 days ago
Simon G. b3f9a96326
- use factory resolve instead of normal resolve 3 days ago
Simon G. ab810a5430
- fix generic arguments and nullability 3 days ago
Simon G. 610c47bc15
- add more test cases with nullable and generic parameters 3 days ago
Simon G. b16721164b
- remove unneeded annotations 3 days ago
Simon G. 8d9777a954
- add all existing test cases that use current factory implementation and substitute it with generated factories 3 days ago
Simon G. 01ee6324de
- make internals visible to new test lib 3 days ago
Simon G. 07538852f2
- add usings for returnValues and parameters 3 days ago
Simon G. 40e0260428
- move files to folders to test correct generation of usings 3 days ago
Simon G. ba922066a1
- add test lib for generator 3 days ago
Simon G. cf95372926
- update nuget packages 3 days ago
Simon G. b5f16126fe
- don't generate a file twice for the same factory 3 days ago
Simon G. 0a006ae787
- update readme 3 days ago
Simon G. 2b6abe5e1f
- only append empty line if not last member 3 days ago
Simon G. dfe0b5713c
- implement clear multiton instance method 3 days ago
Simon G. ec4d0bcb67
- add clearMultitonInstance method to sample 3 days ago
Simon G. 2bfec513e8
- combine appends 3 days ago
Simon G. de0e6b2363
- remove leftover line 3 days ago
Simon G. f0b59b84b7
- use correct types for async resolve 3 days ago
Simon G. 1a3cb30e82
- remove duplicate semicolon 3 days ago
Simon G. 79642012e6
- add methods to test more factory types 3 days ago
Simon G. 94c244a774
- add missing semicolon 3 days ago
Simon G. ae1ed6dd4c
- enable nullable explicitly 3 days ago
Simon G. 88e242ed20
- first implementation generating factory source code 4 days ago
Simon G. aea48017a7
- don't need to use factoryHelper anymore 4 days ago
Simon G. 0ac89506c1
- builder now implements iFactoryBuilder that is called from registration 4 days ago
Simon G. daad788b2e
- introduce factory builder to create factory instances 4 days ago
Simon G. be1cea11e0
- update xml comments 4 days ago
Simon G. 68baf341b4
- call method from interface 4 days ago
Simon G. 8779c6883d
- expose addGeneratedFactory in interface 4 days ago
Simon G. aa18aab764
- update actions 4 days ago
Simon G. 1d9bfa88f6
- start implementing factoryGenerator 5 days ago
Simon G. 543018a560
- add method to add generated factory 5 days ago
Simon G. 230a030b04
- add ctor to pass generated factory instance 5 days ago
Simon G. e7e347a477
- add samle classes 5 days ago
Simon G. 17bd0fad08
- can't include symbols for sourceGenerator 5 days ago
Simon G. ff33b25ef1
- add debug launch settings 5 days ago
Simon G. 13878b8b3f
- don't ignore all launchSettings 5 days ago
Simon G. 2bd3fbfbad
- add debug project 5 days ago
Simon G. e29a3ebdf8
- add readme to package 5 days ago
Simon G. a51be3b819
- update versions and readmes 5 days ago
Simon G. 50b188a7ff
- add generator project 5 days ago
Simon G. 578a021cf8
- update to .net 10 5 days ago
Simon G. 29a5d6fe92
- update copyright 5 days ago
  1. 12
      .github/workflows/ci.yml
  2. 6
      .github/workflows/deploy.yml
  3. 1
      .gitignore
  4. 16
      Debug.LightweightIocContainer.FactoryGenerator/Debug.LightweightIocContainer.FactoryGenerator.csproj
  5. 20
      Debug.LightweightIocContainer.FactoryGenerator/SampleInstaller.cs
  6. 21
      Debug.LightweightIocContainer.FactoryGenerator/Samples/Factories/ISampleClassFactory.cs
  7. 3
      Debug.LightweightIocContainer.FactoryGenerator/Samples/Interfaces/ISampleClass.cs
  8. 9
      Debug.LightweightIocContainer.FactoryGenerator/Samples/SampleClass.cs
  9. 2
      LICENSE.md
  10. 346
      LightweightIocContainer.FactoryGenerator/FactoryGenerator.cs
  11. 39
      LightweightIocContainer.FactoryGenerator/LightweightIocContainer.FactoryGenerator.csproj
  12. 9
      LightweightIocContainer.FactoryGenerator/Properties/launchSettings.json
  13. 23
      LightweightIocContainer.FactoryGenerator/README.md
  14. 76
      LightweightIocContainer.Validation/LightweightIocContainer.Validation.csproj
  15. 2
      LightweightIocContainer.Validation/README.md
  16. 18
      LightweightIocContainer.sln
  17. 8
      LightweightIocContainer/Factories/TypedFactory.cs
  18. 19
      LightweightIocContainer/Interfaces/Factories/IFactoryBuilder.cs
  19. 7
      LightweightIocContainer/Interfaces/Registrations/Fluent/IWithFactory.cs
  20. 64
      LightweightIocContainer/LightweightIocContainer.csproj
  21. 35
      LightweightIocContainer/LightweightIocContainer.xml
  22. 1
      LightweightIocContainer/Properties/AssemblyInfo.cs
  23. 13
      LightweightIocContainer/Registrations/RegistrationBase.cs
  24. 8
      README.md
  25. 60
      Test.LightweightIocContainer.FactoryGenerator/AsyncFactoryTest.cs
  26. 212
      Test.LightweightIocContainer.FactoryGenerator/FluentFactoryRegistrationTest.cs
  27. 40
      Test.LightweightIocContainer.FactoryGenerator/MultiLayerResolveTest.cs
  28. 41
      Test.LightweightIocContainer.FactoryGenerator/OpenGenericRegistrationTest.cs
  29. 33
      Test.LightweightIocContainer.FactoryGenerator/Test.LightweightIocContainer.FactoryGenerator.csproj
  30. 10
      Test.LightweightIocContainer.FactoryGenerator/TestClasses/A.cs
  31. 13
      Test.LightweightIocContainer.FactoryGenerator/TestClasses/AsyncMultitonTest.cs
  32. 14
      Test.LightweightIocContainer.FactoryGenerator/TestClasses/AsyncTest.cs
  33. 10
      Test.LightweightIocContainer.FactoryGenerator/TestClasses/B.cs
  34. 9
      Test.LightweightIocContainer.FactoryGenerator/TestClasses/C.cs
  35. 9
      Test.LightweightIocContainer.FactoryGenerator/TestClasses/Constraint.cs
  36. 11
      Test.LightweightIocContainer.FactoryGenerator/TestClasses/CtorGenericTest.cs
  37. 5
      Test.LightweightIocContainer.FactoryGenerator/TestClasses/DefaultTest.cs
  38. 8
      Test.LightweightIocContainer.FactoryGenerator/TestClasses/Factories/IAFactory.cs
  39. 8
      Test.LightweightIocContainer.FactoryGenerator/TestClasses/Factories/IAsyncMultitonTestFactory.cs
  40. 8
      Test.LightweightIocContainer.FactoryGenerator/TestClasses/Factories/IAsyncTestFactory.cs
  41. 9
      Test.LightweightIocContainer.FactoryGenerator/TestClasses/Factories/IBFactory.cs
  42. 8
      Test.LightweightIocContainer.FactoryGenerator/TestClasses/Factories/ICtorGenericTestFactory.cs
  43. 11
      Test.LightweightIocContainer.FactoryGenerator/TestClasses/Factories/IDefaultTestFactory.cs
  44. 8
      Test.LightweightIocContainer.FactoryGenerator/TestClasses/Factories/IGenericTestFactory.cs
  45. 9
      Test.LightweightIocContainer.FactoryGenerator/TestClasses/Factories/IInvalidMultitonTestFactory.cs
  46. 9
      Test.LightweightIocContainer.FactoryGenerator/TestClasses/Factories/IMultitonTestFactory.cs
  47. 8
      Test.LightweightIocContainer.FactoryGenerator/TestClasses/Factories/ITestDefaultFactory.cs
  48. 3
      Test.LightweightIocContainer.FactoryGenerator/TestClasses/Factories/ITestFactoryNoCreate.cs
  49. 6
      Test.LightweightIocContainer.FactoryGenerator/TestClasses/Factories/ITestFactoryWrongReturn.cs
  50. 8
      Test.LightweightIocContainer.FactoryGenerator/TestClasses/Factories/ITestNullFactory.cs
  51. 5
      Test.LightweightIocContainer.FactoryGenerator/TestClasses/GenericTest.cs
  52. 6
      Test.LightweightIocContainer.FactoryGenerator/TestClasses/Interfaces/IA.cs
  53. 7
      Test.LightweightIocContainer.FactoryGenerator/TestClasses/Interfaces/IAsyncTest.cs
  54. 6
      Test.LightweightIocContainer.FactoryGenerator/TestClasses/Interfaces/IB.cs
  55. 3
      Test.LightweightIocContainer.FactoryGenerator/TestClasses/Interfaces/IConstraint.cs
  56. 3
      Test.LightweightIocContainer.FactoryGenerator/TestClasses/Interfaces/IDefaultTest.cs
  57. 3
      Test.LightweightIocContainer.FactoryGenerator/TestClasses/Interfaces/IGenericTest.cs
  58. 3
      Test.LightweightIocContainer.FactoryGenerator/TestClasses/MultitonScope.cs
  59. 10
      Test.LightweightIocContainer.FactoryGenerator/TestClasses/TestByte.cs
  60. 16
      Test.LightweightIocContainer.FactoryGenerator/TestClasses/TestConstructor.cs
  61. 11
      Test.LightweightIocContainer.FactoryGenerator/TestClasses/TestMultiton.cs
  62. 23
      Test.LightweightIocContainer.FactoryGenerator/TestClasses/TestNull.cs
  63. 10
      Test.LightweightIocContainer.Validation/Test.LightweightIocContainer.Validation.csproj
  64. 10
      Test.LightweightIocContainer/Test.LightweightIocContainer.csproj

@ -9,10 +9,10 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v1 uses: actions/checkout@v5
- uses: actions/setup-dotnet@v1 - uses: actions/setup-dotnet@v5
with: with:
dotnet-version: '9.0.x' dotnet-version: '10.x'
- name: Build - name: Build
run: dotnet build run: dotnet build
@ -23,10 +23,10 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v1 uses: actions/checkout@v5
- uses: actions/setup-dotnet@v1 - uses: actions/setup-dotnet@v5
with: with:
dotnet-version: '9.0.x' dotnet-version: '10.x'
- name: Run tests - name: Run tests
run: dotnet test run: dotnet test

@ -11,10 +11,10 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v1 uses: actions/checkout@v5
- uses: actions/setup-dotnet@v1 - uses: actions/setup-dotnet@v5
with: with:
dotnet-version: '9.0.x' dotnet-version: '10.x'
- name: Build - name: Build
run: dotnet build -c Release -o output run: dotnet build -c Release -o output
- name: Deploy to nuGet gallery - name: Deploy to nuGet gallery

1
.gitignore vendored

@ -52,7 +52,6 @@ BenchmarkDotNet.Artifacts/
project.lock.json project.lock.json
project.fragment.lock.json project.fragment.lock.json
artifacts/ artifacts/
**/Properties/launchSettings.json
# StyleCop # StyleCop
StyleCopReport.xml StyleCopReport.xml

@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<LangVersion>preview</LangVersion>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\LightweightIocContainer\LightweightIocContainer.csproj" />
<ProjectReference Include="..\LightweightIocContainer.FactoryGenerator\LightweightIocContainer.FactoryGenerator.csproj"
OutputItemType="Analyzer"
ReferenceOutputAssembly="false"/>
</ItemGroup>
</Project>

@ -0,0 +1,20 @@
// Author: Simon.Gockner
// Created: 2025-12-01
// Copyright(c) 2025 SimonG. All Rights Reserved.
using Debug.LightweightIocContainer.FactoryGenerator.Samples;
using Debug.LightweightIocContainer.FactoryGenerator.Samples.Factories;
using Debug.LightweightIocContainer.FactoryGenerator.Samples.Interfaces;
using LightweightIocContainer.FactoryGenerator;
using LightweightIocContainer.Interfaces.Installers;
using LightweightIocContainer.Interfaces.Registrations;
namespace Debug.LightweightIocContainer.FactoryGenerator;
public class SampleInstaller : IIocInstaller
{
public void Install(IRegistrationCollector registration)
{
registration.Add<ISampleClass, SampleClass>().WithGeneratedFactory<ISampleClassFactory>();
}
}

@ -0,0 +1,21 @@
using Debug.LightweightIocContainer.FactoryGenerator.Samples.Interfaces;
namespace Debug.LightweightIocContainer.FactoryGenerator.Samples.Factories;
public interface ISampleClassFactory
{
ISampleClass Create();
T Create<T>() where T : ISampleClass;
Task<ISampleClass> CreateAsync();
ISampleClass Create(string name);
T Create<T, U, V>(U param1, V param2) where T : ISampleClass where U : class, new() where V : struct;
Task<T> CreateAsync<T, U>(U parameter) where T : ISampleClass where U : class;
ISampleClass Create<T>(Task<T> task) where T : Task<ISampleClass?>;
Task<T?> Create<T>(ISampleClass? sampleClass) where T : class, ISampleClass;
ISampleClass? Create(int id);
void ClearMultitonInstance<T>() where T : ISampleClass;
}

@ -0,0 +1,3 @@
namespace Debug.LightweightIocContainer.FactoryGenerator.Samples.Interfaces;
public interface ISampleClass;

@ -0,0 +1,9 @@
// Author: Simon.Gockner
// Created: 2025-12-01
// Copyright(c) 2025 SimonG. All Rights Reserved.
using Debug.LightweightIocContainer.FactoryGenerator.Samples.Interfaces;
namespace Debug.LightweightIocContainer.FactoryGenerator.Samples;
public class SampleClass : ISampleClass;

@ -1,6 +1,6 @@
MIT License MIT License
Copyright (c) 2019 Simon G. Copyright (c) 2025 Simon G.
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

@ -0,0 +1,346 @@
// Author: Simon.Gockner
// Created: 2025-12-01
// Copyright(c) 2025 SimonG. All Rights Reserved.
using System.Collections.Immutable;
using System.Text;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
namespace LightweightIocContainer.FactoryGenerator;
[Generator]
public class FactoryGenerator : IIncrementalGenerator
{
private const string EXTENSION_CLASS_NAME = "FactoryExtensions";
private const string BUILDER_CLASS_NAME = "FactoryBuilder";
private const string GENERATED_FILE_HEADER = "//---GENERATED by FactoryGenerator! DO NOT EDIT!---";
private const string INDENT = " ";
private const string CLEAR_MULTITON_INSTANCE_METHOD_NAME = "ClearMultitonInstance";
public void Initialize(IncrementalGeneratorInitializationContext context)
{
string? classNamespace = typeof(FactoryGenerator).Namespace;
context.RegisterPostInitializationOutput(c => c.AddSource($"{EXTENSION_CLASS_NAME}.g.cs", GenerateFactoryExtensionsClass(classNamespace, EXTENSION_CLASS_NAME)));
IncrementalValuesProvider<ITypeSymbol?> syntaxProvider = context.SyntaxProvider.CreateSyntaxProvider(IsCallToGenerateFactory, GetTypeArgument);
context.RegisterSourceOutput(syntaxProvider.Collect(), GenerateTypeDependentClasses);
context.RegisterSourceOutput(syntaxProvider.Collect(), GenerateFactory);
}
private string GenerateFactoryExtensionsClass(string? classNamespace, string className)
{
StringBuilder stringBuilder = new();
stringBuilder.AppendLine(GENERATED_FILE_HEADER);
stringBuilder.AppendLine();
stringBuilder.AppendLine("using LightweightIocContainer.Interfaces.Factories;");
stringBuilder.AppendLine("using LightweightIocContainer.Interfaces.Registrations;");
stringBuilder.AppendLine();
if (!string.IsNullOrEmpty(classNamespace))
{
stringBuilder.AppendLine($"namespace {classNamespace};");
stringBuilder.AppendLine();
}
stringBuilder.AppendLine($"public static class {className}");
stringBuilder.AppendLine("{");
stringBuilder.AppendLine($"{INDENT}public static IRegistrationBase WithGeneratedFactory<TFactory>(this IRegistrationBase registration)");
stringBuilder.AppendLine($"{INDENT}{{");
stringBuilder.AppendLine($"{INDENT}{INDENT}FactoryBuilder factoryBuilder = new();");
stringBuilder.AppendLine($"{INDENT}{INDENT}registration.AddGeneratedFactory<TFactory>(factoryBuilder);");
stringBuilder.AppendLine();
stringBuilder.AppendLine($"{INDENT}{INDENT}return registration;");
stringBuilder.AppendLine($"{INDENT}}}");
stringBuilder.AppendLine("}");
return stringBuilder.ToString();
}
private bool IsCallToGenerateFactory(SyntaxNode node, CancellationToken cancellationToken)
{
if (!node.IsKind(SyntaxKind.GenericName) || node is not GenericNameSyntax genericNameSyntax)
return false;
if (!genericNameSyntax.ToString().StartsWith("WithGeneratedFactory"))
return false;
if (genericNameSyntax.TypeArgumentList.Arguments[0] is not IdentifierNameSyntax)
return false;
return true;
}
private ITypeSymbol? GetTypeArgument(GeneratorSyntaxContext syntaxContext, CancellationToken cancellationToken)
{
if (syntaxContext.Node is not GenericNameSyntax genericNameSyntax)
return null;
if (genericNameSyntax.TypeArgumentList.Arguments[0] is not IdentifierNameSyntax identifierNameSyntax)
return null;
if (syntaxContext.SemanticModel.GetSymbolInfo(identifierNameSyntax).Symbol is not ITypeSymbol typeSymbol)
return null;
return typeSymbol;
}
private void GenerateTypeDependentClasses(SourceProductionContext context, ImmutableArray<ITypeSymbol?> types)
{
string? classNamespace = typeof(FactoryGenerator).Namespace;
context.AddSource($"{BUILDER_CLASS_NAME}.g.cs", GenerateBuilderClassSourceCode(classNamespace, types));
}
private void GenerateFactory(SourceProductionContext context, ImmutableArray<ITypeSymbol?> types)
{
foreach (ISymbol? symbol in types.Distinct(SymbolEqualityComparer.IncludeNullability))
{
if (symbol is not ITypeSymbol typeSymbol)
continue;
context.AddSource($"Generated{typeSymbol.Name}.g.cs", GenerateFactorySourceCode(typeSymbol));
}
}
private string GenerateBuilderClassSourceCode(string? classNamespace, ImmutableArray<ITypeSymbol?> types)
{
StringBuilder stringBuilder = new();
stringBuilder.AppendLine(GENERATED_FILE_HEADER);
stringBuilder.AppendLine();
stringBuilder.AppendLine("using LightweightIocContainer.Interfaces.Factories;");
foreach (string typeNamespace in GetNamespacesOfTypes(types))
stringBuilder.AppendLine($"using {typeNamespace};");
stringBuilder.AppendLine();
if (classNamespace is not null)
{
stringBuilder.AppendLine($"namespace {classNamespace};");
stringBuilder.AppendLine();
}
stringBuilder.AppendLine("public class FactoryBuilder : IFactoryBuilder");
stringBuilder.AppendLine("{");
stringBuilder.AppendLine($"{INDENT}public TFactory Create<TFactory>(IocContainer container)");
stringBuilder.AppendLine($"{INDENT}{{");
foreach (ISymbol? symbol in types.Distinct(SymbolEqualityComparer.IncludeNullability))
{
if (symbol is not ITypeSymbol type)
continue;
stringBuilder.AppendLine($"{INDENT}{INDENT}if (typeof(TFactory) == typeof({type.Name}))");
stringBuilder.AppendLine($"{INDENT}{INDENT}{{");
stringBuilder.AppendLine($"{INDENT}{INDENT}{INDENT}return (TFactory) (object) new Generated{type.Name}(container);");
stringBuilder.AppendLine($"{INDENT}{INDENT}}}");
stringBuilder.AppendLine();
}
stringBuilder.AppendLine($"{INDENT}{INDENT}throw new Exception(\"Invalid type.\");");
stringBuilder.AppendLine($"{INDENT}}}");
stringBuilder.AppendLine("}");
return stringBuilder.ToString();
}
private string GenerateFactorySourceCode(ITypeSymbol typeSymbol)
{
string typeName = typeSymbol.Name;
string? typeNamespace = typeSymbol.ContainingNamespace.IsGlobalNamespace ? null : typeSymbol.ContainingNamespace.ToString();
StringBuilder stringBuilder = new();
stringBuilder.AppendLine(GENERATED_FILE_HEADER);
stringBuilder.AppendLine();
stringBuilder.AppendLine("#nullable enable");
stringBuilder.AppendLine();
stringBuilder.AppendLine("using LightweightIocContainer;");
ImmutableArray<ISymbol> members = typeSymbol.GetMembers();
List<string?> namespaces = [];
foreach (ISymbol? member in members)
{
if (member is not IMethodSymbol method)
continue;
if (!method.ReturnsVoid)
{
if (method.ReturnType is INamedTypeSymbol { IsGenericType: true } namedTypeSymbol)
{
namespaces.AddRange(namedTypeSymbol.TypeArguments.Select(GetNamespaceOfType));
if (method.ReturnType.Name != "Task")
namespaces.Add(GetNamespaceOfType(method.ReturnType));
}
else
namespaces.Add(GetNamespaceOfType(method.ReturnType));
}
namespaces.AddRange(method.Parameters.Select(p => GetNamespaceOfType(p.Type)));
}
foreach (string @namespace in namespaces.Distinct().OfType<string>().OrderBy(n => n))
stringBuilder.AppendLine($"using {@namespace};");
stringBuilder.AppendLine();
if (typeNamespace is not null)
{
stringBuilder.AppendLine($"namespace {typeNamespace};");
stringBuilder.AppendLine();
}
stringBuilder.AppendLine($"public class Generated{typeName}(IocContainer container) : {typeName}");
stringBuilder.AppendLine("{");
foreach (ISymbol? member in members)
{
if (member is not IMethodSymbol method)
continue;
if (!method.ReturnsVoid) //create method
{
stringBuilder.Append($"{INDENT}public {GetTypeText(method.ReturnType)} {method.Name}");
if (method.IsGenericMethod)
stringBuilder.Append(GetGenericParameters(method));
stringBuilder.Append($"({string.Join(", ", method.Parameters.Select(GetParameterText))})");
if (method.IsGenericMethod)
stringBuilder.Append(GetParameterConstraintsText(method));
stringBuilder.AppendLine();
stringBuilder.AppendLine($"{INDENT}{{");
foreach (IParameterSymbol parameter in method.Parameters)
{
stringBuilder.AppendLine($"{INDENT}{INDENT}object? {parameter.Name}Value = {parameter.Name};");
stringBuilder.AppendLine($"{INDENT}{INDENT}if ({parameter.Name}Value is null)");
stringBuilder.AppendLine($"{INDENT}{INDENT}{INDENT}{parameter.Name}Value = new NullParameter(typeof({GetTypeText(parameter.Type, false)}));");
stringBuilder.AppendLine();
}
//don't use getTypeText here, because we need the raw type name for Task<>
if (method.ReturnType is INamedTypeSymbol { IsGenericType: true } namedTypeSymbol)
{
if (method.ReturnType.Name == "Task")
stringBuilder.Append($"{INDENT}{INDENT}return container.FactoryResolveAsync{GetGenericArguments(namedTypeSymbol)}(");
else
stringBuilder.Append($"{INDENT}{INDENT}return container.FactoryResolve<{method.ReturnType.Name}{GetGenericArguments(namedTypeSymbol)}>(");
}
else
stringBuilder.Append($"{INDENT}{INDENT}return container.FactoryResolve<{method.ReturnType.Name}>(");
stringBuilder.Append(string.Join(", ", method.Parameters.Select(p => $"{p.Name}Value")));
stringBuilder.AppendLine(");");
stringBuilder.AppendLine($"{INDENT}}}");
}
else if (method is { Name: CLEAR_MULTITON_INSTANCE_METHOD_NAME, IsGenericMethod: true })
{
stringBuilder.Append($"{INDENT}public void {method.Name}{GetGenericParameters(method)}()");
stringBuilder.Append(GetParameterConstraintsText(method));
stringBuilder.AppendLine($" => container.ClearMultitonInstances{GetGenericArguments(method)}();");
}
if (members.IndexOf(member) < members.Length - 1) //only append empty line if not the last member
stringBuilder.AppendLine();
}
stringBuilder.AppendLine("}");
return stringBuilder.ToString();
}
private string? GetNamespaceOfType(ITypeSymbol s) => s.ContainingNamespace.IsGlobalNamespace ? null : s.ContainingNamespace.ToString();
private IEnumerable<string> GetNamespacesOfTypes(ImmutableArray<ITypeSymbol?> types) =>
types.OfType<ITypeSymbol>()
.Select(GetNamespaceOfType)
.OfType<string>()
.Distinct();
private string GetTypeText(ITypeSymbol typeSymbol) => GetTypeText(typeSymbol, true);
private string GetTypeText(ITypeSymbol typeSymbol, bool allowNullable)
{
StringBuilder stringBuilder = new();
stringBuilder.Append(typeSymbol.Name);
if (typeSymbol is INamedTypeSymbol { IsGenericType: true } namedTypeSymbol)
stringBuilder.Append(GetGenericArguments(namedTypeSymbol));
if (allowNullable && typeSymbol.NullableAnnotation == NullableAnnotation.Annotated)
stringBuilder.Append("?");
return stringBuilder.ToString();
}
private string GetParameterText(IParameterSymbol parameter) => $"{GetTypeText(parameter.Type)} {parameter.Name}";
private string GetGenericArguments(INamedTypeSymbol namedTypeSymbol) => GetGenericArguments(namedTypeSymbol.TypeArguments);
private string GetGenericArguments(IMethodSymbol methodSymbol) => GetGenericArguments(methodSymbol.TypeArguments);
private string GetGenericArguments(ImmutableArray<ITypeSymbol> typeArguments) => $"<{string.Join(", ", typeArguments.Select(GetTypeText))}>";
private string GetGenericParameters(IMethodSymbol methodSymbol) => GetGenericParameters(methodSymbol.TypeParameters);
private string GetGenericParameters(ImmutableArray<ITypeParameterSymbol> typeParameters) => $"<{string.Join(", ", typeParameters.Select(GetTypeText))}>";
private string GetParameterConstraintsText(IMethodSymbol method)
{
StringBuilder stringBuilder = new();
foreach (ITypeParameterSymbol typeParameter in method.TypeParameters)
{
List<string> parameterConstraints = GetParameterConstraints(typeParameter);
if (parameterConstraints.Count == 0)
continue;
stringBuilder.Append($" where {typeParameter.Name} : {string.Join(", ", parameterConstraints)}");
}
return stringBuilder.ToString();
}
private List<string> GetParameterConstraints(ITypeParameterSymbol typeParameterSymbol)
{
List<string> constraints = [];
if (typeParameterSymbol.HasReferenceTypeConstraint)
constraints.Add("class");
if (typeParameterSymbol.HasValueTypeConstraint)
constraints.Add("struct");
if (typeParameterSymbol.HasUnmanagedTypeConstraint)
constraints.Add("unmanaged");
if (typeParameterSymbol.HasNotNullConstraint)
constraints.Add("notnull");
foreach (ITypeSymbol constraintType in typeParameterSymbol.ConstraintTypes)
{
if (constraintType is INamedTypeSymbol { IsGenericType: true } namedTypeSymbol)
constraints.Add($"{constraintType.Name}{GetGenericArguments(namedTypeSymbol)}");
else
constraints.Add(constraintType.Name);
}
if (typeParameterSymbol.HasConstructorConstraint)
constraints.Add("new()");
return constraints;
}
}

@ -0,0 +1,39 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<Authors>SimonG</Authors>
<Copyright>Copyright(c) 2025 SimonG. All Rights Reserved.</Copyright>
<Description>Incremental generator to generate factories</Description>
<RepositoryUrl>https://github.com/SimonG96/LightweightIocContainer</RepositoryUrl>
<LangVersion>preview</LangVersion>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules>
<IsRoslynComponent>true</IsRoslynComponent>
<VersionPrefix>5.0.0</VersionPrefix>
<VersionSuffix>beta</VersionSuffix>
</PropertyGroup>
<PropertyGroup>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<IncludeBuildOutput>false</IncludeBuildOutput>
<SuppressDependenciesWhenPacking>true</SuppressDependenciesWhenPacking>
<PackageProjectUrl>https://github.com/SimonG96/LightweightIocContainer</PackageProjectUrl>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageReadmeFile>README.md</PackageReadmeFile>
</PropertyGroup>
<ItemGroup>
<Content Include="README.md" Pack="true" PackagePath="" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="5.0.0" PrivateAssets="all" Pack="false" />
</ItemGroup>
<ItemGroup>
<!-- Package the generator in the analyzer directory of the nuget package -->
<None Include="$(OutputPath)\$(AssemblyName).dll" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false" />
</ItemGroup>
</Project>

@ -0,0 +1,9 @@
{
"$schema": "http://json.schemastore.org/launchsettings.json",
"profiles": {
"DebugRoslynSourceGenerator": {
"commandName": "DebugRoslynComponent",
"targetProject": "../Debug.LightweightIocContainer.FactoryGenerator/Debug.LightweightIocContainer.FactoryGenerator.csproj"
}
}
}

@ -0,0 +1,23 @@
## Get started with the Lightweight IOC Container Factory Generator
### How to install
The easiest way to [install](https://github.com/SimonG96/LghtweightIocContainer/wiki/Install-Lightweight-IOC-Container) the Lightweight IOC Container is by using [NuGet](https://www.nuget.org/packages/LightweightIocContainer.FactoryGenerator/) through the [`.NET CLI`](https://github.com/SimonG96/LightweightIocContainer/wiki/Install-Lightweight-IOC-Container#net-cli):
```.net
> dotnet add package LightweightIocContainer.FactoryGenerator --version 5.0.0
```
### Example usage
When registering an interface you can use the `WithGeneratedFactory<>()` method to generate a factory for the registered type:
```c#
public class SampleInstaller : IIocInstaller
{
public void Install(IRegistrationCollector registration)
{
registration.Add<ISampleClass, SampleClass>().WithGeneratedFactory<ISampleClassFactory>();
}
}
```

@ -1,45 +1,45 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net10.0</TargetFramework>
<Authors>SimonG</Authors> <Authors>SimonG</Authors>
<Copyright>Copyright(c) 2024 SimonG. All Rights Reserved.</Copyright> <Copyright>Copyright(c) 2025 SimonG. All Rights Reserved.</Copyright>
<Description>A lightweight IOC Container Validator.</Description> <Description>A lightweight IOC Container Validator.</Description>
<RepositoryUrl>https://github.com/SimonG96/LightweightIocContainer</RepositoryUrl> <RepositoryUrl>https://github.com/SimonG96/LightweightIocContainer</RepositoryUrl>
<LangVersion>latest</LangVersion> <LangVersion>latest</LangVersion>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<DocumentationFile>LightweightIocContainer.Validation.xml</DocumentationFile> <DocumentationFile>LightweightIocContainer.Validation.xml</DocumentationFile>
<VersionPrefix>4.4.0</VersionPrefix> <VersionPrefix>5.0.0</VersionPrefix>
</PropertyGroup> <VersionSuffix>beta</VersionSuffix>
</PropertyGroup>
<PropertyGroup> <PropertyGroup>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild> <GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<PackageProjectUrl>https://github.com/SimonG96/LightweightIocContainer</PackageProjectUrl> <PackageProjectUrl>https://github.com/SimonG96/LightweightIocContainer</PackageProjectUrl>
<PackageLicenseExpression>MIT</PackageLicenseExpression> <PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageReadmeFile>README.md</PackageReadmeFile> <PackageReadmeFile>README.md</PackageReadmeFile>
<IncludeSymbols>true</IncludeSymbols> <IncludeSymbols>true</IncludeSymbols>
<SymbolPackageFormat>snupkg</SymbolPackageFormat> <SymbolPackageFormat>snupkg</SymbolPackageFormat>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0"> <PackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
<PackageReference Include="NSubstitute" Version="5.3.0" /> <PackageReference Include="NSubstitute" Version="5.3.0" />
<PackageReference Include="System.Reflection.Emit" Version="4.7.0" /> </ItemGroup>
</ItemGroup>
<ItemGroup> <ItemGroup>
<Content Include="README.md" Pack="true" PackagePath="" /> <Content Include="README.md" Pack="true" PackagePath="" />
</ItemGroup> </ItemGroup>
<ItemGroup Condition="Exists('..\LightweightIocContainer\LightweightIocContainer.csproj')"> <ItemGroup Condition="Exists('..\LightweightIocContainer\LightweightIocContainer.csproj')">
<ProjectReference Include="..\LightweightIocContainer\LightweightIocContainer.csproj" /> <ProjectReference Include="..\LightweightIocContainer\LightweightIocContainer.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup Condition="!Exists('..\LightweightIocContainer\LightweightIocContainer.csproj')"> <ItemGroup Condition="!Exists('..\LightweightIocContainer\LightweightIocContainer.csproj')">
<PackageReference Include="LightweightIocContainer" Version="$(Version)" /> <PackageReference Include="LightweightIocContainer" Version="$(Version)" />
</ItemGroup> </ItemGroup>
</Project> </Project>

@ -5,7 +5,7 @@
The easiest way to [install](https://github.com/SimonG96/LghtweightIocContainer/wiki/Install-Lightweight-IOC-Container) the Lightweight IOC Container is by using [NuGet](https://www.nuget.org/packages/LightweightIocContainer.Validation/) through the [`.NET CLI`](https://github.com/SimonG96/LightweightIocContainer/wiki/Install-Lightweight-IOC-Container#net-cli): The easiest way to [install](https://github.com/SimonG96/LghtweightIocContainer/wiki/Install-Lightweight-IOC-Container) the Lightweight IOC Container is by using [NuGet](https://www.nuget.org/packages/LightweightIocContainer.Validation/) through the [`.NET CLI`](https://github.com/SimonG96/LightweightIocContainer/wiki/Install-Lightweight-IOC-Container#net-cli):
```.net ```.net
> dotnet add package LightweightIocContainer.Validaton --version 4.4.0-beta2 > dotnet add package LightweightIocContainer.Validation --version 5.0.0
``` ```
### Validation ### Validation

@ -11,6 +11,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LightweightIocContainer.Val
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Test.LightweightIocContainer.Validation", "Test.LightweightIocContainer.Validation\Test.LightweightIocContainer.Validation.csproj", "{82818CE7-6219-4A2E-A506-3AE09A00578C}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Test.LightweightIocContainer.Validation", "Test.LightweightIocContainer.Validation\Test.LightweightIocContainer.Validation.csproj", "{82818CE7-6219-4A2E-A506-3AE09A00578C}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LightweightIocContainer.FactoryGenerator", "LightweightIocContainer.FactoryGenerator\LightweightIocContainer.FactoryGenerator.csproj", "{3AAB43AC-1CBA-4A81-81CB-1EAC2AB792E3}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Debug.LightweightIocContainer.FactoryGenerator", "Debug.LightweightIocContainer.FactoryGenerator\Debug.LightweightIocContainer.FactoryGenerator.csproj", "{578ED8B2-A2BE-4E10-9422-4D5AF2E605E0}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Test.LightweightIocContainer.FactoryGenerator", "Test.LightweightIocContainer.FactoryGenerator\Test.LightweightIocContainer.FactoryGenerator.csproj", "{0CB46F2E-5429-40BB-9F9F-31606B212E81}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
@ -33,6 +39,18 @@ Global
{82818CE7-6219-4A2E-A506-3AE09A00578C}.Debug|Any CPU.Build.0 = Debug|Any CPU {82818CE7-6219-4A2E-A506-3AE09A00578C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{82818CE7-6219-4A2E-A506-3AE09A00578C}.Release|Any CPU.ActiveCfg = Release|Any CPU {82818CE7-6219-4A2E-A506-3AE09A00578C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{82818CE7-6219-4A2E-A506-3AE09A00578C}.Release|Any CPU.Build.0 = Release|Any CPU {82818CE7-6219-4A2E-A506-3AE09A00578C}.Release|Any CPU.Build.0 = Release|Any CPU
{3AAB43AC-1CBA-4A81-81CB-1EAC2AB792E3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3AAB43AC-1CBA-4A81-81CB-1EAC2AB792E3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3AAB43AC-1CBA-4A81-81CB-1EAC2AB792E3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3AAB43AC-1CBA-4A81-81CB-1EAC2AB792E3}.Release|Any CPU.Build.0 = Release|Any CPU
{578ED8B2-A2BE-4E10-9422-4D5AF2E605E0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{578ED8B2-A2BE-4E10-9422-4D5AF2E605E0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{578ED8B2-A2BE-4E10-9422-4D5AF2E605E0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{578ED8B2-A2BE-4E10-9422-4D5AF2E605E0}.Release|Any CPU.Build.0 = Release|Any CPU
{0CB46F2E-5429-40BB-9F9F-31606B212E81}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0CB46F2E-5429-40BB-9F9F-31606B212E81}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0CB46F2E-5429-40BB-9F9F-31606B212E81}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0CB46F2E-5429-40BB-9F9F-31606B212E81}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE

@ -19,10 +19,16 @@ public class TypedFactory<TFactory> : TypedFactoryBase<TFactory>, ITypedFactory<
private const string CLEAR_MULTITON_INSTANCE_METHOD_NAME = "ClearMultitonInstance"; private const string CLEAR_MULTITON_INSTANCE_METHOD_NAME = "ClearMultitonInstance";
/// <summary> /// <summary>
/// The /// Constructor for creating factories dynamically
/// </summary> /// </summary>
/// <param name="container">The current instance of the <see cref="IIocContainer"/></param> /// <param name="container">The current instance of the <see cref="IIocContainer"/></param>
public TypedFactory(IocContainer container) => Factory = CreateFactory(container); public TypedFactory(IocContainer container) => Factory = CreateFactory(container);
/// <summary>
/// Constructor for generated factories
/// </summary>
/// <param name="factory">The generated factory instance</param>
public TypedFactory(TFactory factory) => Factory = factory;
/// <summary> /// <summary>
/// The implemented abstract typed factory/> /// The implemented abstract typed factory/>

@ -0,0 +1,19 @@
// Author: Simon.Gockner
// Created: 2025-12-02
// Copyright(c) 2025 SimonG. All Rights Reserved.
namespace LightweightIocContainer.Interfaces.Factories;
/// <summary>
/// Internal class used by the factory source generator to create factory instances
/// </summary>
public interface IFactoryBuilder
{
/// <summary>
/// Internal method used by the factory source generator to create factory instances
/// </summary>
/// <param name="container">The current instance of the <see cref="IocContainer"/></param>
/// <typeparam name="TFactory">The type of the factory</typeparam>
/// <returns>The created factory instance</returns>
TFactory Create<TFactory>(IocContainer container);
}

@ -25,6 +25,13 @@ public interface IWithFactory
/// <typeparam name="TFactoryImplementation">The type of the implementation for the custom factory</typeparam> /// <typeparam name="TFactoryImplementation">The type of the implementation for the custom factory</typeparam>
/// <returns>The current instance of this <see cref="IRegistrationBase"/></returns> /// <returns>The current instance of this <see cref="IRegistrationBase"/></returns>
IRegistrationBase WithFactory<TFactoryInterface, TFactoryImplementation>() where TFactoryImplementation : TFactoryInterface; IRegistrationBase WithFactory<TFactoryInterface, TFactoryImplementation>() where TFactoryImplementation : TFactoryInterface;
/// <summary>
/// Internal method used by the factory source generator to add the generated factory to the registration
/// </summary>
/// <param name="factoryBuilder">The factory creator</param>
/// <typeparam name="TFactory">The type of the generated factory</typeparam>
void AddGeneratedFactory<TFactory>(IFactoryBuilder factoryBuilder);
} }
internal interface IWithFactoryInternal : IWithFactory internal interface IWithFactoryInternal : IWithFactory

@ -1,38 +1,38 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net10.0</TargetFramework>
<Authors>SimonG</Authors> <Authors>SimonG</Authors>
<Copyright>Copyright(c) 2024 SimonG. All Rights Reserved.</Copyright> <Copyright>Copyright(c) 2025 SimonG. All Rights Reserved.</Copyright>
<Description>A lightweight IOC Container that is powerful enough to do all the things you need it to do.</Description> <Description>A lightweight IOC Container that is powerful enough to do all the things you need it to do.</Description>
<RepositoryUrl>https://github.com/SimonG96/LightweightIocContainer</RepositoryUrl> <RepositoryUrl>https://github.com/SimonG96/LightweightIocContainer</RepositoryUrl>
<LangVersion>latest</LangVersion> <LangVersion>latest</LangVersion>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<DocumentationFile>LightweightIocContainer.xml</DocumentationFile> <DocumentationFile>LightweightIocContainer.xml</DocumentationFile>
<VersionPrefix>4.4.0</VersionPrefix> <VersionPrefix>5.0.0</VersionPrefix>
</PropertyGroup> <VersionSuffix>beta</VersionSuffix>
</PropertyGroup>
<PropertyGroup> <PropertyGroup>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild> <GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<PackageProjectUrl>https://github.com/SimonG96/LightweightIocContainer</PackageProjectUrl> <PackageProjectUrl>https://github.com/SimonG96/LightweightIocContainer</PackageProjectUrl>
<PackageLicenseFile>LICENSE.md</PackageLicenseFile> <PackageLicenseFile>LICENSE.md</PackageLicenseFile>
<PackageReadmeFile>README.md</PackageReadmeFile> <PackageReadmeFile>README.md</PackageReadmeFile>
<IncludeSymbols>true</IncludeSymbols> <IncludeSymbols>true</IncludeSymbols>
<SymbolPackageFormat>snupkg</SymbolPackageFormat> <SymbolPackageFormat>snupkg</SymbolPackageFormat>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0"> <PackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
<PackageReference Include="System.Reflection.Emit" Version="4.7.0" /> </ItemGroup>
</ItemGroup>
<ItemGroup> <ItemGroup>
<Content Include="..\README.md" Pack="true" PackagePath="" /> <Content Include="..\README.md" Pack="true" PackagePath="" />
<Content Include="..\LICENSE.md" Pack="true" PackagePath="" /> <Content Include="..\LICENSE.md" Pack="true" PackagePath="" />
</ItemGroup> </ItemGroup>
</Project> </Project>

@ -384,10 +384,16 @@
</member> </member>
<member name="M:LightweightIocContainer.Factories.TypedFactory`1.#ctor(LightweightIocContainer.IocContainer)"> <member name="M:LightweightIocContainer.Factories.TypedFactory`1.#ctor(LightweightIocContainer.IocContainer)">
<summary> <summary>
The Constructor for creating factories dynamically
</summary> </summary>
<param name="container">The current instance of the <see cref="T:LightweightIocContainer.Interfaces.IIocContainer"/></param> <param name="container">The current instance of the <see cref="T:LightweightIocContainer.Interfaces.IIocContainer"/></param>
</member> </member>
<member name="M:LightweightIocContainer.Factories.TypedFactory`1.#ctor(`0)">
<summary>
Constructor for generated factories
</summary>
<param name="factory">The generated factory instance</param>
</member>
<member name="P:LightweightIocContainer.Factories.TypedFactory`1.Factory"> <member name="P:LightweightIocContainer.Factories.TypedFactory`1.Factory">
<summary> <summary>
The implemented abstract typed factory/> The implemented abstract typed factory/>
@ -480,6 +486,19 @@
<param name="assembly">The given <see cref="T:System.Reflection.Assembly"/></param> <param name="assembly">The given <see cref="T:System.Reflection.Assembly"/></param>
<returns>A new <see cref="T:LightweightIocContainer.Interfaces.Installers.IAssemblyInstaller"/> with the given <see cref="T:System.Reflection.Assembly"/></returns> <returns>A new <see cref="T:LightweightIocContainer.Interfaces.Installers.IAssemblyInstaller"/> with the given <see cref="T:System.Reflection.Assembly"/></returns>
</member> </member>
<member name="T:LightweightIocContainer.Interfaces.Factories.IFactoryBuilder">
<summary>
Internal class used by the factory source generator to create factory instances
</summary>
</member>
<member name="M:LightweightIocContainer.Interfaces.Factories.IFactoryBuilder.Create``1(LightweightIocContainer.IocContainer)">
<summary>
Internal method used by the factory source generator to create factory instances
</summary>
<param name="container">The current instance of the <see cref="T:LightweightIocContainer.IocContainer"/></param>
<typeparam name="TFactory">The type of the factory</typeparam>
<returns>The created factory instance</returns>
</member>
<member name="T:LightweightIocContainer.Interfaces.Factories.ITypedFactory"> <member name="T:LightweightIocContainer.Interfaces.Factories.ITypedFactory">
<summary> <summary>
Non-generic <see cref="T:LightweightIocContainer.Interfaces.Factories.ITypedFactory`1"/> Non-generic <see cref="T:LightweightIocContainer.Interfaces.Factories.ITypedFactory`1"/>
@ -664,6 +683,13 @@
<typeparam name="TFactoryImplementation">The type of the implementation for the custom factory</typeparam> <typeparam name="TFactoryImplementation">The type of the implementation for the custom factory</typeparam>
<returns>The current instance of this <see cref="T:LightweightIocContainer.Interfaces.Registrations.IRegistrationBase"/></returns> <returns>The current instance of this <see cref="T:LightweightIocContainer.Interfaces.Registrations.IRegistrationBase"/></returns>
</member> </member>
<member name="M:LightweightIocContainer.Interfaces.Registrations.Fluent.IWithFactory.AddGeneratedFactory``1(LightweightIocContainer.Interfaces.Factories.IFactoryBuilder)">
<summary>
Internal method used by the factory source generator to add the generated factory to the registration
</summary>
<param name="factoryBuilder">The factory creator</param>
<typeparam name="TFactory">The type of the generated factory</typeparam>
</member>
<member name="P:LightweightIocContainer.Interfaces.Registrations.Fluent.IWithFactoryInternal.Factory"> <member name="P:LightweightIocContainer.Interfaces.Registrations.Fluent.IWithFactoryInternal.Factory">
<summary> <summary>
The Factory added with the <see cref="M:LightweightIocContainer.Interfaces.Registrations.Fluent.IWithFactory.WithFactory``1"/> method The Factory added with the <see cref="M:LightweightIocContainer.Interfaces.Registrations.Fluent.IWithFactory.WithFactory``1"/> method
@ -1595,6 +1621,13 @@
<typeparam name="TFactory">The type of the abstract typed factory</typeparam> <typeparam name="TFactory">The type of the abstract typed factory</typeparam>
<returns>The current instance of this <see cref="T:LightweightIocContainer.Interfaces.Registrations.IRegistrationBase"/></returns> <returns>The current instance of this <see cref="T:LightweightIocContainer.Interfaces.Registrations.IRegistrationBase"/></returns>
</member> </member>
<member name="M:LightweightIocContainer.Registrations.RegistrationBase.AddGeneratedFactory``1(LightweightIocContainer.Interfaces.Factories.IFactoryBuilder)">
<summary>
Internal method used by the factory source generator to add the generated factory to the registration
</summary>
<param name="factoryBuilder">The factory creator</param>
<typeparam name="TFactory">The type of the generated factory</typeparam>
</member>
<member name="M:LightweightIocContainer.Registrations.RegistrationBase.WithFactory``2"> <member name="M:LightweightIocContainer.Registrations.RegistrationBase.WithFactory``2">
<summary> <summary>
Register a custom implemented factory for the <see cref="T:LightweightIocContainer.Interfaces.Registrations.IRegistrationBase"/> Register a custom implemented factory for the <see cref="T:LightweightIocContainer.Interfaces.Registrations.IRegistrationBase"/>

@ -7,4 +7,5 @@ using System.Runtime.CompilerServices;
[assembly:InternalsVisibleTo("LightweightIocContainer.Validation")] [assembly:InternalsVisibleTo("LightweightIocContainer.Validation")]
[assembly:InternalsVisibleTo("Test.LightweightIocContainer")] [assembly:InternalsVisibleTo("Test.LightweightIocContainer")]
[assembly:InternalsVisibleTo("Test.LightweightIocContainer.FactoryGenerator")]
[assembly:InternalsVisibleTo("Test.LightweightIocContainer.Validation")] [assembly:InternalsVisibleTo("Test.LightweightIocContainer.Validation")]

@ -121,6 +121,19 @@ internal abstract class RegistrationBase : IRegistrationBase, IWithFactoryIntern
return this; return this;
} }
/// <summary>
/// Internal method used by the factory source generator to add the generated factory to the registration
/// </summary>
/// <param name="factoryBuilder">The factory creator</param>
/// <typeparam name="TFactory">The type of the generated factory</typeparam>
public void AddGeneratedFactory<TFactory>(IFactoryBuilder factoryBuilder)
{
TypedFactory<TFactory> factory = new(factoryBuilder.Create<TFactory>(_container));
Factory = factory;
_container.RegisterFactory(factory);
}
/// <summary> /// <summary>
/// Register a custom implemented factory for the <see cref="IRegistrationBase"/> /// Register a custom implemented factory for the <see cref="IRegistrationBase"/>
/// </summary> /// </summary>

@ -12,6 +12,10 @@ A lightweight IOC Container that is powerful enough to do all the things you nee
[![Nuget](https://img.shields.io/nuget/v/LightweightIocContainer.Validation.svg?label=Validation%20NuGet%20Version&logo=NuGet)](https://www.nuget.org/packages/LightweightIocContainer.Validation/) [![Nuget](https://img.shields.io/nuget/v/LightweightIocContainer.Validation.svg?label=Validation%20NuGet%20Version&logo=NuGet)](https://www.nuget.org/packages/LightweightIocContainer.Validation/)
[![Nuget (with prereleases)](https://img.shields.io/nuget/vpre/LightweightIocContainer.Validation.svg?label=Validation%20NuGet%20Pre-Release&logo=NuGet)](https://www.nuget.org/packages/LightweightIocContainer.Validation/) [![Nuget (with prereleases)](https://img.shields.io/nuget/vpre/LightweightIocContainer.Validation.svg?label=Validation%20NuGet%20Pre-Release&logo=NuGet)](https://www.nuget.org/packages/LightweightIocContainer.Validation/)
[![Nuget](https://img.shields.io/nuget/dt/LightweightIocContainer.FactoryGenerator.svg?label=FactoryGenerator%20NuGet%20Downloads&logo=NuGet)](https://www.nuget.org/packages/LightweightIocContainer.FactoryGenerator/)
[![Nuget](https://img.shields.io/nuget/v/LightweightIocContainer.FactoryGenerator.svg?label=FactoryGenerator%20NuGet%20Version&logo=NuGet)](https://www.nuget.org/packages/LightweightIocContainer.FactoryGenerator/)
[![Nuget (with prereleases)](https://img.shields.io/nuget/vpre/LightweightIocContainer.FactoryGenerator.svg?label=FactoryGenerator%20NuGet%20Pre-Release&logo=NuGet)](https://www.nuget.org/packages/LightweightIocContainer.FactoryGenerator/)
## Get started with the Lightweight IOC Container ## Get started with the Lightweight IOC Container
### How to install ### How to install
@ -19,7 +23,7 @@ A lightweight IOC Container that is powerful enough to do all the things you nee
The easiest way to [install](https://github.com/SimonG96/LightweightIocContainer/wiki/Install-Lightweight-IOC-Container) the Lightweight IOC Container is by using [NuGet](https://www.nuget.org/packages/LightweightIocContainer/) through the [`.NET CLI`](https://github.com/SimonG96/LightweightIocContainer/wiki/Install-Lightweight-IOC-Container#net-cli): The easiest way to [install](https://github.com/SimonG96/LightweightIocContainer/wiki/Install-Lightweight-IOC-Container) the Lightweight IOC Container is by using [NuGet](https://www.nuget.org/packages/LightweightIocContainer/) through the [`.NET CLI`](https://github.com/SimonG96/LightweightIocContainer/wiki/Install-Lightweight-IOC-Container#net-cli):
```.net ```.net
> dotnet add package LightweightIocContainer --version 4.4.0 > dotnet add package LightweightIocContainer --version 5.0.0
``` ```
### Example usage ### Example usage
@ -59,7 +63,7 @@ The easiest way to [install](https://github.com/SimonG96/LightweightIocContainer
There is the option to install the [LightweightIocContainer.Validation](https://www.nuget.org/packages/LightweightIocContainer.Validation/) package: There is the option to install the [LightweightIocContainer.Validation](https://www.nuget.org/packages/LightweightIocContainer.Validation/) package:
```.net ```.net
> dotnet add package LightweightIocContainer.Validaton --version 4.4.0 > dotnet add package LightweightIocContainer.Validation --version 5.0.0
``` ```
With this you can validate your `IocContainer` setup by using the `IocValidator` in a unit test: With this you can validate your `IocContainer` setup by using the `IocValidator` in a unit test:

@ -0,0 +1,60 @@
// Author: Simon.Gockner
// Created: 2025-12-03
// Copyright(c) 2025 SimonG. All Rights Reserved.
using LightweightIocContainer;
using LightweightIocContainer.FactoryGenerator;
using Test.LightweightIocContainer.FactoryGenerator.TestClasses;
using Test.LightweightIocContainer.FactoryGenerator.TestClasses.Factories;
using Test.LightweightIocContainer.FactoryGenerator.TestClasses.Interfaces;
namespace Test.LightweightIocContainer.FactoryGenerator;
[TestFixture]
public class AsyncFactoryTest
{
[Test]
public async Task TestAsyncFactoryResolve()
{
IocContainer container = new();
container.Register(r => r.Add<IAsyncTest, AsyncTest>().WithGeneratedFactory<IAsyncTestFactory>());
IAsyncTestFactory testFactory = container.Resolve<IAsyncTestFactory>();
IAsyncTest test = await testFactory.Create();
Assert.That(test, Is.InstanceOf<AsyncTest>());
}
[Test]
public async Task TestAsyncFactoryResolveOnCreateCalled()
{
IocContainer container = new();
container.Register(r => r.Add<IAsyncTest, AsyncTest>().OnCreateAsync(t => t.Initialize()).WithGeneratedFactory<IAsyncTestFactory>());
IAsyncTestFactory testFactory = container.Resolve<IAsyncTestFactory>();
IAsyncTest test = await testFactory.Create();
Assert.That(test, Is.InstanceOf<AsyncTest>());
Assert.That(test.IsInitialized, Is.True);
}
[Test]
public async Task TestAsyncMultitonFactoryResolveOnCreateCalledCorrectly()
{
IocContainer container = new();
container.Register(r => r.AddMultiton<IAsyncTest, AsyncMultitonTest, int>().OnCreateAsync(t => t.Initialize()).WithGeneratedFactory<IAsyncMultitonTestFactory>());
IAsyncMultitonTestFactory testFactory = container.Resolve<IAsyncMultitonTestFactory>();
IAsyncTest test1 = await testFactory.Create(1);
IAsyncTest test2 = await testFactory.Create(2);
IAsyncTest anotherTest1 = await testFactory.Create(1);
Assert.That(test1, Is.InstanceOf<AsyncTest>());
Assert.That(test1.IsInitialized, Is.True);
Assert.That(test2, Is.InstanceOf<AsyncTest>());
Assert.That(test2.IsInitialized, Is.True);
Assert.That(test1, Is.SameAs(anotherTest1));
}
}

@ -0,0 +1,212 @@
// Author: Simon.Gockner
// Created: 2025-12-03
// Copyright(c) 2025 SimonG. All Rights Reserved.
using LightweightIocContainer;
using LightweightIocContainer.Exceptions;
using LightweightIocContainer.FactoryGenerator;
using Test.LightweightIocContainer.FactoryGenerator.TestClasses;
using Test.LightweightIocContainer.FactoryGenerator.TestClasses.Factories;
using Test.LightweightIocContainer.FactoryGenerator.TestClasses.Interfaces;
namespace Test.LightweightIocContainer.FactoryGenerator;
[TestFixture]
public class FluentFactoryRegistrationTest
{
private IocContainer _iocContainer;
[SetUp]
public void SetUp() => _iocContainer = new IocContainer();
[TearDown]
public void TearDown() => _iocContainer.Dispose();
[Test]
public void TestFluentFactoryRegistration()
{
_iocContainer.Register(r => r.Add<IDefaultTest, DefaultTest>().WithGeneratedFactory<IDefaultTestFactory>());
IDefaultTestFactory factory = _iocContainer.Resolve<IDefaultTestFactory>();
IDefaultTest test = factory.Create();
Assert.That(factory, Is.InstanceOf<IDefaultTestFactory>());
Assert.That(test, Is.InstanceOf<IDefaultTest>());
}
[Test]
public void TestFluentFactoryRegistrationResolveWithoutFactoryFails()
{
_iocContainer.Register(r => r.Add<IDefaultTest, DefaultTest>().WithGeneratedFactory<IDefaultTestFactory>());
Assert.Throws<DirectResolveWithRegisteredFactoryNotAllowed>(()=>_iocContainer.Resolve<IDefaultTest>());
}
[Test]
public void TestRegisterFactoryWithoutCreate() => Assert.Throws<InvalidFactoryRegistrationException>(() => _iocContainer.Register(r => r.Add<IDefaultTest, DefaultTest>().WithGeneratedFactory<ITestFactoryNoCreate>()));
[Test]
public void TestResolveFromFactory()
{
_iocContainer.Register(r => r.Add<IDefaultTest, DefaultTest>().WithGeneratedFactory<IDefaultTestFactory>());
IDefaultTestFactory testFactory = _iocContainer.Resolve<IDefaultTestFactory>();
IDefaultTest createdTest = testFactory.Create();
Assert.That(createdTest, Is.InstanceOf<DefaultTest>());
}
[Test]
public void TestResolveFromFactoryWithParams()
{
_iocContainer.Register(r => r.Add<IDefaultTest, TestConstructor>().WithGeneratedFactory<IDefaultTestFactory>());
_iocContainer.Register(r => r.Add<DefaultTest, DefaultTest>()); //this registration is abnormal and should only be used in unit tests
IDefaultTestFactory testFactory = _iocContainer.Resolve<IDefaultTestFactory>();
IDefaultTest createdTest = testFactory.Create("Test");
Assert.That(createdTest, Is.InstanceOf<TestConstructor>());
}
[Test]
public void TestResolveFromFactoryWithDefaultParamCreate()
{
_iocContainer.Register(r => r.Add<IDefaultTest, TestConstructor>().WithGeneratedFactory<IDefaultTestFactory>());
_iocContainer.Register(r => r.Add<DefaultTest, DefaultTest>()); //this registration is abnormal and should only be used in unit tests
IDefaultTestFactory testFactory = _iocContainer.Resolve<IDefaultTestFactory>();
IDefaultTest createdTest = testFactory.CreateTest();
Assert.That(createdTest, Is.InstanceOf<TestConstructor>());
}
[Test]
public void TestResolveFromFactoryWithDefaultParamCtor()
{
_iocContainer.Register(r => r.Add<IDefaultTest, TestConstructor>().WithGeneratedFactory<IDefaultTestFactory>());
_iocContainer.Register(r => r.Add<DefaultTest, DefaultTest>()); //this registration is abnormal and should only be used in unit tests
IDefaultTestFactory testFactory = _iocContainer.Resolve<IDefaultTestFactory>();
IDefaultTest createdTest = testFactory.Create();
Assert.That(createdTest, Is.InstanceOf<TestConstructor>());
}
[Test]
public void TestResolveFromFactoryWithByte()
{
_iocContainer.Register(r => r.Add<IDefaultTest, TestByte>().WithGeneratedFactory<IDefaultTestFactory>());
IDefaultTestFactory testFactory = _iocContainer.Resolve<IDefaultTestFactory>();
IDefaultTest createdTest = testFactory.Create(1);
Assert.That(createdTest, Is.InstanceOf<TestByte>());
}
[Test]
public void TestPassingNullAsMiddleParameter()
{
_iocContainer.Register(r => r.Add<IDefaultTest, TestNull>().WithGeneratedFactory<ITestNullFactory>());
ITestNullFactory testNullFactory = _iocContainer.Resolve<ITestNullFactory>();
object obj = new();
string content = "TestContent";
string optional2 = "optionalParameter2";
IDefaultTest createdTest = testNullFactory.Create(obj, content, null!, optional2);
if (createdTest is not TestNull testNull)
{
Assert.Fail();
return;
}
Assert.That(testNull.Obj, Is.SameAs(obj));
Assert.That(testNull.Content, Is.EqualTo(content));
Assert.That(testNull.Optional1, Is.Null);
Assert.That(testNull.Optional2, Is.EqualTo(optional2));
}
[Test]
public void TestPassingNullAsDefaultParameter()
{
_iocContainer.Register(r => r.Add<IDefaultTest, TestNull>().WithGeneratedFactory<ITestDefaultFactory>());
ITestDefaultFactory testDefaultFactory = _iocContainer.Resolve<ITestDefaultFactory>();
object obj = new();
string content = "TestContent";
string optional2 = "optionalParameter2";
IDefaultTest createdTest = testDefaultFactory.Create(obj, content, null!, optional2);
if (createdTest is not TestNull testNull)
{
Assert.Fail();
return;
}
Assert.That(testNull.Obj, Is.SameAs(obj));
Assert.That(testNull.Content, Is.EqualTo(content));
Assert.That(testNull.Optional1, Is.Null);
Assert.That(testNull.Optional2, Is.EqualTo(optional2));
Assert.That(testNull.TestNullFactory, Is.Null);
}
[Test]
public void TestResolveMultitonFromFactory()
{
_iocContainer.Register(r => r.AddMultiton<IDefaultTest, TestMultiton, MultitonScope>().WithGeneratedFactory<IMultitonTestFactory>());
MultitonScope scope1 = new();
MultitonScope scope2 = new();
IMultitonTestFactory testFactory = _iocContainer.Resolve<IMultitonTestFactory>();
IDefaultTest resolvedTest1 = testFactory.Create(scope1);
IDefaultTest resolvedTest2 = testFactory.Create(scope1);
IDefaultTest resolvedTest3 = testFactory.Create(scope2);
Assert.That(resolvedTest1, Is.SameAs(resolvedTest2));
Assert.That(resolvedTest1, Is.Not.SameAs(resolvedTest3));
Assert.That(resolvedTest2, Is.Not.SameAs(resolvedTest3));
}
[Test]
public void TestResolveMultitonFromFactoryClearInstances()
{
_iocContainer.Register(r => r.AddMultiton<IDefaultTest, TestMultiton, MultitonScope>().WithGeneratedFactory<IMultitonTestFactory>());
MultitonScope scope1 = new();
MultitonScope scope2 = new();
IMultitonTestFactory testFactory = _iocContainer.Resolve<IMultitonTestFactory>();
IDefaultTest resolvedTest1 = testFactory.Create(scope1);
IDefaultTest resolvedTest2 = testFactory.Create(scope1);
IDefaultTest resolvedTest3 = testFactory.Create(scope2);
Assert.That(resolvedTest1, Is.SameAs(resolvedTest2));
Assert.That(resolvedTest1, Is.Not.SameAs(resolvedTest3));
Assert.That(resolvedTest2, Is.Not.SameAs(resolvedTest3));
testFactory.ClearMultitonInstance<IDefaultTest>();
IDefaultTest resolvedTest4 = testFactory.Create(scope1);
IDefaultTest resolvedTest5 = testFactory.Create(scope2);
Assert.That(resolvedTest1, Is.Not.SameAs(resolvedTest4));
Assert.That(resolvedTest2, Is.Not.SameAs(resolvedTest4));
Assert.That(resolvedTest3, Is.Not.SameAs(resolvedTest5));
}
[Test]
public void InvalidMultitonFactoryRegistrationFactoryWithoutParameter() =>
Assert.Throws<InvalidFactoryRegistrationException>(() => _iocContainer.Register(r => r.AddMultiton<IDefaultTest, DefaultTest, MultitonScope>().WithGeneratedFactory<IDefaultTestFactory>()));
[Test]
public void InvalidMultitonFactoryRegistrationFactoryWithoutScopeAsFirstParameter() =>
Assert.Throws<InvalidFactoryRegistrationException>(() => _iocContainer.Register(r => r.AddMultiton<IDefaultTest, DefaultTest, MultitonScope>().WithGeneratedFactory<IInvalidMultitonTestFactory>()));
[Test]
public void TestInvalidCreateMethodReturnType() =>
Assert.Throws<InvalidFactoryRegistrationException>(() => _iocContainer.Register(r => r.Add<IDefaultTest, DefaultTest>().WithGeneratedFactory<ITestFactoryWrongReturn>()));
}

@ -0,0 +1,40 @@
// Author: Simon.Gockner
// Created: 2025-12-03
// Copyright(c) 2025 SimonG. All Rights Reserved.
using LightweightIocContainer;
using LightweightIocContainer.FactoryGenerator;
using Test.LightweightIocContainer.FactoryGenerator.TestClasses;
using Test.LightweightIocContainer.FactoryGenerator.TestClasses.Factories;
using Test.LightweightIocContainer.FactoryGenerator.TestClasses.Interfaces;
namespace Test.LightweightIocContainer.FactoryGenerator;
[TestFixture]
public class MultiLayerResolveTest
{
[Test]
public void TestResolveFactoryAsCtorParameter()
{
IocContainer container = new();
container.Register(r => r.Add<IA, A>().WithGeneratedFactory<IAFactory>());
container.Register(r => r.Add<IB, B>().WithGeneratedFactory<IBFactory>());
IAFactory aFactory = container.Resolve<IAFactory>();
IA a = aFactory.Create();
Assert.That(a, Is.InstanceOf<A>());
}
[Test]
public void TestResolveSingleTypeRegistrationAsCtorParameter()
{
IocContainer container = new();
container.Register(r => r.Add<IA, A>());
container.Register(r => r.Add<IB, B>().WithGeneratedFactory<IBFactory>());
container.Register(r => r.Add<C>().WithFactoryMethod(_ => new C("test")));
IBFactory bFactory = container.Resolve<IBFactory>();
IB b = bFactory.Create();
Assert.That(b, Is.InstanceOf<B>());
}
}

@ -0,0 +1,41 @@
// Author: Simon.Gockner
// Created: 2025-12-03
// Copyright(c) 2025 SimonG. All Rights Reserved.
using LightweightIocContainer;
using LightweightIocContainer.FactoryGenerator;
using Test.LightweightIocContainer.FactoryGenerator.TestClasses;
using Test.LightweightIocContainer.FactoryGenerator.TestClasses.Factories;
using Test.LightweightIocContainer.FactoryGenerator.TestClasses.Interfaces;
namespace Test.LightweightIocContainer.FactoryGenerator;
[TestFixture]
public class OpenGenericRegistrationTest
{
private IocContainer _iocContainer;
[SetUp]
public void SetUp() => _iocContainer = new IocContainer();
[TearDown]
public void TearDown() => _iocContainer.Dispose();
[Test]
public void TestRegisterFactoryOfOpenGenericType()
{
_iocContainer.Register(r => r.AddOpenGenerics(typeof(IGenericTest<>), typeof(GenericTest<>)).WithGeneratedFactory<IGenericTestFactory>());
IGenericTestFactory testFactory = _iocContainer.Resolve<IGenericTestFactory>();
IGenericTest<Constraint> test = testFactory.Create<Constraint>();
Assert.That(test, Is.InstanceOf<GenericTest<Constraint>>());
}
[Test]
public void TestRegisterFactoryOfOpenGenericTypeWithCtorParameter()
{
_iocContainer.Register(r => r.AddOpenGenerics(typeof(IGenericTest<>), typeof(CtorGenericTest<>)).WithGeneratedFactory<ICtorGenericTestFactory>());
ICtorGenericTestFactory testFactory = _iocContainer.Resolve<ICtorGenericTestFactory>();
IGenericTest<Constraint> test = testFactory.Create(new Constraint());
Assert.That(test, Is.InstanceOf<CtorGenericTest<Constraint>>());
}
}

@ -0,0 +1,33 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<LangVersion>latest</LangVersion>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="coverlet.collector" Version="6.0.4"/>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.0.1" />
<PackageReference Include="NUnit" Version="4.4.0" />
<PackageReference Include="NUnit.Analyzers" Version="4.11.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="NUnit3TestAdapter" Version="6.0.0-beta.3" />
</ItemGroup>
<ItemGroup>
<Using Include="NUnit.Framework"/>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\LightweightIocContainer\LightweightIocContainer.csproj" />
<ProjectReference Include="..\LightweightIocContainer.FactoryGenerator\LightweightIocContainer.FactoryGenerator.csproj"
OutputItemType="Analyzer"
ReferenceOutputAssembly="false"/>
</ItemGroup>
</Project>

@ -0,0 +1,10 @@
using Test.LightweightIocContainer.FactoryGenerator.TestClasses.Factories;
using Test.LightweightIocContainer.FactoryGenerator.TestClasses.Interfaces;
namespace Test.LightweightIocContainer.FactoryGenerator.TestClasses;
public class A : IA
{
public A(IBFactory bFactory) => BProperty = bFactory.Create(new C("from A"));
public IB BProperty { get; }
}

@ -0,0 +1,13 @@
namespace Test.LightweightIocContainer.FactoryGenerator.TestClasses;
public class AsyncMultitonTest(int id) : AsyncTest
{
public int Id { get; } = id;
public override async Task Initialize()
{
if (IsInitialized)
throw new Exception();
await base.Initialize();
}
}

@ -0,0 +1,14 @@
using Test.LightweightIocContainer.FactoryGenerator.TestClasses.Interfaces;
namespace Test.LightweightIocContainer.FactoryGenerator.TestClasses;
public class AsyncTest : IAsyncTest
{
public bool IsInitialized { get; private set; }
public virtual async Task Initialize()
{
await Task.Delay(200);
IsInitialized = true;
}
}

@ -0,0 +1,10 @@
using Test.LightweightIocContainer.FactoryGenerator.TestClasses.Interfaces;
namespace Test.LightweightIocContainer.FactoryGenerator.TestClasses;
public class B : IB
{
public B(C c) => C = c;
public C C { get; }
}

@ -0,0 +1,9 @@
namespace Test.LightweightIocContainer.FactoryGenerator.TestClasses;
public class C
{
public C(string test)
{
}
}

@ -0,0 +1,9 @@
// Author: Simon.Gockner
// Created: 2025-12-03
// Copyright(c) 2025 SimonG. All Rights Reserved.
using Test.LightweightIocContainer.FactoryGenerator.TestClasses.Interfaces;
namespace Test.LightweightIocContainer.FactoryGenerator.TestClasses;
public class Constraint : IConstraint;

@ -0,0 +1,11 @@
using Test.LightweightIocContainer.FactoryGenerator.TestClasses.Interfaces;
namespace Test.LightweightIocContainer.FactoryGenerator.TestClasses;
public class CtorGenericTest<T> : IGenericTest<T> where T : IConstraint, new()
{
public CtorGenericTest(T item)
{
}
}

@ -0,0 +1,5 @@
using Test.LightweightIocContainer.FactoryGenerator.TestClasses.Interfaces;
namespace Test.LightweightIocContainer.FactoryGenerator.TestClasses;
public class DefaultTest : IDefaultTest;

@ -0,0 +1,8 @@
using Test.LightweightIocContainer.FactoryGenerator.TestClasses.Interfaces;
namespace Test.LightweightIocContainer.FactoryGenerator.TestClasses.Factories;
public interface IAFactory
{
IA Create();
}

@ -0,0 +1,8 @@
using Test.LightweightIocContainer.FactoryGenerator.TestClasses.Interfaces;
namespace Test.LightweightIocContainer.FactoryGenerator.TestClasses.Factories;
public interface IAsyncMultitonTestFactory
{
Task<IAsyncTest> Create(int id);
}

@ -0,0 +1,8 @@
using Test.LightweightIocContainer.FactoryGenerator.TestClasses.Interfaces;
namespace Test.LightweightIocContainer.FactoryGenerator.TestClasses.Factories;
public interface IAsyncTestFactory
{
Task<IAsyncTest> Create();
}

@ -0,0 +1,9 @@
using Test.LightweightIocContainer.FactoryGenerator.TestClasses.Interfaces;
namespace Test.LightweightIocContainer.FactoryGenerator.TestClasses.Factories;
public interface IBFactory
{
IB Create();
IB Create(C c);
}

@ -0,0 +1,8 @@
using Test.LightweightIocContainer.FactoryGenerator.TestClasses.Interfaces;
namespace Test.LightweightIocContainer.FactoryGenerator.TestClasses.Factories;
public interface ICtorGenericTestFactory
{
IGenericTest<T> Create<T>(T item) where T : IConstraint, new();
}

@ -0,0 +1,11 @@
using Test.LightweightIocContainer.FactoryGenerator.TestClasses.Interfaces;
namespace Test.LightweightIocContainer.FactoryGenerator.TestClasses.Factories;
public interface IDefaultTestFactory
{
IDefaultTest Create();
IDefaultTest Create(string name);
IDefaultTest CreateTest(string name = null!);
IDefaultTest Create(byte id);
}

@ -0,0 +1,8 @@
using Test.LightweightIocContainer.FactoryGenerator.TestClasses.Interfaces;
namespace Test.LightweightIocContainer.FactoryGenerator.TestClasses.Factories;
public interface IGenericTestFactory
{
IGenericTest<T> Create<T>() where T : IConstraint, new();
}

@ -0,0 +1,9 @@
using Test.LightweightIocContainer.FactoryGenerator.TestClasses.Interfaces;
namespace Test.LightweightIocContainer.FactoryGenerator.TestClasses.Factories;
public interface IInvalidMultitonTestFactory
{
IDefaultTest Create(MultitonScope scope);
IDefaultTest Create(int number);
}

@ -0,0 +1,9 @@
using Test.LightweightIocContainer.FactoryGenerator.TestClasses.Interfaces;
namespace Test.LightweightIocContainer.FactoryGenerator.TestClasses.Factories;
public interface IMultitonTestFactory
{
IDefaultTest Create(MultitonScope scope);
void ClearMultitonInstance<T>();
}

@ -0,0 +1,8 @@
using Test.LightweightIocContainer.FactoryGenerator.TestClasses.Interfaces;
namespace Test.LightweightIocContainer.FactoryGenerator.TestClasses.Factories;
public interface ITestDefaultFactory
{
IDefaultTest Create(object obj, string content, string optional1, string optional2, ITestNullFactory testNullFactory = null!);
}

@ -0,0 +1,3 @@
namespace Test.LightweightIocContainer.FactoryGenerator.TestClasses.Factories;
public interface ITestFactoryNoCreate;

@ -0,0 +1,6 @@
namespace Test.LightweightIocContainer.FactoryGenerator.TestClasses.Factories;
public interface ITestFactoryWrongReturn
{
public MultitonScope Create();
}

@ -0,0 +1,8 @@
using Test.LightweightIocContainer.FactoryGenerator.TestClasses.Interfaces;
namespace Test.LightweightIocContainer.FactoryGenerator.TestClasses.Factories;
public interface ITestNullFactory
{
IDefaultTest Create(object obj, string content, string optional1, string optional2);
}

@ -0,0 +1,5 @@
using Test.LightweightIocContainer.FactoryGenerator.TestClasses.Interfaces;
namespace Test.LightweightIocContainer.FactoryGenerator.TestClasses;
public class GenericTest<T> : IGenericTest<T> where T : IConstraint, new();

@ -0,0 +1,6 @@
namespace Test.LightweightIocContainer.FactoryGenerator.TestClasses.Interfaces;
public interface IA
{
IB BProperty { get; }
}

@ -0,0 +1,7 @@
namespace Test.LightweightIocContainer.FactoryGenerator.TestClasses.Interfaces;
public interface IAsyncTest
{
bool IsInitialized { get; }
Task Initialize();
}

@ -0,0 +1,6 @@
namespace Test.LightweightIocContainer.FactoryGenerator.TestClasses.Interfaces;
public interface IB
{
C C { get; }
}

@ -0,0 +1,3 @@
namespace Test.LightweightIocContainer.FactoryGenerator.TestClasses.Interfaces;
public interface IConstraint;

@ -0,0 +1,3 @@
namespace Test.LightweightIocContainer.FactoryGenerator.TestClasses.Interfaces;
public interface IDefaultTest;

@ -0,0 +1,3 @@
namespace Test.LightweightIocContainer.FactoryGenerator.TestClasses.Interfaces;
public interface IGenericTest<T> where T : IConstraint, new();

@ -0,0 +1,3 @@
namespace Test.LightweightIocContainer.FactoryGenerator.TestClasses;
public class MultitonScope;

@ -0,0 +1,10 @@
using Test.LightweightIocContainer.FactoryGenerator.TestClasses.Interfaces;
namespace Test.LightweightIocContainer.FactoryGenerator.TestClasses;
public class TestByte : IDefaultTest
{
private readonly byte _id;
public TestByte(byte id) => _id = id;
}

@ -0,0 +1,16 @@
using Test.LightweightIocContainer.FactoryGenerator.TestClasses.Interfaces;
namespace Test.LightweightIocContainer.FactoryGenerator.TestClasses;
public class TestConstructor : IDefaultTest
{
public TestConstructor(string name, DefaultTest test)
{
}
public TestConstructor(DefaultTest test, string name = null!)
{
}
}

@ -0,0 +1,11 @@
using Test.LightweightIocContainer.FactoryGenerator.TestClasses.Interfaces;
namespace Test.LightweightIocContainer.FactoryGenerator.TestClasses;
public class TestMultiton : IDefaultTest
{
public TestMultiton(MultitonScope scope)
{
}
}

@ -0,0 +1,23 @@
using Test.LightweightIocContainer.FactoryGenerator.TestClasses.Factories;
using Test.LightweightIocContainer.FactoryGenerator.TestClasses.Interfaces;
namespace Test.LightweightIocContainer.FactoryGenerator.TestClasses;
public class TestNull : IDefaultTest
{
public TestNull(object obj, string content, string optional1, string optional2, ITestNullFactory testNullFactory)
{
Obj = obj;
Content = content;
Optional1 = optional1;
Optional2 = optional2;
TestNullFactory = testNullFactory;
}
public object Obj { get; }
public string Content { get; }
public string Optional1 { get; }
public string Optional2 { get; }
public ITestNullFactory TestNullFactory { get; }
}

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net9.0</TargetFramework> <TargetFramework>net10.0</TargetFramework>
<IsPackable>false</IsPackable> <IsPackable>false</IsPackable>
<Authors>SimonG</Authors> <Authors>SimonG</Authors>
<LangVersion>default</LangVersion> <LangVersion>default</LangVersion>
@ -9,11 +9,11 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="JetBrains.Annotations" Version="2024.3.0" /> <PackageReference Include="JetBrains.Annotations" Version="2025.2.4" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.0.1" />
<PackageReference Include="NSubstitute" Version="5.3.0" /> <PackageReference Include="NSubstitute" Version="5.3.0" />
<PackageReference Include="nunit" Version="4.2.2" /> <PackageReference Include="nunit" Version="4.4.0" />
<PackageReference Include="NUnit3TestAdapter" Version="4.6.0"> <PackageReference Include="NUnit3TestAdapter" Version="6.0.0-beta.3">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net9.0</TargetFramework> <TargetFramework>net10.0</TargetFramework>
<IsPackable>false</IsPackable> <IsPackable>false</IsPackable>
<Authors>SimonG</Authors> <Authors>SimonG</Authors>
<LangVersion>default</LangVersion> <LangVersion>default</LangVersion>
@ -9,11 +9,11 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="JetBrains.Annotations" Version="2024.3.0" /> <PackageReference Include="JetBrains.Annotations" Version="2025.2.4" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.0.1" />
<PackageReference Include="NSubstitute" Version="5.3.0" /> <PackageReference Include="NSubstitute" Version="5.3.0" />
<PackageReference Include="nunit" Version="4.2.2" /> <PackageReference Include="nunit" Version="4.4.0" />
<PackageReference Include="NUnit3TestAdapter" Version="4.6.0"> <PackageReference Include="NUnit3TestAdapter" Version="6.0.0-beta.3">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>

Loading…
Cancel
Save