@@ -6284,6 +6284,242 @@ public static void Main()
62846284 result . GeneratedCode . Contains ( "Resolve<Sample.IBox<Sample.IDependency?>>()" , StringComparison . Ordinal ) . ShouldBeTrue ( result ) ;
62856285 }
62866286
6287+ [ Fact ]
6288+ public async Task ShouldNotGenerateDoubleNullableForNullableGenericDependencySingleton ( )
6289+ {
6290+ // Given
6291+
6292+ // When
6293+ var result = await """
6294+ #nullable enable annotations
6295+ using System;
6296+ using Microsoft.Extensions.Logging;
6297+ using Pure.DI;
6298+
6299+ namespace Microsoft.Extensions.Logging
6300+ {
6301+ public interface ILogger<T>
6302+ {
6303+ }
6304+
6305+ public interface ILoggerFactory
6306+ {
6307+ ILogger<T> CreateLogger<T>();
6308+ }
6309+
6310+ public interface ILoggingBuilder
6311+ {
6312+ }
6313+
6314+ public sealed class LoggerFactory: ILoggerFactory
6315+ {
6316+ public static ILoggerFactory Create(Action<ILoggingBuilder> configure) => new LoggerFactory();
6317+
6318+ public ILogger<T> CreateLogger<T>() => new Logger<T>();
6319+ }
6320+
6321+ public sealed class Logger<T>: ILogger<T>
6322+ {
6323+ }
6324+ }
6325+
6326+ namespace PureDiNullable
6327+ {
6328+ public class Class
6329+ {
6330+ public Class(ILogger<Class>? logger) => Logger = logger;
6331+
6332+ public ILogger<Class>? Logger { get; }
6333+ }
6334+
6335+ partial class Composition
6336+ {
6337+ private void Setup() =>
6338+ DI.Setup(nameof(Composition))
6339+ .Root<Class>(nameof(Class))
6340+ .Bind<ILoggerFactory>().As(Lifetime.Singleton).To(_ => LoggerFactory.Create(builder => { }))
6341+ .Bind<ILogger<TT>>().As(Lifetime.Singleton).To(ctx =>
6342+ {
6343+ ctx.Inject<ILoggerFactory>(out var factory);
6344+ return factory.CreateLogger<TT>();
6345+ });
6346+ }
6347+
6348+ public class Program
6349+ {
6350+ public static void Main()
6351+ {
6352+ var composition = new Composition();
6353+ Console.WriteLine(composition.Class.Logger is not null);
6354+ }
6355+ }
6356+ }
6357+ """ . RunAsync ( new Options { LanguageVersion = LanguageVersion . CSharp10 } ) ;
6358+
6359+ // Then
6360+ result . Success . ShouldBeTrue ( result ) ;
6361+ result . StdOut . ShouldBe ( [ "True" ] , result ) ;
6362+ result . GeneratedCode . Contains ( "?? _singleton" , StringComparison . Ordinal ) . ShouldBeFalse ( result ) ;
6363+ result . GeneratedCode . Contains ( "Microsoft.Extensions.Logging.ILogger<global::PureDiNullable.Class>? _singleton" , StringComparison . Ordinal ) . ShouldBeTrue ( result ) ;
6364+ }
6365+
6366+ [ Fact ]
6367+ public async Task ShouldNotGenerateDoubleNullableForNullableGenericDependencyScoped ( )
6368+ {
6369+ // Given
6370+
6371+ // When
6372+ var result = await """
6373+ #nullable enable annotations
6374+ using System;
6375+ using Pure.DI;
6376+
6377+ namespace Sample;
6378+
6379+ interface IBox<T>
6380+ {
6381+ }
6382+
6383+ class Box<T>: IBox<T>
6384+ {
6385+ }
6386+
6387+ class Service
6388+ {
6389+ public Service(IBox<string>? box) => Box = box;
6390+
6391+ public IBox<string>? Box { get; }
6392+ }
6393+
6394+ static class Setup
6395+ {
6396+ private static void SetupComposition()
6397+ {
6398+ DI.Setup("Composition")
6399+ .Bind<IBox<TT>>().As(Lifetime.Scoped).To<Box<TT>>()
6400+ .Root<Service>("Service");
6401+ }
6402+ }
6403+
6404+ public class Program
6405+ {
6406+ public static void Main() => Console.WriteLine(new Composition().Service.Box is not null);
6407+ }
6408+ """ . RunAsync ( new Options { LanguageVersion = LanguageVersion . CSharp10 } ) ;
6409+
6410+ // Then
6411+ result . Success . ShouldBeTrue ( result ) ;
6412+ result . StdOut . ShouldBe ( [ "True" ] , result ) ;
6413+ result . GeneratedCode . Contains ( "?? _scoped" , StringComparison . Ordinal ) . ShouldBeFalse ( result ) ;
6414+ result . GeneratedCode . Contains ( "Sample.Box<string>? _scoped" , StringComparison . Ordinal ) . ShouldBeTrue ( result ) ;
6415+ }
6416+
6417+ [ Fact ]
6418+ public async Task ShouldNotGenerateDoubleNullableForNullableArrayDependencySingleton ( )
6419+ {
6420+ // Given
6421+
6422+ // When
6423+ var result = await """
6424+ #nullable enable annotations
6425+ using System;
6426+ using Pure.DI;
6427+
6428+ namespace Sample;
6429+
6430+ interface IDependency
6431+ {
6432+ }
6433+
6434+ class Dependency: IDependency
6435+ {
6436+ }
6437+
6438+ class Service
6439+ {
6440+ public Service(IDependency[]? dependencies) => Dependencies = dependencies;
6441+
6442+ public IDependency[]? Dependencies { get; }
6443+ }
6444+
6445+ static class Setup
6446+ {
6447+ private static void SetupComposition()
6448+ {
6449+ DI.Setup("Composition")
6450+ .Bind<IDependency>().To<Dependency>()
6451+ .Bind<IDependency[]?>().As(Lifetime.Singleton).To(ctx =>
6452+ {
6453+ ctx.Inject(out IDependency[] dependencies);
6454+ return dependencies;
6455+ })
6456+ .Root<Service>("Service");
6457+ }
6458+ }
6459+
6460+ public class Program
6461+ {
6462+ public static void Main() => Console.WriteLine(new Composition().Service.Dependencies is { Length: 1 });
6463+ }
6464+ """ . RunAsync ( new Options { LanguageVersion = LanguageVersion . CSharp10 } ) ;
6465+
6466+ // Then
6467+ result . Success . ShouldBeTrue ( result ) ;
6468+ result . StdOut . ShouldBe ( [ "True" ] , result ) ;
6469+ result . GeneratedCode . Contains ( "[]?? _singleton" , StringComparison . Ordinal ) . ShouldBeFalse ( result ) ;
6470+ result . GeneratedCode . Contains ( "IDependency[]? _singleton" , StringComparison . Ordinal ) . ShouldBeTrue ( result ) ;
6471+ }
6472+
6473+ [ Fact ]
6474+ public async Task ShouldGenerateNullableBackingFieldForNonNullableGenericDependencySingleton ( )
6475+ {
6476+ // Given
6477+
6478+ // When
6479+ var result = await """
6480+ #nullable enable annotations
6481+ using System;
6482+ using Pure.DI;
6483+
6484+ namespace Sample;
6485+
6486+ interface IBox<T>
6487+ {
6488+ }
6489+
6490+ class Box<T>: IBox<T>
6491+ {
6492+ }
6493+
6494+ class Service
6495+ {
6496+ public Service(IBox<string> box) => Box = box;
6497+
6498+ public IBox<string> Box { get; }
6499+ }
6500+
6501+ static class Setup
6502+ {
6503+ private static void SetupComposition()
6504+ {
6505+ DI.Setup("Composition")
6506+ .Bind<IBox<TT>>().As(Lifetime.Singleton).To<Box<TT>>()
6507+ .Root<Service>("Service");
6508+ }
6509+ }
6510+
6511+ public class Program
6512+ {
6513+ public static void Main() => Console.WriteLine(new Composition().Service.Box is not null);
6514+ }
6515+ """ . RunAsync ( new Options { LanguageVersion = LanguageVersion . CSharp10 } ) ;
6516+
6517+ // Then
6518+ result . Success . ShouldBeTrue ( result ) ;
6519+ result . StdOut . ShouldBe ( [ "True" ] , result ) ;
6520+ result . GeneratedCode . Contains ( "Sample.Box<string>? _singleton" , StringComparison . Ordinal ) . ShouldBeTrue ( result ) ;
6521+ }
6522+
62876523 [ Fact ]
62886524 public async Task ShouldSupportNullableOnCannotResolvePartialMethod ( )
62896525 {
0 commit comments