From ed6a7456af64259b0faad76ba1961805a389dbd2 Mon Sep 17 00:00:00 2001 From: Chris Pulman Date: Wed, 30 Jun 2021 11:09:16 +0100 Subject: [PATCH 1/9] fix GetService changed to return a non nullable Presently Getservice casts to a nullable return value object? or T?, now returns the value as a object or T --- .../Splat.Autofac.Tests.csproj | 1 + .../AutofacDependencyResolver.cs | 20 ++-- .../Splat.Common.Test.csproj | 1 + src/Splat.Drawing.Tests/BitmapLoaderTests.cs | 4 +- .../Colors/SplatColorTests.cs | 2 +- .../Splat.Drawing.Tests.csproj | 1 + .../Splat.DryIoc.Tests.csproj | 1 + src/Splat.DryIoc/DryIocDependencyResolver.cs | 8 +- .../ContainerWrapper.cs | 3 + .../MicrosoftDependencyResolverTests.cs | 8 +- ...xtensions.DependencyInjection.Tests.csproj | 1 + .../MicrosoftDependencyResolver.cs | 11 +- .../NInjectDependencyResolverTests.cs | 8 +- .../Splat.Ninject.Tests.csproj | 1 + .../NinjectDependencyResolver.cs | 10 +- .../Splat.Prism.Tests.csproj | 1 + src/Splat.Prism/SplatContainerExtension.cs | 16 +-- .../DependencyResolverTests.cs | 2 +- .../Splat.SimpleInjector.Tests.csproj | 1 + .../SimpleInjectorDependencyResolver.cs | 10 +- .../SimpleInjectorInitializer.cs | 18 ++- .../TransientSimpleInjectorRegistration.cs | 4 +- ...ovalTests.SplatProject.net5.0.approved.txt | 26 ++--- ...ts.SplatProject.netcoreapp3.1.approved.txt | 26 ++--- src/Splat.Tests/ApiExtensions.cs | 6 +- .../BaseFeatureUsageTrackingTests.cs | 6 +- src/Splat.Tests/LocatorTests.cs | 12 +- src/Splat.Tests/Logging/ActionLoggerTests.cs | 108 +++++++++--------- .../Logging/FullLoggers/SerilogLoggerTests.cs | 36 +++--- .../WrappingFullLoggers/ConsoleLoggerTests.cs | 4 +- .../ExceptionlessLoggerTests.cs | 16 +-- .../WrappingFullLoggers/Log4NetLoggerTests.cs | 16 +-- src/Splat.Tests/MemoizingMRUCacheTests.cs | 2 +- src/Splat.Tests/Splat.Tests.csproj | 2 + src/Splat.Tests/XUnitHelpers.cs | 2 +- .../DependencyResolverMixins.cs | 14 +-- .../ServiceLocation/FuncDependencyResolver.cs | 10 +- .../IMutableDependencyResolver.cs | 2 +- .../IReadonlyDependencyResolver.cs | 2 +- .../ModernDependencyResolver.cs | 22 ++-- 40 files changed, 230 insertions(+), 214 deletions(-) diff --git a/src/Splat.Autofac.Tests/Splat.Autofac.Tests.csproj b/src/Splat.Autofac.Tests/Splat.Autofac.Tests.csproj index 0c09fe3f9..d56e06da8 100644 --- a/src/Splat.Autofac.Tests/Splat.Autofac.Tests.csproj +++ b/src/Splat.Autofac.Tests/Splat.Autofac.Tests.csproj @@ -6,6 +6,7 @@ false $(NoWarn);1591;CA1707;SA1633;CA2000 latest + enable diff --git a/src/Splat.Autofac/AutofacDependencyResolver.cs b/src/Splat.Autofac/AutofacDependencyResolver.cs index 148e58063..ee6bafbcc 100644 --- a/src/Splat.Autofac/AutofacDependencyResolver.cs +++ b/src/Splat.Autofac/AutofacDependencyResolver.cs @@ -50,7 +50,7 @@ public AutofacDependencyResolver(ContainerBuilder builder) } /// - public virtual object? GetService(Type serviceType, string? contract = null) + public virtual object GetService(Type serviceType, string? contract = null) { lock (_lockObject) { @@ -133,7 +133,7 @@ public bool HasRegistration(Type serviceType, string? contract = null) /// The type which is used for the registration. /// A optional contract value which will indicates to only generate the value if this contract is specified. [Obsolete("Because Autofac 5+ containers are immutable, this method should not be used by the end-user.")] - public virtual void Register(Func factory, Type serviceType, string? contract = null) + public virtual void Register(Func factory, Type serviceType, string? contract = null) { lock (_lockObject) { @@ -147,21 +147,21 @@ public virtual void Register(Func factory, Type serviceType, string? con // Second to child lifetimes in a temporary container, that is used only to satisfy ReactiveUI dependencies. if (contract is null || string.IsNullOrWhiteSpace(contract)) { - _builder.Register(_ => factory()) + _builder.Register(_ => factory()!) .As(serviceType) .AsImplementedInterfaces(); _internalLifetimeScope = _internalLifetimeScope.BeginLifetimeScope(internalBuilder => - internalBuilder.Register(_ => factory()) + internalBuilder.Register(_ => factory()!) .As(serviceType) .AsImplementedInterfaces()); } else { - _builder.Register(_ => factory()) + _builder.Register(_ => factory()!) .Named(contract, serviceType) .AsImplementedInterfaces(); _internalLifetimeScope = _internalLifetimeScope.BeginLifetimeScope(internalBuilder => - internalBuilder.Register(_ => factory()) + internalBuilder.Register(_ => factory()!) .Named(contract, serviceType) .AsImplementedInterfaces()); } @@ -225,19 +225,19 @@ protected virtual void Dispose(bool disposing) } } - private object? Resolve(Type serviceType, string? contract) + private object Resolve(Type serviceType, string? contract) { - object? serviceInstance; + object serviceInstance; var lifeTimeScope = _lifetimeScope ?? _internalLifetimeScope; if (contract is null || string.IsNullOrWhiteSpace(contract)) { - lifeTimeScope.TryResolve(serviceType, out serviceInstance); + lifeTimeScope.TryResolve(serviceType, out serviceInstance!); } else { - lifeTimeScope.TryResolveNamed(contract, serviceType, out serviceInstance); + lifeTimeScope.TryResolveNamed(contract, serviceType, out serviceInstance!); } return serviceInstance; diff --git a/src/Splat.Common.Test/Splat.Common.Test.csproj b/src/Splat.Common.Test/Splat.Common.Test.csproj index 2d14f994c..97e0fa0db 100644 --- a/src/Splat.Common.Test/Splat.Common.Test.csproj +++ b/src/Splat.Common.Test/Splat.Common.Test.csproj @@ -4,6 +4,7 @@ netstandard2.0;net5.0 $(NoWarn);CA2000 latest + enable diff --git a/src/Splat.Drawing.Tests/BitmapLoaderTests.cs b/src/Splat.Drawing.Tests/BitmapLoaderTests.cs index 5354526c6..dd57aad95 100644 --- a/src/Splat.Drawing.Tests/BitmapLoaderTests.cs +++ b/src/Splat.Drawing.Tests/BitmapLoaderTests.cs @@ -11,6 +11,7 @@ using Xunit; #if !NETSTANDARD2_0 + namespace Splat.Tests { /// @@ -100,9 +101,10 @@ private static Stream GetStream(string imageName) return Android.App.Application.Context.Assets.Open(imageName); #else var assembly = Assembly.GetExecutingAssembly(); - return assembly.GetManifestResourceStream(imageName); + return assembly.GetManifestResourceStream(imageName)!; #endif } } } + #endif diff --git a/src/Splat.Drawing.Tests/Colors/SplatColorTests.cs b/src/Splat.Drawing.Tests/Colors/SplatColorTests.cs index c9bb6cd5a..7beb4d505 100644 --- a/src/Splat.Drawing.Tests/Colors/SplatColorTests.cs +++ b/src/Splat.Drawing.Tests/Colors/SplatColorTests.cs @@ -55,7 +55,7 @@ private static IEnumerable GetEnumAsTestTheory() var results = new List(values.Length); foreach (var value in values) { - results.Add(new[] { value }); + results.Add(new[] { value! }); } return results; diff --git a/src/Splat.Drawing.Tests/Splat.Drawing.Tests.csproj b/src/Splat.Drawing.Tests/Splat.Drawing.Tests.csproj index 5e537b02b..7dd32d0b0 100644 --- a/src/Splat.Drawing.Tests/Splat.Drawing.Tests.csproj +++ b/src/Splat.Drawing.Tests/Splat.Drawing.Tests.csproj @@ -5,6 +5,7 @@ false $(NoWarn);1591;CA1707;SA1633;CA2000;CA1034 latest + enable diff --git a/src/Splat.DryIoc.Tests/Splat.DryIoc.Tests.csproj b/src/Splat.DryIoc.Tests/Splat.DryIoc.Tests.csproj index 166804f64..e40f23a1d 100644 --- a/src/Splat.DryIoc.Tests/Splat.DryIoc.Tests.csproj +++ b/src/Splat.DryIoc.Tests/Splat.DryIoc.Tests.csproj @@ -4,6 +4,7 @@ net5.0;netcoreapp3.1 $(NoWarn);1591;CA1707;SA1633;CA2000 latest + enable diff --git a/src/Splat.DryIoc/DryIocDependencyResolver.cs b/src/Splat.DryIoc/DryIocDependencyResolver.cs index 6f34301e3..01ef6f113 100644 --- a/src/Splat.DryIoc/DryIocDependencyResolver.cs +++ b/src/Splat.DryIoc/DryIocDependencyResolver.cs @@ -29,10 +29,10 @@ public DryIocDependencyResolver(IContainer? container = null) } /// - public virtual object? GetService(Type serviceType, string? contract = null) => + public virtual object GetService(Type serviceType, string? contract = null) => string.IsNullOrEmpty(contract) - ? _container.ResolveMany(serviceType).LastOrDefault() - : _container.ResolveMany(serviceType, serviceKey: contract).LastOrDefault(); + ? _container.ResolveMany(serviceType).LastOrDefault()! + : _container.ResolveMany(serviceType, serviceKey: contract).LastOrDefault()!; /// public virtual IEnumerable GetServices(Type serviceType, string? contract = null) => @@ -61,7 +61,7 @@ public bool HasRegistration(Type serviceType, string? contract = null) } /// - public virtual void Register(Func factory, Type serviceType, string? contract = null) + public virtual void Register(Func factory, Type serviceType, string? contract = null) { if (factory is null) { diff --git a/src/Splat.Microsoft.Extensions.DependencyInjection.Tests/ContainerWrapper.cs b/src/Splat.Microsoft.Extensions.DependencyInjection.Tests/ContainerWrapper.cs index 99955ebf5..2a979dbdc 100644 --- a/src/Splat.Microsoft.Extensions.DependencyInjection.Tests/ContainerWrapper.cs +++ b/src/Splat.Microsoft.Extensions.DependencyInjection.Tests/ContainerWrapper.cs @@ -9,7 +9,10 @@ internal class ContainerWrapper { private IServiceProvider _serviceProvider; +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. + public ContainerWrapper() +#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. { ServiceCollection.UseMicrosoftDependencyResolver(); } diff --git a/src/Splat.Microsoft.Extensions.DependencyInjection.Tests/MicrosoftDependencyResolverTests.cs b/src/Splat.Microsoft.Extensions.DependencyInjection.Tests/MicrosoftDependencyResolverTests.cs index 5d9db677d..ac8ba8066 100644 --- a/src/Splat.Microsoft.Extensions.DependencyInjection.Tests/MicrosoftDependencyResolverTests.cs +++ b/src/Splat.Microsoft.Extensions.DependencyInjection.Tests/MicrosoftDependencyResolverTests.cs @@ -21,16 +21,16 @@ public void Can_Register_And_Resolve_Null_Types() { var resolver = GetDependencyResolver(); var foo = 5; - resolver.Register(() => foo, null); + resolver.Register(() => foo, null!); - var value = resolver.GetService(null); + var value = resolver.GetService(null!); Assert.Equal(foo, value); var bar = 4; var contract = "foo"; - resolver.Register(() => bar, null, contract); + resolver.Register(() => bar, null!, contract); - value = resolver.GetService(null, contract); + value = resolver.GetService(null!, contract); Assert.Equal(bar, value); } diff --git a/src/Splat.Microsoft.Extensions.DependencyInjection.Tests/Splat.Microsoft.Extensions.DependencyInjection.Tests.csproj b/src/Splat.Microsoft.Extensions.DependencyInjection.Tests/Splat.Microsoft.Extensions.DependencyInjection.Tests.csproj index 98b3b9f3a..d0f943ee3 100644 --- a/src/Splat.Microsoft.Extensions.DependencyInjection.Tests/Splat.Microsoft.Extensions.DependencyInjection.Tests.csproj +++ b/src/Splat.Microsoft.Extensions.DependencyInjection.Tests/Splat.Microsoft.Extensions.DependencyInjection.Tests.csproj @@ -5,6 +5,7 @@ $(NoWarn);1591;CA1707;SA1633;CA2000 false latest + enable diff --git a/src/Splat.Microsoft.Extensions.DependencyInjection/MicrosoftDependencyResolver.cs b/src/Splat.Microsoft.Extensions.DependencyInjection/MicrosoftDependencyResolver.cs index 7a393e659..faa7bdeb5 100644 --- a/src/Splat.Microsoft.Extensions.DependencyInjection/MicrosoftDependencyResolver.cs +++ b/src/Splat.Microsoft.Extensions.DependencyInjection/MicrosoftDependencyResolver.cs @@ -85,8 +85,8 @@ public void UpdateContainer(IServiceProvider serviceProvider) } /// - public virtual object? GetService(Type serviceType, string? contract = null) => - GetServices(serviceType, contract).LastOrDefault(); + public virtual object GetService(Type serviceType, string? contract = null) => + GetServices(serviceType, contract).LastOrDefault()!; /// public virtual IEnumerable GetServices(Type serviceType, string? contract = null) @@ -106,7 +106,7 @@ public virtual IEnumerable GetServices(Type serviceType, string? contrac { services = services .Cast() - .Select(nst => nst.Factory()); + .Select(nst => nst.Factory()!); } } else @@ -122,7 +122,10 @@ public virtual IEnumerable GetServices(Type serviceType, string? contrac } /// +#pragma warning disable CS8614 // Nullability of reference types in type of parameter doesn't match implicitly implemented member. + public virtual void Register(Func factory, Type serviceType, string? contract = null) +#pragma warning restore CS8614 // Nullability of reference types in type of parameter doesn't match implicitly implemented member. { if (_isImmutable) { @@ -143,7 +146,7 @@ public virtual void Register(Func factory, Type serviceType, string? con _serviceCollection?.AddTransient(serviceType, _ => isNull ? new NullServiceType(factory) - : factory()); + : factory()!); } else { diff --git a/src/Splat.Ninject.Tests/NInjectDependencyResolverTests.cs b/src/Splat.Ninject.Tests/NInjectDependencyResolverTests.cs index 751938ecc..a9ad149b7 100644 --- a/src/Splat.Ninject.Tests/NInjectDependencyResolverTests.cs +++ b/src/Splat.Ninject.Tests/NInjectDependencyResolverTests.cs @@ -22,16 +22,16 @@ public void Can_Register_And_Resolve_Null_Types() { var resolver = GetDependencyResolver(); var foo = 5; - resolver.Register(() => foo, null); + resolver.Register(() => foo, null!); - var value = resolver.GetService(null); + var value = resolver.GetService(null!); Assert.Equal(foo, value); var bar = 4; var contract = "foo"; - resolver.Register(() => bar, null, contract); + resolver.Register(() => bar, null!, contract); - value = resolver.GetService(null, contract); + value = resolver.GetService(null!, contract); Assert.Equal(bar, value); } diff --git a/src/Splat.Ninject.Tests/Splat.Ninject.Tests.csproj b/src/Splat.Ninject.Tests/Splat.Ninject.Tests.csproj index e95153654..891b3a251 100644 --- a/src/Splat.Ninject.Tests/Splat.Ninject.Tests.csproj +++ b/src/Splat.Ninject.Tests/Splat.Ninject.Tests.csproj @@ -5,6 +5,7 @@ $(NoWarn);1591;CA1707;SA1633;CA2000 false latest + enable diff --git a/src/Splat.Ninject/NinjectDependencyResolver.cs b/src/Splat.Ninject/NinjectDependencyResolver.cs index b3b5bc2a4..def0224d0 100644 --- a/src/Splat.Ninject/NinjectDependencyResolver.cs +++ b/src/Splat.Ninject/NinjectDependencyResolver.cs @@ -30,8 +30,8 @@ public NinjectDependencyResolver(IKernel kernel) } /// - public virtual object? GetService(Type serviceType, string? contract = null) => - GetServices(serviceType, contract)?.LastOrDefault(); + public virtual object GetService(Type serviceType, string? contract = null) => + GetServices(serviceType, contract).LastOrDefault()!; /// public virtual IEnumerable GetServices(Type serviceType, string? contract = null) @@ -61,7 +61,7 @@ public bool HasRegistration(Type serviceType, string? contract = null) } /// - public virtual void Register(Func factory, Type serviceType, string? contract = null) + public virtual void Register(Func factory, Type serviceType, string? contract = null) { var isNull = serviceType is null; @@ -170,12 +170,12 @@ private static bool IsCorrectMetadata(global::Ninject.Planning.Bindings.IBinding [SuppressMessage("Design", "CA1812: Uninitialized class.", Justification = "Used in reflection.")] private class NullServiceType { - public NullServiceType(Func factory) + public NullServiceType(Func factory) { Factory = factory; } - public Func Factory { get; } + public Func Factory { get; } } } } diff --git a/src/Splat.Prism.Tests/Splat.Prism.Tests.csproj b/src/Splat.Prism.Tests/Splat.Prism.Tests.csproj index 3112e0e86..9798eae14 100644 --- a/src/Splat.Prism.Tests/Splat.Prism.Tests.csproj +++ b/src/Splat.Prism.Tests/Splat.Prism.Tests.csproj @@ -4,6 +4,7 @@ net5.0;netcoreapp3.1 $(NoWarn);CA1707;CS1574 latest + enable diff --git a/src/Splat.Prism/SplatContainerExtension.cs b/src/Splat.Prism/SplatContainerExtension.cs index 11652f106..2fd7a47ac 100644 --- a/src/Splat.Prism/SplatContainerExtension.cs +++ b/src/Splat.Prism/SplatContainerExtension.cs @@ -240,42 +240,42 @@ public IContainerRegistry RegisterSingleton(Type type, Func - public object? Resolve(Type type) + public object Resolve(Type type) { return Instance.GetService(type); } /// - public object? Resolve(Type type, params (Type Type, object Instance)[] parameters) + public object Resolve(Type type, params (Type Type, object Instance)[] parameters) { if (_types.TryGetValue((type, null), out var resolvedType)) { return Activator.CreateInstance(resolvedType, parameters.Select(x => x.Instance)) ?? throw new InvalidOperationException("Could not create type"); } - return null; + return null!; } /// - public object? Resolve(Type type, string name) + public object Resolve(Type type, string name) { return Instance.GetService(type, name); } /// - public object? Resolve(Type type, string name, params (Type Type, object Instance)[] parameters) + public object Resolve(Type type, string name, params (Type Type, object Instance)[] parameters) { if (!_types.TryGetValue((type, name), out var resolvedType)) { if (resolvedType is null) { - return null; + return null!; } - return Activator.CreateInstance(resolvedType, parameters.Select(x => x.Instance)); + return Activator.CreateInstance(resolvedType, parameters.Select(x => x.Instance))!; } - return null; + return null!; } /// diff --git a/src/Splat.SimpleInjector.Tests/DependencyResolverTests.cs b/src/Splat.SimpleInjector.Tests/DependencyResolverTests.cs index 308e48ce7..e6e1d24dc 100644 --- a/src/Splat.SimpleInjector.Tests/DependencyResolverTests.cs +++ b/src/Splat.SimpleInjector.Tests/DependencyResolverTests.cs @@ -94,7 +94,7 @@ public void SimpleInjectorDependencyResolver_ShouldResolveSplatRegisteredDepende Locator.CurrentMutable.InitializeSplat(); container.UseSimpleInjectorDependencyResolver(initializer); - ILogger dependency = Locator.Current.GetService(typeof(ILogger)) as ILogger; + var dependency = Locator.Current.GetService(typeof(ILogger)) as ILogger; Assert.NotNull(dependency); } diff --git a/src/Splat.SimpleInjector.Tests/Splat.SimpleInjector.Tests.csproj b/src/Splat.SimpleInjector.Tests/Splat.SimpleInjector.Tests.csproj index e284ec60d..bab1213df 100644 --- a/src/Splat.SimpleInjector.Tests/Splat.SimpleInjector.Tests.csproj +++ b/src/Splat.SimpleInjector.Tests/Splat.SimpleInjector.Tests.csproj @@ -4,6 +4,7 @@ net5.0;netcoreapp3.1 $(NoWarn);1591;CA1707;SA1633;CA2000 latest + enable diff --git a/src/Splat.SimpleInjector/SimpleInjectorDependencyResolver.cs b/src/Splat.SimpleInjector/SimpleInjectorDependencyResolver.cs index 1d88f6161..04cdcbc20 100644 --- a/src/Splat.SimpleInjector/SimpleInjectorDependencyResolver.cs +++ b/src/Splat.SimpleInjector/SimpleInjectorDependencyResolver.cs @@ -32,7 +32,7 @@ public SimpleInjectorDependencyResolver(Container container, SimpleInjectorIniti } /// - public object? GetService(Type serviceType, string? contract = null) + public object GetService(Type serviceType, string? contract = null) { try { @@ -43,11 +43,11 @@ public SimpleInjectorDependencyResolver(Container container, SimpleInjectorIniti } IEnumerable registers = _container.GetAllInstances(serviceType); - return registers.LastOrDefault(); + return registers.LastOrDefault()!; } catch { - return null; + return null!; } } @@ -77,7 +77,7 @@ public bool HasRegistration(Type serviceType, string? contract = null) } /// - public void Register(Func factory, Type serviceType, string? contract = null) + public void Register(Func factory, Type serviceType, string? contract = null) { // The function does nothing because there should be no registration called on this object. // Anyway, Locator.SetLocator performs some unnecessary registrations. @@ -122,7 +122,7 @@ protected virtual void Dispose(bool disposing) private void RegisterFactories(SimpleInjectorInitializer initializer) { - foreach (KeyValuePair>> typeFactories in initializer.RegisteredFactories) + foreach (KeyValuePair>> typeFactories in initializer.RegisteredFactories) { _container.Collection.Register( typeFactories.Key, diff --git a/src/Splat.SimpleInjector/SimpleInjectorInitializer.cs b/src/Splat.SimpleInjector/SimpleInjectorInitializer.cs index 2ee89e190..1daf4536f 100644 --- a/src/Splat.SimpleInjector/SimpleInjectorInitializer.cs +++ b/src/Splat.SimpleInjector/SimpleInjectorInitializer.cs @@ -20,16 +20,16 @@ public class SimpleInjectorInitializer : IDependencyResolver /// /// Gets dictionary of registered factories. /// - public Dictionary>> RegisteredFactories { get; } + public Dictionary>> RegisteredFactories { get; } = new(); /// - public object? GetService(Type serviceType, string? contract = null) + public object GetService(Type serviceType, string? contract = null) { lock (_lockObject) { - Func? fact = RegisteredFactories[serviceType].LastOrDefault(); - return fact?.Invoke(); + Func? fact = RegisteredFactories[serviceType].LastOrDefault(); + return fact?.Invoke()!; } } @@ -39,7 +39,7 @@ public IEnumerable GetServices(Type serviceType, string? contract = null lock (_lockObject) { return RegisteredFactories[serviceType] - .Select(n => n()); + .Select(n => n()!); } } @@ -54,13 +54,13 @@ public bool HasRegistration(Type serviceType, string? contract = null) } /// - public void Register(Func factory, Type serviceType, string? contract = null) + public void Register(Func factory, Type serviceType, string? contract = null) { lock (_lockObject) { if (!RegisteredFactories.ContainsKey(serviceType)) { - RegisteredFactories.Add(serviceType, new List>()); + RegisteredFactories.Add(serviceType, new List>()); } RegisteredFactories[serviceType].Add(factory); @@ -92,12 +92,10 @@ public IDisposable ServiceRegistrationCallback(Type serviceType, string? contrac } /// -#pragma warning disable CA1063 // Implement IDisposable Correctly public void Dispose() -#pragma warning restore CA1063 // Implement IDisposable Correctly { - GC.SuppressFinalize(this); Dispose(true); + GC.SuppressFinalize(this); } /// diff --git a/src/Splat.SimpleInjector/TransientSimpleInjectorRegistration.cs b/src/Splat.SimpleInjector/TransientSimpleInjectorRegistration.cs index 8852cf33c..39b93b65c 100644 --- a/src/Splat.SimpleInjector/TransientSimpleInjectorRegistration.cs +++ b/src/Splat.SimpleInjector/TransientSimpleInjectorRegistration.cs @@ -11,8 +11,8 @@ namespace Splat.SimpleInjector { internal class TransientSimpleInjectorRegistration : Registration { - public TransientSimpleInjectorRegistration(Container container, Type implementationType, Func? instanceCreator = null) - : base(Lifestyle.Transient, container, implementationType, instanceCreator) + public TransientSimpleInjectorRegistration(Container container, Type implementationType, Func? instanceCreator = null) + : base(Lifestyle.Transient, container, implementationType, instanceCreator!) { } diff --git a/src/Splat.Tests/API/ApiApprovalTests.SplatProject.net5.0.approved.txt b/src/Splat.Tests/API/ApiApprovalTests.SplatProject.net5.0.approved.txt index c11747f59..6dcb5fd12 100644 --- a/src/Splat.Tests/API/ApiApprovalTests.SplatProject.net5.0.approved.txt +++ b/src/Splat.Tests/API/ApiApprovalTests.SplatProject.net5.0.approved.txt @@ -159,15 +159,15 @@ namespace Splat } public static class DependencyResolverMixins { - public static T? GetService(this Splat.IReadonlyDependencyResolver resolver, string? contract = null) { } + public static T GetService(this Splat.IReadonlyDependencyResolver resolver, string? contract = null) { } public static System.Collections.Generic.IEnumerable GetServices(this Splat.IReadonlyDependencyResolver resolver, string? contract = null) { } - public static void Register(this Splat.IMutableDependencyResolver resolver, System.Func factory, string? contract = null) + public static void Register(this Splat.IMutableDependencyResolver resolver, System.Func factory, string? contract = null) where T : notnull { } - public static void RegisterConstant(this Splat.IMutableDependencyResolver resolver, object value, System.Type serviceType, string? contract = null) { } + public static void RegisterConstant(this Splat.IMutableDependencyResolver resolver, object? value, System.Type serviceType, string? contract = null) { } public static void RegisterConstant(this Splat.IMutableDependencyResolver resolver, T value, string? contract = null) where T : notnull { } - public static void RegisterLazySingleton(this Splat.IMutableDependencyResolver resolver, System.Func valueFactory, System.Type serviceType, string? contract = null) { } - public static void RegisterLazySingleton(this Splat.IMutableDependencyResolver resolver, System.Func valueFactory, string? contract = null) + public static void RegisterLazySingleton(this Splat.IMutableDependencyResolver resolver, System.Func valueFactory, System.Type serviceType, string? contract = null) { } + public static void RegisterLazySingleton(this Splat.IMutableDependencyResolver resolver, System.Func valueFactory, string? contract = null) where T : notnull { } public static System.IDisposable ServiceRegistrationCallback(this Splat.IMutableDependencyResolver resolver, System.Type serviceType, System.Action callback) { } public static void UnregisterAll(this Splat.IMutableDependencyResolver resolver, string? contract = null) { } @@ -194,13 +194,13 @@ namespace Splat } public class FuncDependencyResolver : Splat.IDependencyResolver, Splat.IMutableDependencyResolver, Splat.IReadonlyDependencyResolver, System.IDisposable { - public FuncDependencyResolver(System.Func> getAllServices, System.Action, System.Type, string?>? register = null, System.Action? unregisterCurrent = null, System.Action? unregisterAll = null, System.IDisposable? toDispose = null) { } + public FuncDependencyResolver(System.Func> getAllServices, System.Action, System.Type, string?>? register = null, System.Action? unregisterCurrent = null, System.Action? unregisterAll = null, System.IDisposable? toDispose = null) { } public void Dispose() { } protected virtual void Dispose(bool isDisposing) { } - public object? GetService(System.Type serviceType, string? contract = null) { } + public object GetService(System.Type serviceType, string? contract = null) { } public System.Collections.Generic.IEnumerable GetServices(System.Type serviceType, string? contract = null) { } public bool HasRegistration(System.Type serviceType, string? contract = null) { } - public void Register(System.Func factory, System.Type serviceType, string? contract = null) { } + public void Register(System.Func factory, System.Type serviceType, string? contract = null) { } public System.IDisposable ServiceRegistrationCallback(System.Type serviceType, string? contract, System.Action callback) { } public void UnregisterAll(System.Type serviceType, string? contract = null) { } public void UnregisterCurrent(System.Type serviceType, string? contract = null) { } @@ -411,14 +411,14 @@ namespace Splat public interface IMutableDependencyResolver { bool HasRegistration(System.Type serviceType, string? contract = null); - void Register(System.Func factory, System.Type serviceType, string? contract = null); + void Register(System.Func factory, System.Type serviceType, string? contract = null); System.IDisposable ServiceRegistrationCallback(System.Type serviceType, string? contract, System.Action callback); void UnregisterAll(System.Type serviceType, string? contract = null); void UnregisterCurrent(System.Type serviceType, string? contract = null); } public interface IReadonlyDependencyResolver { - object? GetService(System.Type serviceType, string? contract = null); + object GetService(System.Type serviceType, string? contract = null); System.Collections.Generic.IEnumerable GetServices(System.Type serviceType, string? contract = null); } public interface IStaticFullLogger @@ -519,14 +519,14 @@ namespace Splat public ModernDependencyResolver() { } protected ModernDependencyResolver([System.Runtime.CompilerServices.TupleElementNames(new string[] { "serviceType", - "contract"})] System.Collections.Generic.Dictionary, System.Collections.Generic.List>>? registry) { } + "contract"})] System.Collections.Generic.Dictionary, System.Collections.Generic.List>>? registry) { } public void Dispose() { } protected virtual void Dispose(bool isDisposing) { } public Splat.ModernDependencyResolver Duplicate() { } - public object? GetService(System.Type serviceType, string? contract = null) { } + public object GetService(System.Type serviceType, string? contract = null) { } public System.Collections.Generic.IEnumerable GetServices(System.Type serviceType, string? contract = null) { } public bool HasRegistration(System.Type serviceType, string? contract = null) { } - public void Register(System.Func factory, System.Type serviceType, string? contract = null) { } + public void Register(System.Func factory, System.Type serviceType, string? contract = null) { } public System.IDisposable ServiceRegistrationCallback(System.Type serviceType, string? contract, System.Action callback) { } public void UnregisterAll(System.Type serviceType, string? contract = null) { } public void UnregisterCurrent(System.Type serviceType, string? contract = null) { } diff --git a/src/Splat.Tests/API/ApiApprovalTests.SplatProject.netcoreapp3.1.approved.txt b/src/Splat.Tests/API/ApiApprovalTests.SplatProject.netcoreapp3.1.approved.txt index 2b7497bd6..09114069b 100644 --- a/src/Splat.Tests/API/ApiApprovalTests.SplatProject.netcoreapp3.1.approved.txt +++ b/src/Splat.Tests/API/ApiApprovalTests.SplatProject.netcoreapp3.1.approved.txt @@ -159,15 +159,15 @@ namespace Splat } public static class DependencyResolverMixins { - public static T? GetService(this Splat.IReadonlyDependencyResolver resolver, string? contract = null) { } + public static T GetService(this Splat.IReadonlyDependencyResolver resolver, string? contract = null) { } public static System.Collections.Generic.IEnumerable GetServices(this Splat.IReadonlyDependencyResolver resolver, string? contract = null) { } - public static void Register(this Splat.IMutableDependencyResolver resolver, System.Func factory, string? contract = null) + public static void Register(this Splat.IMutableDependencyResolver resolver, System.Func factory, string? contract = null) where T : notnull { } - public static void RegisterConstant(this Splat.IMutableDependencyResolver resolver, object value, System.Type serviceType, string? contract = null) { } + public static void RegisterConstant(this Splat.IMutableDependencyResolver resolver, object? value, System.Type serviceType, string? contract = null) { } public static void RegisterConstant(this Splat.IMutableDependencyResolver resolver, T value, string? contract = null) where T : notnull { } - public static void RegisterLazySingleton(this Splat.IMutableDependencyResolver resolver, System.Func valueFactory, System.Type serviceType, string? contract = null) { } - public static void RegisterLazySingleton(this Splat.IMutableDependencyResolver resolver, System.Func valueFactory, string? contract = null) + public static void RegisterLazySingleton(this Splat.IMutableDependencyResolver resolver, System.Func valueFactory, System.Type serviceType, string? contract = null) { } + public static void RegisterLazySingleton(this Splat.IMutableDependencyResolver resolver, System.Func valueFactory, string? contract = null) where T : notnull { } public static System.IDisposable ServiceRegistrationCallback(this Splat.IMutableDependencyResolver resolver, System.Type serviceType, System.Action callback) { } public static void UnregisterAll(this Splat.IMutableDependencyResolver resolver, string? contract = null) { } @@ -194,13 +194,13 @@ namespace Splat } public class FuncDependencyResolver : Splat.IDependencyResolver, Splat.IMutableDependencyResolver, Splat.IReadonlyDependencyResolver, System.IDisposable { - public FuncDependencyResolver(System.Func> getAllServices, System.Action, System.Type, string?>? register = null, System.Action? unregisterCurrent = null, System.Action? unregisterAll = null, System.IDisposable? toDispose = null) { } + public FuncDependencyResolver(System.Func> getAllServices, System.Action, System.Type, string?>? register = null, System.Action? unregisterCurrent = null, System.Action? unregisterAll = null, System.IDisposable? toDispose = null) { } public void Dispose() { } protected virtual void Dispose(bool isDisposing) { } - public object? GetService(System.Type serviceType, string? contract = null) { } + public object GetService(System.Type serviceType, string? contract = null) { } public System.Collections.Generic.IEnumerable GetServices(System.Type serviceType, string? contract = null) { } public bool HasRegistration(System.Type serviceType, string? contract = null) { } - public void Register(System.Func factory, System.Type serviceType, string? contract = null) { } + public void Register(System.Func factory, System.Type serviceType, string? contract = null) { } public System.IDisposable ServiceRegistrationCallback(System.Type serviceType, string? contract, System.Action callback) { } public void UnregisterAll(System.Type serviceType, string? contract = null) { } public void UnregisterCurrent(System.Type serviceType, string? contract = null) { } @@ -411,14 +411,14 @@ namespace Splat public interface IMutableDependencyResolver { bool HasRegistration(System.Type serviceType, string? contract = null); - void Register(System.Func factory, System.Type serviceType, string? contract = null); + void Register(System.Func factory, System.Type serviceType, string? contract = null); System.IDisposable ServiceRegistrationCallback(System.Type serviceType, string? contract, System.Action callback); void UnregisterAll(System.Type serviceType, string? contract = null); void UnregisterCurrent(System.Type serviceType, string? contract = null); } public interface IReadonlyDependencyResolver { - object? GetService(System.Type serviceType, string? contract = null); + object GetService(System.Type serviceType, string? contract = null); System.Collections.Generic.IEnumerable GetServices(System.Type serviceType, string? contract = null); } public interface IStaticFullLogger @@ -519,14 +519,14 @@ namespace Splat public ModernDependencyResolver() { } protected ModernDependencyResolver([System.Runtime.CompilerServices.TupleElementNames(new string[] { "serviceType", - "contract"})] System.Collections.Generic.Dictionary, System.Collections.Generic.List>>? registry) { } + "contract"})] System.Collections.Generic.Dictionary, System.Collections.Generic.List>>? registry) { } public void Dispose() { } protected virtual void Dispose(bool isDisposing) { } public Splat.ModernDependencyResolver Duplicate() { } - public object? GetService(System.Type serviceType, string? contract = null) { } + public object GetService(System.Type serviceType, string? contract = null) { } public System.Collections.Generic.IEnumerable GetServices(System.Type serviceType, string? contract = null) { } public bool HasRegistration(System.Type serviceType, string? contract = null) { } - public void Register(System.Func factory, System.Type serviceType, string? contract = null) { } + public void Register(System.Func factory, System.Type serviceType, string? contract = null) { } public System.IDisposable ServiceRegistrationCallback(System.Type serviceType, string? contract, System.Action callback) { } public void UnregisterAll(System.Type serviceType, string? contract = null) { } public void UnregisterCurrent(System.Type serviceType, string? contract = null) { } diff --git a/src/Splat.Tests/ApiExtensions.cs b/src/Splat.Tests/ApiExtensions.cs index 290e7551c..7eebd562d 100644 --- a/src/Splat.Tests/ApiExtensions.cs +++ b/src/Splat.Tests/ApiExtensions.cs @@ -34,14 +34,14 @@ public static class ApiExtensions /// The assembly that is being checked. /// The caller member. /// The caller file path. - public static void CheckApproval(this Assembly assembly, [CallerMemberName] string memberName = null, [CallerFilePath] string filePath = null) + public static void CheckApproval(this Assembly assembly, [CallerMemberName] string? memberName = null, [CallerFilePath] string? filePath = null) { var targetFrameworkName = Assembly.GetExecutingAssembly().GetTargetFrameworkName(); var sourceDirectory = Path.GetDirectoryName(filePath); - var approvedFileName = Path.Combine(sourceDirectory, $"ApiApprovalTests.{memberName}.{targetFrameworkName}.approved.txt"); - var receivedFileName = Path.Combine(sourceDirectory, $"ApiApprovalTests.{memberName}.{targetFrameworkName}.received.txt"); + var approvedFileName = Path.Combine(sourceDirectory!, $"ApiApprovalTests.{memberName}.{targetFrameworkName}.approved.txt"); + var receivedFileName = Path.Combine(sourceDirectory!, $"ApiApprovalTests.{memberName}.{targetFrameworkName}.received.txt"); string approvedPublicApi = string.Empty; diff --git a/src/Splat.Tests/ApplicationPerformanceMonitoring/BaseFeatureUsageTrackingTests.cs b/src/Splat.Tests/ApplicationPerformanceMonitoring/BaseFeatureUsageTrackingTests.cs index 183afcf00..072601f75 100644 --- a/src/Splat.Tests/ApplicationPerformanceMonitoring/BaseFeatureUsageTrackingTests.cs +++ b/src/Splat.Tests/ApplicationPerformanceMonitoring/BaseFeatureUsageTrackingTests.cs @@ -71,9 +71,9 @@ public void ReturnsInstance() var genericSubfeature = subfeature as IFeatureUsageTrackingSession; Assert.NotNull(genericSubfeature); - Assert.Equal(subfeatureName, genericSubfeature.FeatureName); - Assert.NotEqual(Guid.Empty, genericSubfeature.FeatureReference); - Assert.Equal(instance.FeatureReference, genericSubfeature.ParentReference); + Assert.Equal(subfeatureName, genericSubfeature?.FeatureName); + Assert.NotEqual(Guid.Empty, genericSubfeature?.FeatureReference); + Assert.Equal(instance.FeatureReference, genericSubfeature?.ParentReference); } /// diff --git a/src/Splat.Tests/LocatorTests.cs b/src/Splat.Tests/LocatorTests.cs index 64e83bfd3..4e88200f0 100644 --- a/src/Splat.Tests/LocatorTests.cs +++ b/src/Splat.Tests/LocatorTests.cs @@ -280,15 +280,15 @@ public void ModernDependencyResolver_UnregisterCurrent_NoValuesWorks() public void FuncDependencyResolver_UnregisterAll() { bool unregisterAllCalled = false; - Type type = null; - string contract = null; + Type? type = null; + string? contract = null; var currentMutable = new FuncDependencyResolver( (funcType, funcContract) => Array.Empty(), unregisterAll: (passedType, passedContract) => { unregisterAllCalled = true; - contract = passedContract; + contract = passedContract!; type = passedType; }); @@ -312,15 +312,15 @@ public void FuncDependencyResolver_UnregisterAll() public void FuncDependencyResolver_UnregisterCurrent() { bool unregisterAllCalled = false; - Type type = null; - string contract = null; + Type? type = null; + string? contract = null; var currentMutable = new FuncDependencyResolver( (funcType, funcContract) => Array.Empty(), unregisterCurrent: (passedType, passedContract) => { unregisterAllCalled = true; - contract = passedContract; + contract = passedContract!; type = passedType; }); diff --git a/src/Splat.Tests/Logging/ActionLoggerTests.cs b/src/Splat.Tests/Logging/ActionLoggerTests.cs index be4c292b2..d5569febc 100644 --- a/src/Splat.Tests/Logging/ActionLoggerTests.cs +++ b/src/Splat.Tests/Logging/ActionLoggerTests.cs @@ -20,7 +20,7 @@ public class ActionLoggerTests [Fact] public void Write_Should_Emit_Message() { - string passedMessage = null; + string? passedMessage = null; LogLevel? passedLevel = null; var logger = new ActionLogger( @@ -29,9 +29,9 @@ public void Write_Should_Emit_Message() passedMessage = message; passedLevel = level; }, - null, - null, - null); + null!, + null!, + null!); var fullLogger = new WrappingFullLogger(logger); @@ -47,20 +47,20 @@ public void Write_Should_Emit_Message() [Fact] public void Debug_With_Generic_Type_Should_Emit_Message_And_Type() { - string passedMessage = null; + string? passedMessage = null; LogLevel? passedLevel = null; - Type passedType = null; + Type? passedType = null; var logger = new ActionLogger( - null, + null!, (message, type, level) => { passedMessage = message; passedType = type; passedLevel = level; }, - null, - null); + null!, + null!); var fullLogger = new WrappingFullLogger(logger); @@ -77,20 +77,20 @@ public void Debug_With_Generic_Type_Should_Emit_Message_And_Type() [Fact] public void Debug_With_Generic_Type_Should_Emit_Message_And_Type_Provided() { - string passedMessage = null; + string? passedMessage = null; LogLevel? passedLevel = null; - Type passedType = null; + Type? passedType = null; var logger = new ActionLogger( - null, + null!, (message, type, level) => { passedMessage = message; passedType = type; passedLevel = level; }, - null, - null); + null!, + null!); var fullLogger = new WrappingFullLogger(logger); @@ -107,20 +107,20 @@ public void Debug_With_Generic_Type_Should_Emit_Message_And_Type_Provided() [Fact] public void Info_With_Generic_Type_Should_Emit_Message_And_Type() { - string passedMessage = null; + string? passedMessage = null; LogLevel? passedLevel = null; - Type passedType = null; + Type? passedType = null; var logger = new ActionLogger( - null, + null!, (message, type, level) => { passedMessage = message; passedType = type; passedLevel = level; }, - null, - null); + null!, + null!); var fullLogger = new WrappingFullLogger(logger); @@ -137,20 +137,20 @@ public void Info_With_Generic_Type_Should_Emit_Message_And_Type() [Fact] public void Info_With_Generic_Type_Should_Emit_Message_And_Type_Provided() { - string passedMessage = null; + string? passedMessage = null; LogLevel? passedLevel = null; - Type passedType = null; + Type? passedType = null; var logger = new ActionLogger( - null, + null!, (message, type, level) => { passedMessage = message; passedType = type; passedLevel = level; }, - null, - null); + null!, + null!); var fullLogger = new WrappingFullLogger(logger); @@ -167,20 +167,20 @@ public void Info_With_Generic_Type_Should_Emit_Message_And_Type_Provided() [Fact] public void Warn_With_Generic_Type_Should_Emit_Message_And_Type() { - string passedMessage = null; + string? passedMessage = null; LogLevel? passedLevel = null; - Type passedType = null; + Type? passedType = null; var logger = new ActionLogger( - null, + null!, (message, type, level) => { passedMessage = message; passedType = type; passedLevel = level; }, - null, - null); + null!, + null!); var fullLogger = new WrappingFullLogger(logger); @@ -197,20 +197,20 @@ public void Warn_With_Generic_Type_Should_Emit_Message_And_Type() [Fact] public void Warn_With_Generic_Type_Should_Emit_Message_And_Type_Provided() { - string passedMessage = null; + string? passedMessage = null; LogLevel? passedLevel = null; - Type passedType = null; + Type? passedType = null; var logger = new ActionLogger( - null, + null!, (message, type, level) => { passedMessage = message; passedType = type; passedLevel = level; }, - null, - null); + null!, + null!); var fullLogger = new WrappingFullLogger(logger); @@ -227,20 +227,20 @@ public void Warn_With_Generic_Type_Should_Emit_Message_And_Type_Provided() [Fact] public void Error_With_Generic_Type_Should_Emit_Message_And_Type() { - string passedMessage = null; + string? passedMessage = null; LogLevel? passedLevel = null; - Type passedType = null; + Type? passedType = null; var logger = new ActionLogger( - null, + null!, (message, type, level) => { passedMessage = message; passedType = type; passedLevel = level; }, - null, - null); + null!, + null!); var fullLogger = new WrappingFullLogger(logger); @@ -257,20 +257,20 @@ public void Error_With_Generic_Type_Should_Emit_Message_And_Type() [Fact] public void Error_With_Generic_Type_Should_Emit_Message_And_Type_Provided() { - string passedMessage = null; + string? passedMessage = null; LogLevel? passedLevel = null; - Type passedType = null; + Type? passedType = null; var logger = new ActionLogger( - null, + null!, (message, type, level) => { passedMessage = message; passedType = type; passedLevel = level; }, - null, - null); + null!, + null!); var fullLogger = new WrappingFullLogger(logger); @@ -287,20 +287,20 @@ public void Error_With_Generic_Type_Should_Emit_Message_And_Type_Provided() [Fact] public void Fatal_With_Generic_Type_Should_Emit_Message_And_Type() { - string passedMessage = null; + string? passedMessage = null; LogLevel? passedLevel = null; - Type passedType = null; + Type? passedType = null; var logger = new ActionLogger( - null, + null!, (message, type, level) => { passedMessage = message; passedType = type; passedLevel = level; }, - null, - null); + null!, + null!); var fullLogger = new WrappingFullLogger(logger); @@ -317,20 +317,20 @@ public void Fatal_With_Generic_Type_Should_Emit_Message_And_Type() [Fact] public void Fatal_With_Generic_Type_Should_Emit_Message_And_Type_Provided() { - string passedMessage = null; + string? passedMessage = null; LogLevel? passedLevel = null; - Type passedType = null; + Type? passedType = null; var logger = new ActionLogger( - null, + null!, (message, type, level) => { passedMessage = message; passedType = type; passedLevel = level; }, - null, - null); + null!, + null!); var fullLogger = new WrappingFullLogger(logger); diff --git a/src/Splat.Tests/Logging/FullLoggers/SerilogLoggerTests.cs b/src/Splat.Tests/Logging/FullLoggers/SerilogLoggerTests.cs index 6484bd6f2..729498be6 100644 --- a/src/Splat.Tests/Logging/FullLoggers/SerilogLoggerTests.cs +++ b/src/Splat.Tests/Logging/FullLoggers/SerilogLoggerTests.cs @@ -30,25 +30,25 @@ public class SerilogLoggerTests : FullLoggerTestBase /// Gets a list of mappings of Serilog levels and equivalent Splat log levels. /// private static readonly Dictionary _mappingsToSerilog = new() - { - { LogLevel.Debug, LogEventLevel.Debug }, - { LogLevel.Info, LogEventLevel.Information }, - { LogLevel.Warn, LogEventLevel.Warning }, - { LogLevel.Error, LogEventLevel.Error }, - { LogLevel.Fatal, LogEventLevel.Fatal } - }; + { + { LogLevel.Debug, LogEventLevel.Debug }, + { LogLevel.Info, LogEventLevel.Information }, + { LogLevel.Warn, LogEventLevel.Warning }, + { LogLevel.Error, LogEventLevel.Error }, + { LogLevel.Fatal, LogEventLevel.Fatal } + }; /// /// Gets a list of mappings of Serilog levels and equivalent Splat log levels. /// private static readonly Dictionary _mappingsToSplat = new() - { - { LogEventLevel.Debug, LogLevel.Debug }, - { LogEventLevel.Information, LogLevel.Info }, - { LogEventLevel.Warning, LogLevel.Warn }, - { LogEventLevel.Error, LogLevel.Error }, - { LogEventLevel.Fatal, LogLevel.Fatal } - }; + { + { LogEventLevel.Debug, LogLevel.Debug }, + { LogEventLevel.Information, LogLevel.Info }, + { LogEventLevel.Warning, LogLevel.Warn }, + { LogEventLevel.Error, LogLevel.Error }, + { LogEventLevel.Fatal, LogLevel.Fatal } + }; /// /// Test to make sure the calling `UseSerilogWithWrappingFullLogger` logs. @@ -67,11 +67,11 @@ public void Configuring_With_Static_Log_Should_Write_Message() Assert.Equal(0, target.Logs.Count); - IEnableLogger logger = null; + IEnableLogger logger = null!; logger.Log().Debug("This is a test."); Assert.Equal(1, target.Logs.Count); - Assert.Equal("This is a test.", target.Logs.Last().message.Trim(NewLine).Trim()); + Assert.Equal("This is a test.", target.Logs.Last().message!.Trim(NewLine).Trim()); } finally { @@ -94,12 +94,12 @@ public void Configuring_With_PreConfigured_Log_Should_Write_Message() Assert.Equal(0, target.Logs.Count); - IEnableLogger logger = null; + IEnableLogger logger = null!; logger.Log().Debug("This is a test."); Assert.Equal(1, target.Logs.Count); - Assert.Equal("This is a test.", target.Logs.Last().message.Trim(NewLine).Trim()); + Assert.Equal("This is a test.", target.Logs.Last().message!.Trim(NewLine).Trim()); } finally { diff --git a/src/Splat.Tests/Logging/WrappingFullLoggers/ConsoleLoggerTests.cs b/src/Splat.Tests/Logging/WrappingFullLoggers/ConsoleLoggerTests.cs index cc6f890c4..fe7da580a 100644 --- a/src/Splat.Tests/Logging/WrappingFullLoggers/ConsoleLoggerTests.cs +++ b/src/Splat.Tests/Logging/WrappingFullLoggers/ConsoleLoggerTests.cs @@ -35,9 +35,9 @@ private class ConsoleWriter : TextWriter, IMockLogTarget public ICollection<(LogLevel logLevel, string message)> Logs => _logs; - public override void WriteLine(string value) + public override void WriteLine(string? value) { - var colonIndex = value.IndexOf(":", StringComparison.InvariantCulture); + var colonIndex = value!.IndexOf(":", StringComparison.InvariantCulture); var level = (LogLevel)Enum.Parse(typeof(LogLevel), value.Substring(0, colonIndex)); var message = value.Substring(colonIndex + 1).Trim(); _logs.Add((level, message)); diff --git a/src/Splat.Tests/Logging/WrappingFullLoggers/ExceptionlessLoggerTests.cs b/src/Splat.Tests/Logging/WrappingFullLoggers/ExceptionlessLoggerTests.cs index 07acb36af..dc0e30f67 100644 --- a/src/Splat.Tests/Logging/WrappingFullLoggers/ExceptionlessLoggerTests.cs +++ b/src/Splat.Tests/Logging/WrappingFullLoggers/ExceptionlessLoggerTests.cs @@ -25,19 +25,19 @@ public class ExceptionlessLoggerTests : FullLoggerTestBase private static readonly Dictionary _exceptionless2Splat = new() { { global::Exceptionless.Logging.LogLevel.Debug, LogLevel.Debug }, - { global::Exceptionless.Logging.LogLevel.Info, LogLevel.Info }, - { global::Exceptionless.Logging.LogLevel.Warn, LogLevel.Warn }, + { global::Exceptionless.Logging.LogLevel.Info, LogLevel.Info }, + { global::Exceptionless.Logging.LogLevel.Warn, LogLevel.Warn }, { global::Exceptionless.Logging.LogLevel.Error, LogLevel.Error }, { global::Exceptionless.Logging.LogLevel.Fatal, LogLevel.Fatal }, }; private static readonly Dictionary _splat2Exceptionless = new() { - { LogLevel.Debug, global::Exceptionless.Logging.LogLevel.Debug }, - { LogLevel.Info, global::Exceptionless.Logging.LogLevel.Info }, - { LogLevel.Warn, global::Exceptionless.Logging.LogLevel.Warn }, - { LogLevel.Error, global::Exceptionless.Logging.LogLevel.Error }, - { LogLevel.Fatal, global::Exceptionless.Logging.LogLevel.Fatal }, + { LogLevel.Debug, global::Exceptionless.Logging.LogLevel.Debug }, + { LogLevel.Info, global::Exceptionless.Logging.LogLevel.Info }, + { LogLevel.Warn, global::Exceptionless.Logging.LogLevel.Warn }, + { LogLevel.Error, global::Exceptionless.Logging.LogLevel.Error }, + { LogLevel.Fatal, global::Exceptionless.Logging.LogLevel.Fatal }, }; /// @@ -71,7 +71,7 @@ private static void PluginAction(EventPluginContext obj, InMemoryExceptionlessLo var level = obj.Event.Data.GetValueOrDefault(Event.KnownDataKeys.Level) as string; - var logLevel = global::Exceptionless.Logging.LogLevel.FromString(level); + var logLevel = global::Exceptionless.Logging.LogLevel.FromString(level!); var splatLogLevel = GetSplatLogLevel(logLevel); var exception = obj.ContextData.HasException() ? obj.ContextData.GetException() : null; diff --git a/src/Splat.Tests/Logging/WrappingFullLoggers/Log4NetLoggerTests.cs b/src/Splat.Tests/Logging/WrappingFullLoggers/Log4NetLoggerTests.cs index 1406f1a99..84feaba19 100644 --- a/src/Splat.Tests/Logging/WrappingFullLoggers/Log4NetLoggerTests.cs +++ b/src/Splat.Tests/Logging/WrappingFullLoggers/Log4NetLoggerTests.cs @@ -27,19 +27,19 @@ public class Log4NetLoggerTests : FullLoggerTestBase private static readonly Dictionary _log4Net2Splat = new() { { Level.Debug, LogLevel.Debug }, - { Level.Info, LogLevel.Info }, - { Level.Warn, LogLevel.Warn }, + { Level.Info, LogLevel.Info }, + { Level.Warn, LogLevel.Warn }, { Level.Error, LogLevel.Error }, { Level.Fatal, LogLevel.Fatal }, }; private static readonly Dictionary _splat2log4net = new() { - { LogLevel.Debug, Level.Debug }, - { LogLevel.Info, Level.Info }, - { LogLevel.Warn, Level.Warn }, - { LogLevel.Error, Level.Error }, - { LogLevel.Fatal, Level.Fatal }, + { LogLevel.Debug, Level.Debug }, + { LogLevel.Info, Level.Info }, + { LogLevel.Warn, Level.Warn }, + { LogLevel.Error, Level.Error }, + { LogLevel.Fatal, Level.Fatal }, }; /// @@ -106,7 +106,7 @@ public MemoryTargetWrapper(global::log4net.Appender.MemoryAppender memoryTarget) return (currentLevel, $"{x.MessageObject} {x.ExceptionObject}"); } - return (currentLevel, x.MessageObject.ToString()); + return (currentLevel, x.MessageObject.ToString()!); }).ToList(); } } diff --git a/src/Splat.Tests/MemoizingMRUCacheTests.cs b/src/Splat.Tests/MemoizingMRUCacheTests.cs index 1920a5910..712eedac6 100644 --- a/src/Splat.Tests/MemoizingMRUCacheTests.cs +++ b/src/Splat.Tests/MemoizingMRUCacheTests.cs @@ -22,7 +22,7 @@ public class MemoizingMRUCacheTests public void ThrowsArgumentNullException() { var instance = GetTestInstance(); - Assert.Throws(() => instance.Get(null)); + Assert.Throws(() => instance.Get(null!)); } /// diff --git a/src/Splat.Tests/Splat.Tests.csproj b/src/Splat.Tests/Splat.Tests.csproj index 88b9f9b32..652f69dc2 100644 --- a/src/Splat.Tests/Splat.Tests.csproj +++ b/src/Splat.Tests/Splat.Tests.csproj @@ -4,6 +4,8 @@ net5.0;netcoreapp3.1 $(NoWarn);1591;CA1707;SA1633;CA2000;CA1034 latest + latest + enable diff --git a/src/Splat.Tests/XUnitHelpers.cs b/src/Splat.Tests/XUnitHelpers.cs index d443a9d0e..1d99ec80d 100644 --- a/src/Splat.Tests/XUnitHelpers.cs +++ b/src/Splat.Tests/XUnitHelpers.cs @@ -25,7 +25,7 @@ public static IEnumerable GetEnumAsTestTheory() var results = new List(values.Length); foreach (var value in values) { - results.Add(new[] { value }); + results.Add(new[] { value! }); } return results; diff --git a/src/Splat/ServiceLocation/DependencyResolverMixins.cs b/src/Splat/ServiceLocation/DependencyResolverMixins.cs index be913d30e..347036721 100644 --- a/src/Splat/ServiceLocation/DependencyResolverMixins.cs +++ b/src/Splat/ServiceLocation/DependencyResolverMixins.cs @@ -24,14 +24,14 @@ public static class DependencyResolverMixins /// The resolver we are getting the service from. /// A optional value which will retrieve only a object registered with the same contract. /// The requested object, if found; null otherwise. - public static T? GetService(this IReadonlyDependencyResolver resolver, string? contract = null) + public static T GetService(this IReadonlyDependencyResolver resolver, string? contract = null) { if (resolver is null) { throw new ArgumentNullException(nameof(resolver)); } - return (T?)resolver.GetService(typeof(T), contract); + return (T)resolver.GetService(typeof(T), contract); } /// @@ -99,7 +99,7 @@ public static IDisposable WithResolver(this IDependencyResolver resolver, bool s /// The resolver to register the service type with. /// A factory method for generating a object of the specified type. /// A optional contract value which will indicates to only generate the value if this contract is specified. - public static void Register(this IMutableDependencyResolver resolver, Func factory, string? contract = null) + public static void Register(this IMutableDependencyResolver resolver, Func factory, string? contract = null) where T : notnull { if (resolver is null) @@ -122,7 +122,7 @@ public static void Register(this IMutableDependencyResolver resolver, Func /// The specified instance to always return. /// The type of service to register. /// A optional contract value which will indicates to only return the value if this contract is specified. - public static void RegisterConstant(this IMutableDependencyResolver resolver, object value, Type serviceType, string? contract = null) + public static void RegisterConstant(this IMutableDependencyResolver resolver, object? value, Type serviceType, string? contract = null) { if (resolver is null) { @@ -158,14 +158,14 @@ public static void RegisterConstant(this IMutableDependencyResolver resolver, /// A factory method for generating a object of the specified type. /// The type of service to register. /// A optional contract value which will indicates to only return the value if this contract is specified. - public static void RegisterLazySingleton(this IMutableDependencyResolver resolver, Func valueFactory, Type serviceType, string? contract = null) + public static void RegisterLazySingleton(this IMutableDependencyResolver resolver, Func valueFactory, Type serviceType, string? contract = null) { if (resolver is null) { throw new ArgumentNullException(nameof(resolver)); } - var val = new Lazy(valueFactory, LazyThreadSafetyMode.ExecutionAndPublication); + var val = new Lazy(valueFactory, LazyThreadSafetyMode.ExecutionAndPublication); resolver.Register(() => val.Value, serviceType, contract); } @@ -177,7 +177,7 @@ public static void RegisterLazySingleton(this IMutableDependencyResolver resolve /// The resolver to register the service type with. /// A factory method for generating a object of the specified type. /// A optional contract value which will indicates to only return the value if this contract is specified. - public static void RegisterLazySingleton(this IMutableDependencyResolver resolver, Func valueFactory, string? contract = null) + public static void RegisterLazySingleton(this IMutableDependencyResolver resolver, Func valueFactory, string? contract = null) where T : notnull { RegisterLazySingleton(resolver, () => valueFactory(), typeof(T), contract); diff --git a/src/Splat/ServiceLocation/FuncDependencyResolver.cs b/src/Splat/ServiceLocation/FuncDependencyResolver.cs index 4b898ad4e..fd846751b 100644 --- a/src/Splat/ServiceLocation/FuncDependencyResolver.cs +++ b/src/Splat/ServiceLocation/FuncDependencyResolver.cs @@ -18,7 +18,7 @@ namespace Splat public class FuncDependencyResolver : IDependencyResolver { private readonly Func> _innerGetServices; - private readonly Action, Type, string?>? _innerRegister; + private readonly Action, Type, string?>? _innerRegister; private readonly Action? _unregisterCurrent; private readonly Action? _unregisterAll; private readonly Dictionary<(Type type, string callback), List>> _callbackRegistry = new(); @@ -36,7 +36,7 @@ public class FuncDependencyResolver : IDependencyResolver /// A optional disposable which is called when this resolver is disposed. public FuncDependencyResolver( Func> getAllServices, - Action, Type, string?>? register = null, + Action, Type, string?>? register = null, Action? unregisterCurrent = null, Action? unregisterAll = null, IDisposable? toDispose = null) @@ -49,9 +49,9 @@ public FuncDependencyResolver( } /// - public object? GetService(Type serviceType, string? contract = null) + public object GetService(Type serviceType, string? contract = null) { - return (GetServices(serviceType, contract) ?? Enumerable.Empty()).LastOrDefault(); + return (GetServices(serviceType, contract) ?? Enumerable.Empty()).LastOrDefault()!; } /// @@ -67,7 +67,7 @@ public bool HasRegistration(Type serviceType, string? contract = null) } /// - public void Register(Func factory, Type serviceType, string? contract = null) + public void Register(Func factory, Type serviceType, string? contract = null) { if (_innerRegister is null) { diff --git a/src/Splat/ServiceLocation/IMutableDependencyResolver.cs b/src/Splat/ServiceLocation/IMutableDependencyResolver.cs index 82f301417..234114b30 100644 --- a/src/Splat/ServiceLocation/IMutableDependencyResolver.cs +++ b/src/Splat/ServiceLocation/IMutableDependencyResolver.cs @@ -30,7 +30,7 @@ public interface IMutableDependencyResolver /// The factory function which generates our object. /// The type which is used for the registration. /// A optional contract value which will indicates to only generate the value if this contract is specified. - void Register(Func factory, Type serviceType, string? contract = null); + void Register(Func factory, Type serviceType, string? contract = null); /// /// Unregisters the current item based on the specified type and contract. diff --git a/src/Splat/ServiceLocation/IReadonlyDependencyResolver.cs b/src/Splat/ServiceLocation/IReadonlyDependencyResolver.cs index 868e84b0c..e03b7c2b2 100644 --- a/src/Splat/ServiceLocation/IReadonlyDependencyResolver.cs +++ b/src/Splat/ServiceLocation/IReadonlyDependencyResolver.cs @@ -19,7 +19,7 @@ public interface IReadonlyDependencyResolver /// The object type. /// A optional value which will retrieve only a object registered with the same contract. /// The requested object, if found; null otherwise. - object? GetService(Type serviceType, string? contract = null); + object GetService(Type serviceType, string? contract = null); /// /// Gets all instances of the given . Must return an empty diff --git a/src/Splat/ServiceLocation/ModernDependencyResolver.cs b/src/Splat/ServiceLocation/ModernDependencyResolver.cs index a4cdece1b..bae3f0031 100644 --- a/src/Splat/ServiceLocation/ModernDependencyResolver.cs +++ b/src/Splat/ServiceLocation/ModernDependencyResolver.cs @@ -24,7 +24,7 @@ namespace Splat /// public class ModernDependencyResolver : IDependencyResolver { - private Dictionary<(Type serviceType, string contract), List>>? _registry; + private Dictionary<(Type serviceType, string contract), List>>? _registry; private Dictionary<(Type serviceType, string contract), List>> _callbackRegistry; private bool _isDisposed; @@ -41,11 +41,11 @@ public ModernDependencyResolver() /// Initializes a new instance of the class. /// /// A registry of services. - protected ModernDependencyResolver(Dictionary<(Type serviceType, string contract), List>>? registry) + protected ModernDependencyResolver(Dictionary<(Type serviceType, string contract), List>>? registry) { _registry = registry is not null ? registry.ToDictionary(k => k.Key, v => v.Value.ToList()) : - new Dictionary<(Type serviceType, string contract), List>>(); + new Dictionary<(Type serviceType, string contract), List>>(); _callbackRegistry = new Dictionary<(Type serviceType, string contract), List>>(); } @@ -63,7 +63,7 @@ public bool HasRegistration(Type serviceType, string? contract = null) } /// - public void Register(Func factory, Type serviceType, string? contract = null) + public void Register(Func factory, Type serviceType, string? contract = null) { var pair = GetKey(serviceType, contract); @@ -74,7 +74,7 @@ public void Register(Func factory, Type serviceType, string? contract = if (!_registry.ContainsKey(pair)) { - _registry[pair] = new List>(); + _registry[pair] = new List>(); } _registry[pair].Add(factory); @@ -111,21 +111,21 @@ public void Register(Func factory, Type serviceType, string? contract = } /// - public object? GetService(Type serviceType, string? contract = null) + public object GetService(Type serviceType, string? contract = null) { if (_registry is null) { - return default; + return null!; } var pair = GetKey(serviceType, contract); if (!_registry.ContainsKey(pair)) { - return default; + return null!; } var ret = _registry[pair].LastOrDefault(); - return ret is null ? null : ret(); + return (ret is null ? null : ret())!; } /// @@ -142,7 +142,7 @@ public IEnumerable GetServices(Type serviceType, string? contract = null return Enumerable.Empty(); } - return _registry[pair].Select(x => x()).ToList(); + return _registry[pair].Select(x => x()!).ToList(); } /// @@ -179,7 +179,7 @@ public void UnregisterAll(Type serviceType, string? contract = null) var pair = GetKey(serviceType, contract); - _registry[pair] = new List>(); + _registry[pair] = new List>(); } /// From dea9b8e8b83862e45b4747ab788ed95af4c03ea0 Mon Sep 17 00:00:00 2001 From: Chris Pulman Date: Thu, 1 Jul 2021 04:29:51 +0100 Subject: [PATCH 2/9] Added tests to prove nullable types can be registered and will return null if not valid housekeeping on tests fix ILogManager_Resolvable test --- .../AutofacDependencyResolver.cs | 2 +- .../DummyObjectClass1.cs | 2 +- .../DummyObjectClass2.cs | 2 +- .../DummyObjectClass3.cs | 2 +- .../IDummyInterface.cs | 2 +- src/Splat.Common.Test/IViewFor.cs | 7 +- src/Splat.Common.Test/ViewOne.cs | 6 +- src/Splat.Common.Test/ViewTwo.cs | 6 +- .../ContainerWrapper.cs | 13 +--- .../DependencyResolverTests.cs | 25 ++++++- .../MicrosoftDependencyResolverTests.cs | 1 + ...xtensions.DependencyInjection.Tests.csproj | 1 + .../DependencyResolverTests.cs | 15 ++++ ...ovalTests.SplatProject.net5.0.approved.txt | 9 +-- ...ts.SplatProject.netcoreapp3.1.approved.txt | 9 +-- src/Splat.Tests/LocatorTests.cs | 72 +++++++++++++++++++ .../BaseDependencyResolverTests.cs | 21 ++++-- src/Splat.Tests/Splat.Tests.csproj | 1 + .../DependencyResolverMixins.cs | 5 +- .../ModernDependencyResolver.cs | 21 +++--- 20 files changed, 162 insertions(+), 60 deletions(-) rename src/{Splat.Tests/Mocks => Splat.Common.Test}/DummyObjectClass1.cs (88%) rename src/{Splat.Tests/Mocks => Splat.Common.Test}/DummyObjectClass2.cs (88%) rename src/{Splat.Tests/Mocks => Splat.Common.Test}/DummyObjectClass3.cs (88%) rename src/{Splat.Tests/Mocks => Splat.Common.Test}/IDummyInterface.cs (91%) diff --git a/src/Splat.Autofac/AutofacDependencyResolver.cs b/src/Splat.Autofac/AutofacDependencyResolver.cs index ee6bafbcc..c2ef3160d 100644 --- a/src/Splat.Autofac/AutofacDependencyResolver.cs +++ b/src/Splat.Autofac/AutofacDependencyResolver.cs @@ -126,7 +126,7 @@ public bool HasRegistration(Type serviceType, string? contract = null) /// Register a function with the resolver which will generate a object /// for the specified service type. /// Optionally a contract can be registered which will indicate - /// that that registration will only work with that contract. + /// that registration will only work with that contract. /// Most implementations will use a stack based approach to allow for multiple items to be registered. /// /// The factory function which generates our object. diff --git a/src/Splat.Tests/Mocks/DummyObjectClass1.cs b/src/Splat.Common.Test/DummyObjectClass1.cs similarity index 88% rename from src/Splat.Tests/Mocks/DummyObjectClass1.cs rename to src/Splat.Common.Test/DummyObjectClass1.cs index 93c79a77f..74ded1409 100644 --- a/src/Splat.Tests/Mocks/DummyObjectClass1.cs +++ b/src/Splat.Common.Test/DummyObjectClass1.cs @@ -8,7 +8,7 @@ namespace Splat.Tests.Mocks /// /// A dummy class used during Locator testing. /// - internal class DummyObjectClass1 : IDummyInterface + public class DummyObjectClass1 : IDummyInterface { } } diff --git a/src/Splat.Tests/Mocks/DummyObjectClass2.cs b/src/Splat.Common.Test/DummyObjectClass2.cs similarity index 88% rename from src/Splat.Tests/Mocks/DummyObjectClass2.cs rename to src/Splat.Common.Test/DummyObjectClass2.cs index c10eef6e4..468f1ffc1 100644 --- a/src/Splat.Tests/Mocks/DummyObjectClass2.cs +++ b/src/Splat.Common.Test/DummyObjectClass2.cs @@ -8,7 +8,7 @@ namespace Splat.Tests.Mocks /// /// A dummy class used during Locator testing. /// - internal class DummyObjectClass2 : IDummyInterface + public class DummyObjectClass2 : IDummyInterface { } } diff --git a/src/Splat.Tests/Mocks/DummyObjectClass3.cs b/src/Splat.Common.Test/DummyObjectClass3.cs similarity index 88% rename from src/Splat.Tests/Mocks/DummyObjectClass3.cs rename to src/Splat.Common.Test/DummyObjectClass3.cs index e96171868..c98e40fc2 100644 --- a/src/Splat.Tests/Mocks/DummyObjectClass3.cs +++ b/src/Splat.Common.Test/DummyObjectClass3.cs @@ -8,7 +8,7 @@ namespace Splat.Tests.Mocks /// /// A dummy class used during Locator testing. /// - internal class DummyObjectClass3 : IDummyInterface + public class DummyObjectClass3 : IDummyInterface { } } diff --git a/src/Splat.Tests/Mocks/IDummyInterface.cs b/src/Splat.Common.Test/IDummyInterface.cs similarity index 91% rename from src/Splat.Tests/Mocks/IDummyInterface.cs rename to src/Splat.Common.Test/IDummyInterface.cs index fd654087b..10befa033 100644 --- a/src/Splat.Tests/Mocks/IDummyInterface.cs +++ b/src/Splat.Common.Test/IDummyInterface.cs @@ -8,7 +8,7 @@ namespace Splat.Tests.Mocks /// /// A dummy interface used during Locator testing. /// - internal interface IDummyInterface + public interface IDummyInterface { } } diff --git a/src/Splat.Common.Test/IViewFor.cs b/src/Splat.Common.Test/IViewFor.cs index 0e668263c..2bb25ef3d 100644 --- a/src/Splat.Common.Test/IViewFor.cs +++ b/src/Splat.Common.Test/IViewFor.cs @@ -6,17 +6,19 @@ namespace Splat.Common.Test { #pragma warning disable SA1402 // File may only contain a single type + /// /// Represents a view bound to a view model. /// /// The view model type. /// public interface IViewFor : IViewFor + where T : class { /// /// Gets or sets the view model. /// - new T ViewModel { get; set; } + new T? ViewModel { get; set; } } /// @@ -28,7 +30,8 @@ public interface IViewFor /// /// Gets or sets the view model. /// - object ViewModel { get; set; } + object? ViewModel { get; set; } } + #pragma warning restore SA1402 // File may only contain a single type } diff --git a/src/Splat.Common.Test/ViewOne.cs b/src/Splat.Common.Test/ViewOne.cs index f318b6dc9..62ce609dc 100644 --- a/src/Splat.Common.Test/ViewOne.cs +++ b/src/Splat.Common.Test/ViewOne.cs @@ -12,13 +12,13 @@ namespace Splat.Common.Test public class ViewOne : IViewFor { /// - object IViewFor.ViewModel + object? IViewFor.ViewModel { get => ViewModel; - set => ViewModel = (ViewModelOne)value; + set => ViewModel = (ViewModelOne?)value; } /// - public ViewModelOne ViewModel { get; set; } + public ViewModelOne? ViewModel { get; set; } } } diff --git a/src/Splat.Common.Test/ViewTwo.cs b/src/Splat.Common.Test/ViewTwo.cs index 218c89527..550495fa3 100644 --- a/src/Splat.Common.Test/ViewTwo.cs +++ b/src/Splat.Common.Test/ViewTwo.cs @@ -12,13 +12,13 @@ namespace Splat.Common.Test public class ViewTwo : IViewFor { /// - object IViewFor.ViewModel + object? IViewFor.ViewModel { get => ViewModel; - set => ViewModel = (ViewModelTwo)value; + set => ViewModel = (ViewModelTwo?)value; } /// - public ViewModelTwo ViewModel { get; set; } + public ViewModelTwo? ViewModel { get; set; } } } diff --git a/src/Splat.Microsoft.Extensions.DependencyInjection.Tests/ContainerWrapper.cs b/src/Splat.Microsoft.Extensions.DependencyInjection.Tests/ContainerWrapper.cs index 2a979dbdc..051d4038b 100644 --- a/src/Splat.Microsoft.Extensions.DependencyInjection.Tests/ContainerWrapper.cs +++ b/src/Splat.Microsoft.Extensions.DependencyInjection.Tests/ContainerWrapper.cs @@ -19,18 +19,7 @@ public ContainerWrapper() public IServiceCollection ServiceCollection { get; } = new ServiceCollection(); - public IServiceProvider ServiceProvider - { - get - { - if (_serviceProvider is null) - { - _serviceProvider = ServiceCollection.BuildServiceProvider(); - } - - return _serviceProvider; - } - } + public IServiceProvider ServiceProvider => _serviceProvider ??= ServiceCollection.BuildServiceProvider(); public void BuildAndUse() => ServiceProvider.UseMicrosoftDependencyResolver(); } diff --git a/src/Splat.Microsoft.Extensions.DependencyInjection.Tests/DependencyResolverTests.cs b/src/Splat.Microsoft.Extensions.DependencyInjection.Tests/DependencyResolverTests.cs index af21e3401..9734ab191 100644 --- a/src/Splat.Microsoft.Extensions.DependencyInjection.Tests/DependencyResolverTests.cs +++ b/src/Splat.Microsoft.Extensions.DependencyInjection.Tests/DependencyResolverTests.cs @@ -10,7 +10,7 @@ using Microsoft.Extensions.DependencyInjection; using Splat.Common.Test; - +using Splat.NLog; using Xunit; namespace Splat.Microsoft.Extensions.DependencyInjection.Tests @@ -147,5 +147,28 @@ public void MicrosoftDependencyResolver_Should_Throw_If_Attempt_Registration_Aft result.Should().BeOfType(); } + + /// + /// Tests to ensure NLog registers correctly with different service locators. + /// Based on issue reported in #553. + /// + [Fact] + public void ILogManager_Resolvable() + { + var wrapper = new ContainerWrapper(); + var services = wrapper.ServiceCollection; + + // Setup NLog for Logging (doesn't matter if I actually configure NLog or not) + var funcLogManager = new FuncLogManager(type => new NLogLogger(LogResolver.Resolve(type))); + services.AddSingleton(funcLogManager); + + wrapper.BuildAndUse(); + + // Get the ILogManager instance. + ILogManager lm = Locator.Current.GetService(); + + var mgr = lm.GetLogger(); + Assert.NotNull(mgr); + } } } diff --git a/src/Splat.Microsoft.Extensions.DependencyInjection.Tests/MicrosoftDependencyResolverTests.cs b/src/Splat.Microsoft.Extensions.DependencyInjection.Tests/MicrosoftDependencyResolverTests.cs index ac8ba8066..4fe4936db 100644 --- a/src/Splat.Microsoft.Extensions.DependencyInjection.Tests/MicrosoftDependencyResolverTests.cs +++ b/src/Splat.Microsoft.Extensions.DependencyInjection.Tests/MicrosoftDependencyResolverTests.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Text; +using Microsoft.Extensions.DependencyInjection; using Splat.Microsoft.Extensions.DependencyInjection; using Xunit; diff --git a/src/Splat.Microsoft.Extensions.DependencyInjection.Tests/Splat.Microsoft.Extensions.DependencyInjection.Tests.csproj b/src/Splat.Microsoft.Extensions.DependencyInjection.Tests/Splat.Microsoft.Extensions.DependencyInjection.Tests.csproj index d0f943ee3..62b413b00 100644 --- a/src/Splat.Microsoft.Extensions.DependencyInjection.Tests/Splat.Microsoft.Extensions.DependencyInjection.Tests.csproj +++ b/src/Splat.Microsoft.Extensions.DependencyInjection.Tests/Splat.Microsoft.Extensions.DependencyInjection.Tests.csproj @@ -9,6 +9,7 @@ + diff --git a/src/Splat.SimpleInjector.Tests/DependencyResolverTests.cs b/src/Splat.SimpleInjector.Tests/DependencyResolverTests.cs index e6e1d24dc..f88fc1a28 100644 --- a/src/Splat.SimpleInjector.Tests/DependencyResolverTests.cs +++ b/src/Splat.SimpleInjector.Tests/DependencyResolverTests.cs @@ -35,6 +35,21 @@ public void SimpleInjectorDependencyResolver_Should_Resolve_View_Model() viewModel.Should().BeOfType(); } + /// + /// Simples the injector dependency resolver should resolve a view model. + /// + [Fact] + public void SimpleInjectorDependencyResolver_Should_Resolve_View_Model_Directly() + { + var container = new SimpleInjectorInitializer(); + container.Register(() => new ViewModelOne()); + + var viewModel = container.GetService(); + + viewModel.Should().NotBeNull(); + viewModel.Should().BeOfType(); + } + /// /// Simples the injector dependency resolver should resolve a view. /// diff --git a/src/Splat.Tests/API/ApiApprovalTests.SplatProject.net5.0.approved.txt b/src/Splat.Tests/API/ApiApprovalTests.SplatProject.net5.0.approved.txt index 6dcb5fd12..be7ae737b 100644 --- a/src/Splat.Tests/API/ApiApprovalTests.SplatProject.net5.0.approved.txt +++ b/src/Splat.Tests/API/ApiApprovalTests.SplatProject.net5.0.approved.txt @@ -161,14 +161,11 @@ namespace Splat { public static T GetService(this Splat.IReadonlyDependencyResolver resolver, string? contract = null) { } public static System.Collections.Generic.IEnumerable GetServices(this Splat.IReadonlyDependencyResolver resolver, string? contract = null) { } - public static void Register(this Splat.IMutableDependencyResolver resolver, System.Func factory, string? contract = null) - where T : notnull { } + public static void Register(this Splat.IMutableDependencyResolver resolver, System.Func factory, string? contract = null) { } public static void RegisterConstant(this Splat.IMutableDependencyResolver resolver, object? value, System.Type serviceType, string? contract = null) { } - public static void RegisterConstant(this Splat.IMutableDependencyResolver resolver, T value, string? contract = null) - where T : notnull { } + public static void RegisterConstant(this Splat.IMutableDependencyResolver resolver, T? value, string? contract = null) { } public static void RegisterLazySingleton(this Splat.IMutableDependencyResolver resolver, System.Func valueFactory, System.Type serviceType, string? contract = null) { } - public static void RegisterLazySingleton(this Splat.IMutableDependencyResolver resolver, System.Func valueFactory, string? contract = null) - where T : notnull { } + public static void RegisterLazySingleton(this Splat.IMutableDependencyResolver resolver, System.Func valueFactory, string? contract = null) { } public static System.IDisposable ServiceRegistrationCallback(this Splat.IMutableDependencyResolver resolver, System.Type serviceType, System.Action callback) { } public static void UnregisterAll(this Splat.IMutableDependencyResolver resolver, string? contract = null) { } public static void UnregisterCurrent(this Splat.IMutableDependencyResolver resolver, string? contract = null) { } diff --git a/src/Splat.Tests/API/ApiApprovalTests.SplatProject.netcoreapp3.1.approved.txt b/src/Splat.Tests/API/ApiApprovalTests.SplatProject.netcoreapp3.1.approved.txt index 09114069b..bf07b4649 100644 --- a/src/Splat.Tests/API/ApiApprovalTests.SplatProject.netcoreapp3.1.approved.txt +++ b/src/Splat.Tests/API/ApiApprovalTests.SplatProject.netcoreapp3.1.approved.txt @@ -161,14 +161,11 @@ namespace Splat { public static T GetService(this Splat.IReadonlyDependencyResolver resolver, string? contract = null) { } public static System.Collections.Generic.IEnumerable GetServices(this Splat.IReadonlyDependencyResolver resolver, string? contract = null) { } - public static void Register(this Splat.IMutableDependencyResolver resolver, System.Func factory, string? contract = null) - where T : notnull { } + public static void Register(this Splat.IMutableDependencyResolver resolver, System.Func factory, string? contract = null) { } public static void RegisterConstant(this Splat.IMutableDependencyResolver resolver, object? value, System.Type serviceType, string? contract = null) { } - public static void RegisterConstant(this Splat.IMutableDependencyResolver resolver, T value, string? contract = null) - where T : notnull { } + public static void RegisterConstant(this Splat.IMutableDependencyResolver resolver, T? value, string? contract = null) { } public static void RegisterLazySingleton(this Splat.IMutableDependencyResolver resolver, System.Func valueFactory, System.Type serviceType, string? contract = null) { } - public static void RegisterLazySingleton(this Splat.IMutableDependencyResolver resolver, System.Func valueFactory, string? contract = null) - where T : notnull { } + public static void RegisterLazySingleton(this Splat.IMutableDependencyResolver resolver, System.Func valueFactory, string? contract = null) { } public static System.IDisposable ServiceRegistrationCallback(this Splat.IMutableDependencyResolver resolver, System.Type serviceType, System.Action callback) { } public static void UnregisterAll(this Splat.IMutableDependencyResolver resolver, string? contract = null) { } public static void UnregisterCurrent(this Splat.IMutableDependencyResolver resolver, string? contract = null) { } diff --git a/src/Splat.Tests/LocatorTests.cs b/src/Splat.Tests/LocatorTests.cs index 4e88200f0..5157af9af 100644 --- a/src/Splat.Tests/LocatorTests.cs +++ b/src/Splat.Tests/LocatorTests.cs @@ -49,6 +49,20 @@ public void InitializeSplat_ContractRegistrationsNullNoRegistration() Assert.Null(logger); } + /// + /// Tests that if we use a contract it returns null entries for that type. + /// + [Fact] + public void InitializeSplat_ContractRegistrationsExtensionMethodsNullNoRegistration() + { + var testLocator = new InternalLocator(); + var logManager = testLocator.Current.GetService("test"); + var logger = testLocator.Current.GetService("test"); + + Assert.Null(logManager); + Assert.Null(logger); + } + /// /// Tests using the extension methods that the retrieving of the default InitializeSplat() still work. /// @@ -197,6 +211,64 @@ public void ModernDependencyResolver_UnregisterAll_WithValuesWorks() } } + /// + /// Nullables the type. + /// + [Fact] + public void RegisterAndResolveANullableTypeWithValue() + { + Locator.CurrentMutable.Register(() => new()); + var doc = Locator.Current.GetService(); + doc.Should().BeOfType(); + } + + /// + /// Nullables the type. + /// + [Fact] + public void RegisterAndResolveANullableTypeWithNull() + { + Locator.CurrentMutable.Register(() => null); + var doc = Locator.Current.GetService(); + doc.Should().BeNull(); + } + + /// + /// Nullables the type. + /// + [Fact] + public void RegisterAndResolveANullableTypeWithValueLocatorDisposed() + { + var currentMutable = new ModernDependencyResolver(); + currentMutable.Register(() => new()); + currentMutable.Dispose(); + var doc = currentMutable.GetService(); + doc.Should().BeNull(); + } + + /// + /// Nullables the type. + /// + [Fact] + public void RegisterAndResolveANullableTypeWithDefault() + { + Locator.CurrentMutable.Register(() => default); + var doc = Locator.Current.GetService(); + doc.Should().BeNull(); + } + + /// + /// Nullables the type. + /// + [Fact] + public void RegisterAndResolveANullableTypeWithNulledInstance() + { + DummyObjectClass1? dummy = null; + Locator.CurrentMutable.Register(() => dummy); + var doc = Locator.Current.GetService(); + doc.Should().BeNull(); + } + /// /// Tests to make sure that the unregister all functions correctly. /// This is a test when there are values not registered. diff --git a/src/Splat.Tests/ServiceLocation/BaseDependencyResolverTests.cs b/src/Splat.Tests/ServiceLocation/BaseDependencyResolverTests.cs index 1f4f036da..c2ffbc6f4 100644 --- a/src/Splat.Tests/ServiceLocation/BaseDependencyResolverTests.cs +++ b/src/Splat.Tests/ServiceLocation/BaseDependencyResolverTests.cs @@ -151,12 +151,21 @@ public void ILogManager_Resolvable() { var resolver = GetDependencyResolver(); - // Setup NLog for Logging (doesn't matter if I actually configure NLog or not) - resolver.UseNLogWithWrappingFullLogger(); - - // Get the ILogManager instance (this should succeed, but fails in current code) - ILogManager lm = Locator.Current.GetService(); - Assert.NotNull(lm); + // NOTE:MicrosoftDependencyResolver test for this funtionality is in DependencyResolverTests + if (resolver.GetType().Name != "MicrosoftDependencyResolver") + { + // Setup NLog for Logging (doesn't matter if I actually configure NLog or not) + resolver.UseNLogWithWrappingFullLogger(); + Locator.SetLocator(resolver); + Locator.CurrentMutable.InitializeSplat(); + + // Get the ILogManager instance + var lm = Locator.Current.GetService(); + + // now suceeds for AutoFac, Ninject and Splat + var mgr = lm.GetLogger(); + Assert.NotNull(mgr); + } } /// diff --git a/src/Splat.Tests/Splat.Tests.csproj b/src/Splat.Tests/Splat.Tests.csproj index 652f69dc2..57e448c33 100644 --- a/src/Splat.Tests/Splat.Tests.csproj +++ b/src/Splat.Tests/Splat.Tests.csproj @@ -14,6 +14,7 @@ + diff --git a/src/Splat/ServiceLocation/DependencyResolverMixins.cs b/src/Splat/ServiceLocation/DependencyResolverMixins.cs index 347036721..a3d0d8216 100644 --- a/src/Splat/ServiceLocation/DependencyResolverMixins.cs +++ b/src/Splat/ServiceLocation/DependencyResolverMixins.cs @@ -100,7 +100,6 @@ public static IDisposable WithResolver(this IDependencyResolver resolver, bool s /// A factory method for generating a object of the specified type. /// A optional contract value which will indicates to only generate the value if this contract is specified. public static void Register(this IMutableDependencyResolver resolver, Func factory, string? contract = null) - where T : notnull { if (resolver is null) { @@ -139,8 +138,7 @@ public static void RegisterConstant(this IMutableDependencyResolver resolver, ob /// The resolver to register the service type with. /// The specified instance to always return. /// A optional contract value which will indicates to only return the value if this contract is specified. - public static void RegisterConstant(this IMutableDependencyResolver resolver, T value, string? contract = null) - where T : notnull + public static void RegisterConstant(this IMutableDependencyResolver resolver, T? value, string? contract = null) { if (resolver is null) { @@ -178,7 +176,6 @@ public static void RegisterLazySingleton(this IMutableDependencyResolver resolve /// A factory method for generating a object of the specified type. /// A optional contract value which will indicates to only return the value if this contract is specified. public static void RegisterLazySingleton(this IMutableDependencyResolver resolver, Func valueFactory, string? contract = null) - where T : notnull { RegisterLazySingleton(resolver, () => valueFactory(), typeof(T), contract); } diff --git a/src/Splat/ServiceLocation/ModernDependencyResolver.cs b/src/Splat/ServiceLocation/ModernDependencyResolver.cs index bae3f0031..22c8b3dd7 100644 --- a/src/Splat/ServiceLocation/ModernDependencyResolver.cs +++ b/src/Splat/ServiceLocation/ModernDependencyResolver.cs @@ -11,21 +11,23 @@ namespace Splat { /// + /// /// This class is a dependency resolver written for modern C# 5.0 times. /// It implements all registrations via a Factory method. With the power /// of Closures, you can actually implement most lifetime styles (i.e. /// construct per call, lazy construct, singleton) using this. - /// + /// + /// /// Unless you have a very compelling reason not to, this is the only class /// you need in order to do dependency resolution, don't bother with using /// a full IoC container. - /// - /// This container is not thread safe. + /// + /// This container is not thread safe. /// public class ModernDependencyResolver : IDependencyResolver { + private readonly Dictionary<(Type serviceType, string contract), List>> _callbackRegistry; private Dictionary<(Type serviceType, string contract), List>>? _registry; - private Dictionary<(Type serviceType, string contract), List>> _callbackRegistry; private bool _isDisposed; @@ -91,12 +93,7 @@ public void Register(Func factory, Type serviceType, string? contract = if (disp.IsDisposed) { - if (toRemove is null) - { - toRemove = new List>(); - } - - toRemove.Add(callback); + (toRemove ??= new List>()).Add(callback); } } @@ -125,7 +122,7 @@ public object GetService(Type serviceType, string? contract = null) } var ret = _registry[pair].LastOrDefault(); - return (ret is null ? null : ret())!; + return (ret != null ? ret() : null)!; } /// @@ -142,7 +139,7 @@ public IEnumerable GetServices(Type serviceType, string? contract = null return Enumerable.Empty(); } - return _registry[pair].Select(x => x()!).ToList(); + return _registry[pair].ConvertAll(x => x()!); } /// From 1e0c3d7bc6070113b993c184cb20416789ebbe1e Mon Sep 17 00:00:00 2001 From: Chris Pulman Date: Thu, 1 Jul 2021 06:00:29 +0100 Subject: [PATCH 3/9] Reverted GetService to return object? matched the GetServices to also return IEmeumerable --- .../AutofacDependencyResolver.cs | 10 +++---- src/Splat.DryIoc/DryIocDependencyResolver.cs | 8 +++--- .../MicrosoftDependencyResolver.cs | 19 +++++--------- .../NinjectDependencyResolver.cs | 4 +-- src/Splat.Prism/SplatContainerExtension.cs | 15 +++++------ .../SimpleInjectorDependencyResolver.cs | 8 +++--- .../SimpleInjectorInitializer.cs | 4 +-- ...ovalTests.SplatProject.net5.0.approved.txt | 20 +++++++------- ...ts.SplatProject.netcoreapp3.1.approved.txt | 20 +++++++------- .../DependencyResolverMixins.cs | 8 +++--- .../ServiceLocation/FuncDependencyResolver.cs | 17 +++++------- .../IReadonlyDependencyResolver.cs | 4 +-- .../ModernDependencyResolver.cs | 26 +++++++++---------- 13 files changed, 76 insertions(+), 87 deletions(-) diff --git a/src/Splat.Autofac/AutofacDependencyResolver.cs b/src/Splat.Autofac/AutofacDependencyResolver.cs index c2ef3160d..acec9894a 100644 --- a/src/Splat.Autofac/AutofacDependencyResolver.cs +++ b/src/Splat.Autofac/AutofacDependencyResolver.cs @@ -50,7 +50,7 @@ public AutofacDependencyResolver(ContainerBuilder builder) } /// - public virtual object GetService(Type serviceType, string? contract = null) + public virtual object? GetService(Type serviceType, string? contract = null) { lock (_lockObject) { @@ -83,7 +83,7 @@ public void SetLifetimeScope(ILifetimeScope lifetimeScope) } /// - public virtual IEnumerable GetServices(Type serviceType, string? contract = null) + public virtual IEnumerable GetServices(Type serviceType, string? contract = null) { lock (_lockObject) { @@ -94,14 +94,14 @@ public virtual IEnumerable GetServices(Type serviceType, string? contrac if (instance is null) { - return Array.Empty(); + return Array.Empty(); } - return ((IEnumerable)instance).Cast(); + return ((IEnumerable)instance).Cast(); } catch (DependencyResolutionException) { - return Array.Empty(); + return Array.Empty(); } } } diff --git a/src/Splat.DryIoc/DryIocDependencyResolver.cs b/src/Splat.DryIoc/DryIocDependencyResolver.cs index 01ef6f113..97bbf6cba 100644 --- a/src/Splat.DryIoc/DryIocDependencyResolver.cs +++ b/src/Splat.DryIoc/DryIocDependencyResolver.cs @@ -29,13 +29,13 @@ public DryIocDependencyResolver(IContainer? container = null) } /// - public virtual object GetService(Type serviceType, string? contract = null) => + public virtual object? GetService(Type serviceType, string? contract = null) => string.IsNullOrEmpty(contract) - ? _container.ResolveMany(serviceType).LastOrDefault()! - : _container.ResolveMany(serviceType, serviceKey: contract).LastOrDefault()!; + ? _container.ResolveMany(serviceType).LastOrDefault() + : _container.ResolveMany(serviceType, serviceKey: contract).LastOrDefault(); /// - public virtual IEnumerable GetServices(Type serviceType, string? contract = null) => + public virtual IEnumerable GetServices(Type serviceType, string? contract = null) => string.IsNullOrEmpty(contract) ? _container.ResolveMany(serviceType) : _container.ResolveMany(serviceType, serviceKey: contract); diff --git a/src/Splat.Microsoft.Extensions.DependencyInjection/MicrosoftDependencyResolver.cs b/src/Splat.Microsoft.Extensions.DependencyInjection/MicrosoftDependencyResolver.cs index faa7bdeb5..a00643b38 100644 --- a/src/Splat.Microsoft.Extensions.DependencyInjection/MicrosoftDependencyResolver.cs +++ b/src/Splat.Microsoft.Extensions.DependencyInjection/MicrosoftDependencyResolver.cs @@ -85,11 +85,11 @@ public void UpdateContainer(IServiceProvider serviceProvider) } /// - public virtual object GetService(Type serviceType, string? contract = null) => + public virtual object? GetService(Type serviceType, string? contract = null) => GetServices(serviceType, contract).LastOrDefault()!; /// - public virtual IEnumerable GetServices(Type serviceType, string? contract = null) + public virtual IEnumerable GetServices(Type serviceType, string? contract = null) { var isNull = serviceType is null; if (serviceType is null) @@ -97,11 +97,11 @@ public virtual IEnumerable GetServices(Type serviceType, string? contrac serviceType = typeof(NullServiceType); } - IEnumerable services; + IEnumerable services; if (contract is null || string.IsNullOrWhiteSpace(contract)) { - services = ServiceProvider.GetServices(serviceType).Where(x => x is not null).Select(x => x!); + services = ServiceProvider.GetServices(serviceType); if (isNull) { services = services @@ -115,7 +115,7 @@ public virtual IEnumerable GetServices(Type serviceType, string? contrac services = dic? .GetFactories(contract) .Select(f => f()) - ?? Enumerable.Empty(); + ?? Enumerable.Empty(); } return services; @@ -240,7 +240,7 @@ public virtual void UnregisterAll(Type serviceType, string? contract = null) else { var dic = GetContractDictionary(serviceType, false); - if (dic is not null && dic.TryRemoveContract(contract) && dic.IsEmpty) + if (dic?.TryRemoveContract(contract) == true && dic.IsEmpty) { RemoveContractService(serviceType); } @@ -378,12 +378,7 @@ public IEnumerable> GetFactories(string contract) => public void AddFactory(string contract, Func factory) => _dictionary.AddOrUpdate(contract, _ => new List> { factory }, (_, list) => { - if (list is null) - { - list = new List>(); - } - - list.Add(factory); + (list ??= new List>()).Add(factory); return list; }); diff --git a/src/Splat.Ninject/NinjectDependencyResolver.cs b/src/Splat.Ninject/NinjectDependencyResolver.cs index def0224d0..925137987 100644 --- a/src/Splat.Ninject/NinjectDependencyResolver.cs +++ b/src/Splat.Ninject/NinjectDependencyResolver.cs @@ -30,11 +30,11 @@ public NinjectDependencyResolver(IKernel kernel) } /// - public virtual object GetService(Type serviceType, string? contract = null) => + public virtual object? GetService(Type serviceType, string? contract = null) => GetServices(serviceType, contract).LastOrDefault()!; /// - public virtual IEnumerable GetServices(Type serviceType, string? contract = null) + public virtual IEnumerable GetServices(Type serviceType, string? contract = null) { var isNull = serviceType is null; if (isNull) diff --git a/src/Splat.Prism/SplatContainerExtension.cs b/src/Splat.Prism/SplatContainerExtension.cs index 2fd7a47ac..cab36beac 100644 --- a/src/Splat.Prism/SplatContainerExtension.cs +++ b/src/Splat.Prism/SplatContainerExtension.cs @@ -15,7 +15,6 @@ namespace Splat.Prism /// /// A container for the Prism application. /// - [System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.NamingRules", "SA1316:Tuple element names should use correct casing", Justification = "Match Prism naming scheme.")] [System.Diagnostics.CodeAnalysis.SuppressMessage("Analyzers", "CA1065: Don't throw exceptions from properties", Justification = "Deliberate usage")] public class SplatContainerExtension : IContainerExtension, IDisposable { @@ -240,42 +239,42 @@ public IContainerRegistry RegisterSingleton(Type type, Func - public object Resolve(Type type) + public object? Resolve(Type type) { return Instance.GetService(type); } /// - public object Resolve(Type type, params (Type Type, object Instance)[] parameters) + public object? Resolve(Type type, params (Type Type, object Instance)[] parameters) { if (_types.TryGetValue((type, null), out var resolvedType)) { return Activator.CreateInstance(resolvedType, parameters.Select(x => x.Instance)) ?? throw new InvalidOperationException("Could not create type"); } - return null!; + return default; } /// - public object Resolve(Type type, string name) + public object? Resolve(Type type, string name) { return Instance.GetService(type, name); } /// - public object Resolve(Type type, string name, params (Type Type, object Instance)[] parameters) + public object? Resolve(Type type, string name, params (Type Type, object Instance)[] parameters) { if (!_types.TryGetValue((type, name), out var resolvedType)) { if (resolvedType is null) { - return null!; + return default; } return Activator.CreateInstance(resolvedType, parameters.Select(x => x.Instance))!; } - return null!; + return default; } /// diff --git a/src/Splat.SimpleInjector/SimpleInjectorDependencyResolver.cs b/src/Splat.SimpleInjector/SimpleInjectorDependencyResolver.cs index 04cdcbc20..033811158 100644 --- a/src/Splat.SimpleInjector/SimpleInjectorDependencyResolver.cs +++ b/src/Splat.SimpleInjector/SimpleInjectorDependencyResolver.cs @@ -32,7 +32,7 @@ public SimpleInjectorDependencyResolver(Container container, SimpleInjectorIniti } /// - public object GetService(Type serviceType, string? contract = null) + public object? GetService(Type serviceType, string? contract = null) { try { @@ -47,12 +47,12 @@ public object GetService(Type serviceType, string? contract = null) } catch { - return null!; + return default; } } /// - public IEnumerable GetServices(Type serviceType, string? contract = null) + public IEnumerable GetServices(Type serviceType, string? contract = null) { try { @@ -66,7 +66,7 @@ public IEnumerable GetServices(Type serviceType, string? contract = null return new[] { registration.GetInstance() }; } - return Enumerable.Empty(); + return Enumerable.Empty(); } } diff --git a/src/Splat.SimpleInjector/SimpleInjectorInitializer.cs b/src/Splat.SimpleInjector/SimpleInjectorInitializer.cs index 1daf4536f..3f358219f 100644 --- a/src/Splat.SimpleInjector/SimpleInjectorInitializer.cs +++ b/src/Splat.SimpleInjector/SimpleInjectorInitializer.cs @@ -24,7 +24,7 @@ public class SimpleInjectorInitializer : IDependencyResolver = new(); /// - public object GetService(Type serviceType, string? contract = null) + public object? GetService(Type serviceType, string? contract = null) { lock (_lockObject) { @@ -34,7 +34,7 @@ public object GetService(Type serviceType, string? contract = null) } /// - public IEnumerable GetServices(Type serviceType, string? contract = null) + public IEnumerable GetServices(Type serviceType, string? contract = null) { lock (_lockObject) { diff --git a/src/Splat.Tests/API/ApiApprovalTests.SplatProject.net5.0.approved.txt b/src/Splat.Tests/API/ApiApprovalTests.SplatProject.net5.0.approved.txt index be7ae737b..384c7de9d 100644 --- a/src/Splat.Tests/API/ApiApprovalTests.SplatProject.net5.0.approved.txt +++ b/src/Splat.Tests/API/ApiApprovalTests.SplatProject.net5.0.approved.txt @@ -159,8 +159,8 @@ namespace Splat } public static class DependencyResolverMixins { - public static T GetService(this Splat.IReadonlyDependencyResolver resolver, string? contract = null) { } - public static System.Collections.Generic.IEnumerable GetServices(this Splat.IReadonlyDependencyResolver resolver, string? contract = null) { } + public static T? GetService(this Splat.IReadonlyDependencyResolver resolver, string? contract = null) { } + public static System.Collections.Generic.IEnumerable GetServices(this Splat.IReadonlyDependencyResolver resolver, string? contract = null) { } public static void Register(this Splat.IMutableDependencyResolver resolver, System.Func factory, string? contract = null) { } public static void RegisterConstant(this Splat.IMutableDependencyResolver resolver, object? value, System.Type serviceType, string? contract = null) { } public static void RegisterConstant(this Splat.IMutableDependencyResolver resolver, T? value, string? contract = null) { } @@ -191,11 +191,11 @@ namespace Splat } public class FuncDependencyResolver : Splat.IDependencyResolver, Splat.IMutableDependencyResolver, Splat.IReadonlyDependencyResolver, System.IDisposable { - public FuncDependencyResolver(System.Func> getAllServices, System.Action, System.Type, string?>? register = null, System.Action? unregisterCurrent = null, System.Action? unregisterAll = null, System.IDisposable? toDispose = null) { } + public FuncDependencyResolver(System.Func> getAllServices, System.Action, System.Type, string?>? register = null, System.Action? unregisterCurrent = null, System.Action? unregisterAll = null, System.IDisposable? toDispose = null) { } public void Dispose() { } protected virtual void Dispose(bool isDisposing) { } - public object GetService(System.Type serviceType, string? contract = null) { } - public System.Collections.Generic.IEnumerable GetServices(System.Type serviceType, string? contract = null) { } + public object? GetService(System.Type serviceType, string? contract = null) { } + public System.Collections.Generic.IEnumerable GetServices(System.Type serviceType, string? contract = null) { } public bool HasRegistration(System.Type serviceType, string? contract = null) { } public void Register(System.Func factory, System.Type serviceType, string? contract = null) { } public System.IDisposable ServiceRegistrationCallback(System.Type serviceType, string? contract, System.Action callback) { } @@ -415,8 +415,8 @@ namespace Splat } public interface IReadonlyDependencyResolver { - object GetService(System.Type serviceType, string? contract = null); - System.Collections.Generic.IEnumerable GetServices(System.Type serviceType, string? contract = null); + object? GetService(System.Type serviceType, string? contract = null); + System.Collections.Generic.IEnumerable GetServices(System.Type serviceType, string? contract = null); } public interface IStaticFullLogger { @@ -516,12 +516,12 @@ namespace Splat public ModernDependencyResolver() { } protected ModernDependencyResolver([System.Runtime.CompilerServices.TupleElementNames(new string[] { "serviceType", - "contract"})] System.Collections.Generic.Dictionary, System.Collections.Generic.List>>? registry) { } + "contract"})] System.Collections.Generic.Dictionary, System.Collections.Generic.List>>? registry) { } public void Dispose() { } protected virtual void Dispose(bool isDisposing) { } public Splat.ModernDependencyResolver Duplicate() { } - public object GetService(System.Type serviceType, string? contract = null) { } - public System.Collections.Generic.IEnumerable GetServices(System.Type serviceType, string? contract = null) { } + public object? GetService(System.Type serviceType, string? contract = null) { } + public System.Collections.Generic.IEnumerable GetServices(System.Type serviceType, string? contract = null) { } public bool HasRegistration(System.Type serviceType, string? contract = null) { } public void Register(System.Func factory, System.Type serviceType, string? contract = null) { } public System.IDisposable ServiceRegistrationCallback(System.Type serviceType, string? contract, System.Action callback) { } diff --git a/src/Splat.Tests/API/ApiApprovalTests.SplatProject.netcoreapp3.1.approved.txt b/src/Splat.Tests/API/ApiApprovalTests.SplatProject.netcoreapp3.1.approved.txt index bf07b4649..776339ad2 100644 --- a/src/Splat.Tests/API/ApiApprovalTests.SplatProject.netcoreapp3.1.approved.txt +++ b/src/Splat.Tests/API/ApiApprovalTests.SplatProject.netcoreapp3.1.approved.txt @@ -159,8 +159,8 @@ namespace Splat } public static class DependencyResolverMixins { - public static T GetService(this Splat.IReadonlyDependencyResolver resolver, string? contract = null) { } - public static System.Collections.Generic.IEnumerable GetServices(this Splat.IReadonlyDependencyResolver resolver, string? contract = null) { } + public static T? GetService(this Splat.IReadonlyDependencyResolver resolver, string? contract = null) { } + public static System.Collections.Generic.IEnumerable GetServices(this Splat.IReadonlyDependencyResolver resolver, string? contract = null) { } public static void Register(this Splat.IMutableDependencyResolver resolver, System.Func factory, string? contract = null) { } public static void RegisterConstant(this Splat.IMutableDependencyResolver resolver, object? value, System.Type serviceType, string? contract = null) { } public static void RegisterConstant(this Splat.IMutableDependencyResolver resolver, T? value, string? contract = null) { } @@ -191,11 +191,11 @@ namespace Splat } public class FuncDependencyResolver : Splat.IDependencyResolver, Splat.IMutableDependencyResolver, Splat.IReadonlyDependencyResolver, System.IDisposable { - public FuncDependencyResolver(System.Func> getAllServices, System.Action, System.Type, string?>? register = null, System.Action? unregisterCurrent = null, System.Action? unregisterAll = null, System.IDisposable? toDispose = null) { } + public FuncDependencyResolver(System.Func> getAllServices, System.Action, System.Type, string?>? register = null, System.Action? unregisterCurrent = null, System.Action? unregisterAll = null, System.IDisposable? toDispose = null) { } public void Dispose() { } protected virtual void Dispose(bool isDisposing) { } - public object GetService(System.Type serviceType, string? contract = null) { } - public System.Collections.Generic.IEnumerable GetServices(System.Type serviceType, string? contract = null) { } + public object? GetService(System.Type serviceType, string? contract = null) { } + public System.Collections.Generic.IEnumerable GetServices(System.Type serviceType, string? contract = null) { } public bool HasRegistration(System.Type serviceType, string? contract = null) { } public void Register(System.Func factory, System.Type serviceType, string? contract = null) { } public System.IDisposable ServiceRegistrationCallback(System.Type serviceType, string? contract, System.Action callback) { } @@ -415,8 +415,8 @@ namespace Splat } public interface IReadonlyDependencyResolver { - object GetService(System.Type serviceType, string? contract = null); - System.Collections.Generic.IEnumerable GetServices(System.Type serviceType, string? contract = null); + object? GetService(System.Type serviceType, string? contract = null); + System.Collections.Generic.IEnumerable GetServices(System.Type serviceType, string? contract = null); } public interface IStaticFullLogger { @@ -516,12 +516,12 @@ namespace Splat public ModernDependencyResolver() { } protected ModernDependencyResolver([System.Runtime.CompilerServices.TupleElementNames(new string[] { "serviceType", - "contract"})] System.Collections.Generic.Dictionary, System.Collections.Generic.List>>? registry) { } + "contract"})] System.Collections.Generic.Dictionary, System.Collections.Generic.List>>? registry) { } public void Dispose() { } protected virtual void Dispose(bool isDisposing) { } public Splat.ModernDependencyResolver Duplicate() { } - public object GetService(System.Type serviceType, string? contract = null) { } - public System.Collections.Generic.IEnumerable GetServices(System.Type serviceType, string? contract = null) { } + public object? GetService(System.Type serviceType, string? contract = null) { } + public System.Collections.Generic.IEnumerable GetServices(System.Type serviceType, string? contract = null) { } public bool HasRegistration(System.Type serviceType, string? contract = null) { } public void Register(System.Func factory, System.Type serviceType, string? contract = null) { } public System.IDisposable ServiceRegistrationCallback(System.Type serviceType, string? contract, System.Action callback) { } diff --git a/src/Splat/ServiceLocation/DependencyResolverMixins.cs b/src/Splat/ServiceLocation/DependencyResolverMixins.cs index a3d0d8216..31c3379ff 100644 --- a/src/Splat/ServiceLocation/DependencyResolverMixins.cs +++ b/src/Splat/ServiceLocation/DependencyResolverMixins.cs @@ -24,14 +24,14 @@ public static class DependencyResolverMixins /// The resolver we are getting the service from. /// A optional value which will retrieve only a object registered with the same contract. /// The requested object, if found; null otherwise. - public static T GetService(this IReadonlyDependencyResolver resolver, string? contract = null) + public static T? GetService(this IReadonlyDependencyResolver resolver, string? contract = null) { if (resolver is null) { throw new ArgumentNullException(nameof(resolver)); } - return (T)resolver.GetService(typeof(T), contract); + return (T?)resolver.GetService(typeof(T), contract); } /// @@ -43,14 +43,14 @@ public static T GetService(this IReadonlyDependencyResolver resolver, string? /// A optional value which will retrieve only a object registered with the same contract. /// A sequence of instances of the requested . The sequence /// should be empty (not null) if no objects of the given type are available. - public static IEnumerable GetServices(this IReadonlyDependencyResolver resolver, string? contract = null) + public static IEnumerable GetServices(this IReadonlyDependencyResolver resolver, string? contract = null) { if (resolver is null) { throw new ArgumentNullException(nameof(resolver)); } - return resolver.GetServices(typeof(T), contract).Cast(); + return resolver.GetServices(typeof(T), contract).Cast(); } /// diff --git a/src/Splat/ServiceLocation/FuncDependencyResolver.cs b/src/Splat/ServiceLocation/FuncDependencyResolver.cs index fd846751b..576fc33ba 100644 --- a/src/Splat/ServiceLocation/FuncDependencyResolver.cs +++ b/src/Splat/ServiceLocation/FuncDependencyResolver.cs @@ -17,7 +17,7 @@ namespace Splat /// public class FuncDependencyResolver : IDependencyResolver { - private readonly Func> _innerGetServices; + private readonly Func> _innerGetServices; private readonly Action, Type, string?>? _innerRegister; private readonly Action? _unregisterCurrent; private readonly Action? _unregisterAll; @@ -35,7 +35,7 @@ public class FuncDependencyResolver : IDependencyResolver /// A func which will unregister all the registered elements for a service type and contract. /// A optional disposable which is called when this resolver is disposed. public FuncDependencyResolver( - Func> getAllServices, + Func> getAllServices, Action, Type, string?>? register = null, Action? unregisterCurrent = null, Action? unregisterAll = null, @@ -49,13 +49,13 @@ public FuncDependencyResolver( } /// - public object GetService(Type serviceType, string? contract = null) + public object? GetService(Type serviceType, string? contract = null) { - return (GetServices(serviceType, contract) ?? Enumerable.Empty()).LastOrDefault()!; + return (GetServices(serviceType, contract) ?? Enumerable.Empty()).LastOrDefault()!; } /// - public IEnumerable GetServices(Type serviceType, string? contract = null) + public IEnumerable GetServices(Type serviceType, string? contract = null) { return _innerGetServices(serviceType, contract); } @@ -90,12 +90,7 @@ public void Register(Func factory, Type serviceType, string? contract = if (disp.IsDisposed) { - if (toRemove is null) - { - toRemove = new List>(); - } - - toRemove.Add(callback); + (toRemove ??= new List>()).Add(callback); } } diff --git a/src/Splat/ServiceLocation/IReadonlyDependencyResolver.cs b/src/Splat/ServiceLocation/IReadonlyDependencyResolver.cs index e03b7c2b2..a052be35b 100644 --- a/src/Splat/ServiceLocation/IReadonlyDependencyResolver.cs +++ b/src/Splat/ServiceLocation/IReadonlyDependencyResolver.cs @@ -19,7 +19,7 @@ public interface IReadonlyDependencyResolver /// The object type. /// A optional value which will retrieve only a object registered with the same contract. /// The requested object, if found; null otherwise. - object GetService(Type serviceType, string? contract = null); + object? GetService(Type serviceType, string? contract = null); /// /// Gets all instances of the given . Must return an empty @@ -29,6 +29,6 @@ public interface IReadonlyDependencyResolver /// A optional value which will retrieve only objects registered with the same contract. /// A sequence of instances of the requested . The sequence /// should be empty (not null) if no objects of the given type are available. - IEnumerable GetServices(Type serviceType, string? contract = null); + IEnumerable GetServices(Type serviceType, string? contract = null); } } diff --git a/src/Splat/ServiceLocation/ModernDependencyResolver.cs b/src/Splat/ServiceLocation/ModernDependencyResolver.cs index 22c8b3dd7..8b8a1fcf2 100644 --- a/src/Splat/ServiceLocation/ModernDependencyResolver.cs +++ b/src/Splat/ServiceLocation/ModernDependencyResolver.cs @@ -26,8 +26,8 @@ namespace Splat /// public class ModernDependencyResolver : IDependencyResolver { - private readonly Dictionary<(Type serviceType, string contract), List>> _callbackRegistry; - private Dictionary<(Type serviceType, string contract), List>>? _registry; + private readonly Dictionary<(Type serviceType, string? contract), List>> _callbackRegistry; + private Dictionary<(Type serviceType, string? contract), List>>? _registry; private bool _isDisposed; @@ -43,13 +43,13 @@ public ModernDependencyResolver() /// Initializes a new instance of the class. /// /// A registry of services. - protected ModernDependencyResolver(Dictionary<(Type serviceType, string contract), List>>? registry) + protected ModernDependencyResolver(Dictionary<(Type serviceType, string? contract), List>>? registry) { _registry = registry is not null ? registry.ToDictionary(k => k.Key, v => v.Value.ToList()) : - new Dictionary<(Type serviceType, string contract), List>>(); + new Dictionary<(Type serviceType, string? contract), List>>(); - _callbackRegistry = new Dictionary<(Type serviceType, string contract), List>>(); + _callbackRegistry = new Dictionary<(Type serviceType, string? contract), List>>(); } /// @@ -108,38 +108,38 @@ public void Register(Func factory, Type serviceType, string? contract = } /// - public object GetService(Type serviceType, string? contract = null) + public object? GetService(Type serviceType, string? contract = null) { if (_registry is null) { - return null!; + return default; } var pair = GetKey(serviceType, contract); if (!_registry.ContainsKey(pair)) { - return null!; + return default; } var ret = _registry[pair].LastOrDefault(); - return (ret != null ? ret() : null)!; + return ret is null ? default : ret(); } /// - public IEnumerable GetServices(Type serviceType, string? contract = null) + public IEnumerable GetServices(Type serviceType, string? contract = null) { if (_registry is null) { - return Enumerable.Empty(); + return Enumerable.Empty(); } var pair = GetKey(serviceType, contract); if (!_registry.ContainsKey(pair)) { - return Enumerable.Empty(); + return Enumerable.Empty(); } - return _registry[pair].ConvertAll(x => x()!); + return _registry[pair].ConvertAll(x => x()); } /// From de50dcd4aa56d4ceab577413d9dbccaddf7899e4 Mon Sep 17 00:00:00 2001 From: David Vreony Date: Sat, 17 Jul 2021 11:46:43 +0100 Subject: [PATCH 4/9] prep bump to v12 --- version.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.json b/version.json index 1738e72e0..4c30e65a3 100644 --- a/version.json +++ b/version.json @@ -1,5 +1,5 @@ { - "version": "11.1", + "version": "12.0", "publicReleaseRefSpec": [ "^refs/heads/main$", // we release out of master "^refs/heads/preview/.*", // we release previews From d3c81fb256b87a59446b3087ca67955e43a1a802 Mon Sep 17 00:00:00 2001 From: David Vreony Date: Tue, 20 Jul 2021 08:39:44 +0100 Subject: [PATCH 5/9] Merge to PR #721 for GetService and GetServices (#729) * WIP: tweaks for getservices * warnings as errors for nullable * attempt to tidy up getservices warnings * remove bak files * change autofac to use Enumerable.Empty --- src/Directory.build.props | 1 + .../AutofacDependencyResolver.cs | 19 ++++++++++++------- src/Splat.DryIoc/DryIocDependencyResolver.cs | 2 +- .../DependencyResolverTests.cs | 5 ++++- .../MicrosoftDependencyResolver.cs | 14 +++++++++----- .../NinjectDependencyResolver.cs | 10 +++++----- .../SimpleInjectorDependencyResolver.cs | 9 +++++++-- .../SimpleInjectorInitializer.cs | 7 ++++++- ...ovalTests.SplatProject.net5.0.approved.txt | 8 ++++---- ...ts.SplatProject.netcoreapp3.1.approved.txt | 8 ++++---- .../BaseDependencyResolverTests.cs | 3 +++ .../ServiceLocation/FuncDependencyResolver.cs | 13 +++++++++---- .../IReadonlyDependencyResolver.cs | 2 +- .../ModernDependencyResolver.cs | 13 +++++++++---- 14 files changed, 75 insertions(+), 39 deletions(-) diff --git a/src/Directory.build.props b/src/Directory.build.props index 51599ea07..f6f24f60e 100644 --- a/src/Directory.build.props +++ b/src/Directory.build.props @@ -16,6 +16,7 @@ https://github.com/reactiveui/splat/releases https://github.com/reactiveui/splat git + nullable false diff --git a/src/Splat.Autofac/AutofacDependencyResolver.cs b/src/Splat.Autofac/AutofacDependencyResolver.cs index acec9894a..7f816c8d2 100644 --- a/src/Splat.Autofac/AutofacDependencyResolver.cs +++ b/src/Splat.Autofac/AutofacDependencyResolver.cs @@ -83,8 +83,13 @@ public void SetLifetimeScope(ILifetimeScope lifetimeScope) } /// - public virtual IEnumerable GetServices(Type serviceType, string? contract = null) + public virtual IEnumerable GetServices(Type? serviceType, string? contract = null) { + if (serviceType is null) + { + throw new ArgumentNullException(nameof(serviceType)); + } + lock (_lockObject) { try @@ -92,17 +97,17 @@ public void SetLifetimeScope(ILifetimeScope lifetimeScope) var enumerableType = typeof(IEnumerable<>).MakeGenericType(serviceType); var instance = Resolve(enumerableType, contract); - if (instance is null) + if (instance is not null) { - return Array.Empty(); + return new object[] { instance }; } - - return ((IEnumerable)instance).Cast(); } catch (DependencyResolutionException) { - return Array.Empty(); + // no op } + + return Enumerable.Empty(); } } @@ -225,7 +230,7 @@ protected virtual void Dispose(bool disposing) } } - private object Resolve(Type serviceType, string? contract) + private object? Resolve(Type serviceType, string? contract) { object serviceInstance; diff --git a/src/Splat.DryIoc/DryIocDependencyResolver.cs b/src/Splat.DryIoc/DryIocDependencyResolver.cs index 97bbf6cba..6a89a93c8 100644 --- a/src/Splat.DryIoc/DryIocDependencyResolver.cs +++ b/src/Splat.DryIoc/DryIocDependencyResolver.cs @@ -35,7 +35,7 @@ public DryIocDependencyResolver(IContainer? container = null) : _container.ResolveMany(serviceType, serviceKey: contract).LastOrDefault(); /// - public virtual IEnumerable GetServices(Type serviceType, string? contract = null) => + public virtual IEnumerable GetServices(Type? serviceType, string? contract = null) => string.IsNullOrEmpty(contract) ? _container.ResolveMany(serviceType) : _container.ResolveMany(serviceType, serviceKey: contract); diff --git a/src/Splat.Microsoft.Extensions.DependencyInjection.Tests/DependencyResolverTests.cs b/src/Splat.Microsoft.Extensions.DependencyInjection.Tests/DependencyResolverTests.cs index 9734ab191..009125928 100644 --- a/src/Splat.Microsoft.Extensions.DependencyInjection.Tests/DependencyResolverTests.cs +++ b/src/Splat.Microsoft.Extensions.DependencyInjection.Tests/DependencyResolverTests.cs @@ -165,9 +165,12 @@ public void ILogManager_Resolvable() wrapper.BuildAndUse(); // Get the ILogManager instance. - ILogManager lm = Locator.Current.GetService(); + ILogManager? lm = Locator.Current.GetService(); + Assert.NotNull(lm); +#pragma warning disable CS8604 // Possible null reference argument. var mgr = lm.GetLogger(); +#pragma warning restore CS8604 // Possible null reference argument. Assert.NotNull(mgr); } } diff --git a/src/Splat.Microsoft.Extensions.DependencyInjection/MicrosoftDependencyResolver.cs b/src/Splat.Microsoft.Extensions.DependencyInjection/MicrosoftDependencyResolver.cs index a00643b38..07db68bde 100644 --- a/src/Splat.Microsoft.Extensions.DependencyInjection/MicrosoftDependencyResolver.cs +++ b/src/Splat.Microsoft.Extensions.DependencyInjection/MicrosoftDependencyResolver.cs @@ -89,7 +89,7 @@ public void UpdateContainer(IServiceProvider serviceProvider) GetServices(serviceType, contract).LastOrDefault()!; /// - public virtual IEnumerable GetServices(Type serviceType, string? contract = null) + public virtual IEnumerable GetServices(Type? serviceType, string? contract = null) { var isNull = serviceType is null; if (serviceType is null) @@ -97,11 +97,15 @@ public void UpdateContainer(IServiceProvider serviceProvider) serviceType = typeof(NullServiceType); } - IEnumerable services; + IEnumerable services; if (contract is null || string.IsNullOrWhiteSpace(contract)) { - services = ServiceProvider.GetServices(serviceType); + // this is to deal with CS8613 that GetServices returns IEnumerable? + services = ServiceProvider.GetServices(serviceType) + .Where(a => a is not null) + .Select(a => a!); + if (isNull) { services = services @@ -115,7 +119,7 @@ public void UpdateContainer(IServiceProvider serviceProvider) services = dic? .GetFactories(contract) .Select(f => f()) - ?? Enumerable.Empty(); + ?? Enumerable.Empty(); } return services; @@ -124,7 +128,7 @@ public void UpdateContainer(IServiceProvider serviceProvider) /// #pragma warning disable CS8614 // Nullability of reference types in type of parameter doesn't match implicitly implemented member. - public virtual void Register(Func factory, Type serviceType, string? contract = null) + public virtual void Register(Func factory, Type? serviceType, string? contract = null) #pragma warning restore CS8614 // Nullability of reference types in type of parameter doesn't match implicitly implemented member. { if (_isImmutable) diff --git a/src/Splat.Ninject/NinjectDependencyResolver.cs b/src/Splat.Ninject/NinjectDependencyResolver.cs index 925137987..9bf019d5c 100644 --- a/src/Splat.Ninject/NinjectDependencyResolver.cs +++ b/src/Splat.Ninject/NinjectDependencyResolver.cs @@ -34,10 +34,10 @@ public NinjectDependencyResolver(IKernel kernel) GetServices(serviceType, contract).LastOrDefault()!; /// - public virtual IEnumerable GetServices(Type serviceType, string? contract = null) + public virtual IEnumerable GetServices(Type? serviceType, string? contract = null) { var isNull = serviceType is null; - if (isNull) + if (serviceType is null) { serviceType = typeof(NullServiceType); } @@ -61,7 +61,7 @@ public bool HasRegistration(Type serviceType, string? contract = null) } /// - public virtual void Register(Func factory, Type serviceType, string? contract = null) + public virtual void Register(Func factory, Type? serviceType, string? contract = null) { var isNull = serviceType is null; @@ -80,7 +80,7 @@ public virtual void Register(Func factory, Type serviceType, string? co } /// - public virtual void UnregisterCurrent(Type serviceType, string? contract = null) + public virtual void UnregisterCurrent(Type? serviceType, string? contract = null) { var isNull = serviceType is null; @@ -107,7 +107,7 @@ public virtual void UnregisterCurrent(Type serviceType, string? contract = null) } /// - public virtual void UnregisterAll(Type serviceType, string? contract = null) + public virtual void UnregisterAll(Type? serviceType, string? contract = null) { var isNull = serviceType is null; diff --git a/src/Splat.SimpleInjector/SimpleInjectorDependencyResolver.cs b/src/Splat.SimpleInjector/SimpleInjectorDependencyResolver.cs index 033811158..3b5a5bd3b 100644 --- a/src/Splat.SimpleInjector/SimpleInjectorDependencyResolver.cs +++ b/src/Splat.SimpleInjector/SimpleInjectorDependencyResolver.cs @@ -52,8 +52,13 @@ public SimpleInjectorDependencyResolver(Container container, SimpleInjectorIniti } /// - public IEnumerable GetServices(Type serviceType, string? contract = null) + public IEnumerable GetServices(Type? serviceType, string? contract = null) { + if (serviceType is null) + { + throw new ArgumentNullException(nameof(serviceType)); + } + try { return _container.GetAllInstances(serviceType); @@ -66,7 +71,7 @@ public SimpleInjectorDependencyResolver(Container container, SimpleInjectorIniti return new[] { registration.GetInstance() }; } - return Enumerable.Empty(); + return Enumerable.Empty(); } } diff --git a/src/Splat.SimpleInjector/SimpleInjectorInitializer.cs b/src/Splat.SimpleInjector/SimpleInjectorInitializer.cs index 3f358219f..534014c8c 100644 --- a/src/Splat.SimpleInjector/SimpleInjectorInitializer.cs +++ b/src/Splat.SimpleInjector/SimpleInjectorInitializer.cs @@ -34,8 +34,13 @@ public class SimpleInjectorInitializer : IDependencyResolver } /// - public IEnumerable GetServices(Type serviceType, string? contract = null) + public IEnumerable GetServices(Type? serviceType, string? contract = null) { + if (serviceType is null) + { + throw new ArgumentNullException(nameof(serviceType)); + } + lock (_lockObject) { return RegisteredFactories[serviceType] diff --git a/src/Splat.Tests/API/ApiApprovalTests.SplatProject.net5.0.approved.txt b/src/Splat.Tests/API/ApiApprovalTests.SplatProject.net5.0.approved.txt index 384c7de9d..d6cfb96b0 100644 --- a/src/Splat.Tests/API/ApiApprovalTests.SplatProject.net5.0.approved.txt +++ b/src/Splat.Tests/API/ApiApprovalTests.SplatProject.net5.0.approved.txt @@ -191,11 +191,11 @@ namespace Splat } public class FuncDependencyResolver : Splat.IDependencyResolver, Splat.IMutableDependencyResolver, Splat.IReadonlyDependencyResolver, System.IDisposable { - public FuncDependencyResolver(System.Func> getAllServices, System.Action, System.Type, string?>? register = null, System.Action? unregisterCurrent = null, System.Action? unregisterAll = null, System.IDisposable? toDispose = null) { } + public FuncDependencyResolver(System.Func> getAllServices, System.Action, System.Type, string?>? register = null, System.Action? unregisterCurrent = null, System.Action? unregisterAll = null, System.IDisposable? toDispose = null) { } public void Dispose() { } protected virtual void Dispose(bool isDisposing) { } public object? GetService(System.Type serviceType, string? contract = null) { } - public System.Collections.Generic.IEnumerable GetServices(System.Type serviceType, string? contract = null) { } + public System.Collections.Generic.IEnumerable GetServices(System.Type? serviceType, string? contract = null) { } public bool HasRegistration(System.Type serviceType, string? contract = null) { } public void Register(System.Func factory, System.Type serviceType, string? contract = null) { } public System.IDisposable ServiceRegistrationCallback(System.Type serviceType, string? contract, System.Action callback) { } @@ -416,7 +416,7 @@ namespace Splat public interface IReadonlyDependencyResolver { object? GetService(System.Type serviceType, string? contract = null); - System.Collections.Generic.IEnumerable GetServices(System.Type serviceType, string? contract = null); + System.Collections.Generic.IEnumerable GetServices(System.Type? serviceType, string? contract = null); } public interface IStaticFullLogger { @@ -521,7 +521,7 @@ namespace Splat protected virtual void Dispose(bool isDisposing) { } public Splat.ModernDependencyResolver Duplicate() { } public object? GetService(System.Type serviceType, string? contract = null) { } - public System.Collections.Generic.IEnumerable GetServices(System.Type serviceType, string? contract = null) { } + public System.Collections.Generic.IEnumerable GetServices(System.Type? serviceType, string? contract = null) { } public bool HasRegistration(System.Type serviceType, string? contract = null) { } public void Register(System.Func factory, System.Type serviceType, string? contract = null) { } public System.IDisposable ServiceRegistrationCallback(System.Type serviceType, string? contract, System.Action callback) { } diff --git a/src/Splat.Tests/API/ApiApprovalTests.SplatProject.netcoreapp3.1.approved.txt b/src/Splat.Tests/API/ApiApprovalTests.SplatProject.netcoreapp3.1.approved.txt index 776339ad2..4028a03c5 100644 --- a/src/Splat.Tests/API/ApiApprovalTests.SplatProject.netcoreapp3.1.approved.txt +++ b/src/Splat.Tests/API/ApiApprovalTests.SplatProject.netcoreapp3.1.approved.txt @@ -191,11 +191,11 @@ namespace Splat } public class FuncDependencyResolver : Splat.IDependencyResolver, Splat.IMutableDependencyResolver, Splat.IReadonlyDependencyResolver, System.IDisposable { - public FuncDependencyResolver(System.Func> getAllServices, System.Action, System.Type, string?>? register = null, System.Action? unregisterCurrent = null, System.Action? unregisterAll = null, System.IDisposable? toDispose = null) { } + public FuncDependencyResolver(System.Func> getAllServices, System.Action, System.Type, string?>? register = null, System.Action? unregisterCurrent = null, System.Action? unregisterAll = null, System.IDisposable? toDispose = null) { } public void Dispose() { } protected virtual void Dispose(bool isDisposing) { } public object? GetService(System.Type serviceType, string? contract = null) { } - public System.Collections.Generic.IEnumerable GetServices(System.Type serviceType, string? contract = null) { } + public System.Collections.Generic.IEnumerable GetServices(System.Type? serviceType, string? contract = null) { } public bool HasRegistration(System.Type serviceType, string? contract = null) { } public void Register(System.Func factory, System.Type serviceType, string? contract = null) { } public System.IDisposable ServiceRegistrationCallback(System.Type serviceType, string? contract, System.Action callback) { } @@ -416,7 +416,7 @@ namespace Splat public interface IReadonlyDependencyResolver { object? GetService(System.Type serviceType, string? contract = null); - System.Collections.Generic.IEnumerable GetServices(System.Type serviceType, string? contract = null); + System.Collections.Generic.IEnumerable GetServices(System.Type? serviceType, string? contract = null); } public interface IStaticFullLogger { @@ -521,7 +521,7 @@ namespace Splat protected virtual void Dispose(bool isDisposing) { } public Splat.ModernDependencyResolver Duplicate() { } public object? GetService(System.Type serviceType, string? contract = null) { } - public System.Collections.Generic.IEnumerable GetServices(System.Type serviceType, string? contract = null) { } + public System.Collections.Generic.IEnumerable GetServices(System.Type? serviceType, string? contract = null) { } public bool HasRegistration(System.Type serviceType, string? contract = null) { } public void Register(System.Func factory, System.Type serviceType, string? contract = null) { } public System.IDisposable ServiceRegistrationCallback(System.Type serviceType, string? contract, System.Action callback) { } diff --git a/src/Splat.Tests/ServiceLocation/BaseDependencyResolverTests.cs b/src/Splat.Tests/ServiceLocation/BaseDependencyResolverTests.cs index c2ffbc6f4..92106ff36 100644 --- a/src/Splat.Tests/ServiceLocation/BaseDependencyResolverTests.cs +++ b/src/Splat.Tests/ServiceLocation/BaseDependencyResolverTests.cs @@ -161,9 +161,12 @@ public void ILogManager_Resolvable() // Get the ILogManager instance var lm = Locator.Current.GetService(); + Assert.NotNull(lm); // now suceeds for AutoFac, Ninject and Splat +#pragma warning disable CS8604 // Possible null reference argument. var mgr = lm.GetLogger(); +#pragma warning restore CS8604 // Possible null reference argument. Assert.NotNull(mgr); } } diff --git a/src/Splat/ServiceLocation/FuncDependencyResolver.cs b/src/Splat/ServiceLocation/FuncDependencyResolver.cs index 576fc33ba..b8ac601e7 100644 --- a/src/Splat/ServiceLocation/FuncDependencyResolver.cs +++ b/src/Splat/ServiceLocation/FuncDependencyResolver.cs @@ -17,7 +17,7 @@ namespace Splat /// public class FuncDependencyResolver : IDependencyResolver { - private readonly Func> _innerGetServices; + private readonly Func> _innerGetServices; private readonly Action, Type, string?>? _innerRegister; private readonly Action? _unregisterCurrent; private readonly Action? _unregisterAll; @@ -35,7 +35,7 @@ public class FuncDependencyResolver : IDependencyResolver /// A func which will unregister all the registered elements for a service type and contract. /// A optional disposable which is called when this resolver is disposed. public FuncDependencyResolver( - Func> getAllServices, + Func> getAllServices, Action, Type, string?>? register = null, Action? unregisterCurrent = null, Action? unregisterAll = null, @@ -51,12 +51,17 @@ public FuncDependencyResolver( /// public object? GetService(Type serviceType, string? contract = null) { - return (GetServices(serviceType, contract) ?? Enumerable.Empty()).LastOrDefault()!; + return GetServices(serviceType, contract)?.LastOrDefault(); } /// - public IEnumerable GetServices(Type serviceType, string? contract = null) + public IEnumerable GetServices(Type? serviceType, string? contract = null) { + if (serviceType is null) + { + throw new ArgumentNullException(nameof(serviceType)); + } + return _innerGetServices(serviceType, contract); } diff --git a/src/Splat/ServiceLocation/IReadonlyDependencyResolver.cs b/src/Splat/ServiceLocation/IReadonlyDependencyResolver.cs index a052be35b..28451743a 100644 --- a/src/Splat/ServiceLocation/IReadonlyDependencyResolver.cs +++ b/src/Splat/ServiceLocation/IReadonlyDependencyResolver.cs @@ -29,6 +29,6 @@ public interface IReadonlyDependencyResolver /// A optional value which will retrieve only objects registered with the same contract. /// A sequence of instances of the requested . The sequence /// should be empty (not null) if no objects of the given type are available. - IEnumerable GetServices(Type serviceType, string? contract = null); + IEnumerable GetServices(Type? serviceType, string? contract = null); } } diff --git a/src/Splat/ServiceLocation/ModernDependencyResolver.cs b/src/Splat/ServiceLocation/ModernDependencyResolver.cs index 8b8a1fcf2..899aad062 100644 --- a/src/Splat/ServiceLocation/ModernDependencyResolver.cs +++ b/src/Splat/ServiceLocation/ModernDependencyResolver.cs @@ -126,20 +126,25 @@ public void Register(Func factory, Type serviceType, string? contract = } /// - public IEnumerable GetServices(Type serviceType, string? contract = null) + public IEnumerable GetServices(Type? serviceType, string? contract = null) { + if (serviceType == null) + { + throw new ArgumentNullException(nameof(serviceType)); + } + if (_registry is null) { - return Enumerable.Empty(); + return Enumerable.Empty(); } var pair = GetKey(serviceType, contract); if (!_registry.ContainsKey(pair)) { - return Enumerable.Empty(); + return Enumerable.Empty(); } - return _registry[pair].ConvertAll(x => x()); + return _registry[pair].ConvertAll(x => x()!); } /// From c3d054919f3e3dfd3b8c742fa3eb5582dcc0beba Mon Sep 17 00:00:00 2001 From: Chris Pulman Date: Wed, 21 Jul 2021 21:40:25 +0100 Subject: [PATCH 6/9] updates to enable NullService type with as many resolvers as possible found an issue with Dryloc resolver with contracts, returns the wrong instance --- .editorconfig | 4 +- .../DependencyResolverTests.cs | 24 ++++++ .../AutofacDependencyResolver.cs | 33 +++++--- src/Splat.Common.Test/IDummyInterface.cs | 2 + src/Splat.Common.Test/IViewModelOne.cs | 2 + .../DependencyResolverTests.cs | 23 ++++++ src/Splat.DryIoc/DryIocDependencyResolver.cs | 72 ++++++++++++++---- .../MicrosoftDependencyResolver.cs | 48 ++++-------- .../NinjectDependencyResolver.cs | 20 ++--- .../SimpleInjectorDependencyResolver.cs | 22 ++++-- .../SimpleInjectorInitializer.cs | 38 ++++++++-- ...ovalTests.SplatProject.net5.0.approved.txt | 52 ++++++------- ...ts.SplatProject.netcoreapp3.1.approved.txt | 52 ++++++------- src/Splat.Tests/LocatorSerialRegisterTests.cs | 8 +- src/Splat.Tests/LocatorTests.cs | 22 ++++++ .../BaseDependencyResolverTests.cs | 10 ++- .../DependencyResolverMixins.cs | 8 +- .../ServiceLocation/FuncDependencyResolver.cs | 66 +++++++++++----- .../IMutableDependencyResolver.cs | 8 +- .../IReadonlyDependencyResolver.cs | 2 +- .../ModernDependencyResolver.cs | 75 ++++++++++++++----- src/Splat/ServiceLocation/NullServiceType.cs | 26 +++++++ 22 files changed, 428 insertions(+), 189 deletions(-) create mode 100644 src/Splat/ServiceLocation/NullServiceType.cs diff --git a/.editorconfig b/.editorconfig index 22e454e94..ebd68226c 100644 --- a/.editorconfig +++ b/.editorconfig @@ -49,8 +49,8 @@ csharp_style_var_elsewhere = true:suggestion # Types: use keywords instead of BCL types, and permit var only when the type is clear csharp_style_var_for_built_in_types = false:suggestion -csharp_style_var_when_type_is_apparent = false:none -csharp_style_var_elsewhere = false:suggestion +csharp_style_var_when_type_is_apparent =true:none +csharp_style_var_elsewhere =true:suggestion dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion dotnet_style_predefined_type_for_member_access = true:suggestion diff --git a/src/Splat.Autofac.Tests/DependencyResolverTests.cs b/src/Splat.Autofac.Tests/DependencyResolverTests.cs index e94a612e2..71d3ec117 100644 --- a/src/Splat.Autofac.Tests/DependencyResolverTests.cs +++ b/src/Splat.Autofac.Tests/DependencyResolverTests.cs @@ -19,6 +19,30 @@ namespace Splat.Autofac.Tests /// public class DependencyResolverTests : BaseDependencyResolverTests { + /// + /// Shoulds the resolve nulls. + /// + [Fact] + public void Can_Register_And_Resolve_Null_Types() + { + var builder = new ContainerBuilder(); + var autofacResolver = builder.UseAutofacDependencyResolver(); + + var foo = 5; + Locator.CurrentMutable.Register(() => foo, null); + + var bar = 4; + var contract = "foo"; + Locator.CurrentMutable.Register(() => bar, null, contract); + autofacResolver.SetLifetimeScope(builder.Build()); + + var value = Locator.Current.GetService(null); + Assert.Equal(foo, value); + + value = Locator.Current.GetService(null, contract); + Assert.Equal(bar, value); + } + /// /// Shoulds the resolve views. /// diff --git a/src/Splat.Autofac/AutofacDependencyResolver.cs b/src/Splat.Autofac/AutofacDependencyResolver.cs index 7f816c8d2..ef10a3dae 100644 --- a/src/Splat.Autofac/AutofacDependencyResolver.cs +++ b/src/Splat.Autofac/AutofacDependencyResolver.cs @@ -50,8 +50,13 @@ public AutofacDependencyResolver(ContainerBuilder builder) } /// - public virtual object? GetService(Type serviceType, string? contract = null) + public virtual object? GetService(Type? serviceType, string? contract = null) { + if (serviceType is null) + { + serviceType = typeof(NullServiceType); + } + lock (_lockObject) { return Resolve(serviceType, contract); @@ -87,7 +92,7 @@ public virtual IEnumerable GetServices(Type? serviceType, string? contra { if (serviceType is null) { - throw new ArgumentNullException(nameof(serviceType)); + serviceType = typeof(NullServiceType); } lock (_lockObject) @@ -112,8 +117,13 @@ public virtual IEnumerable GetServices(Type? serviceType, string? contra } /// - public bool HasRegistration(Type serviceType, string? contract = null) + public bool HasRegistration(Type? serviceType, string? contract = null) { + if (serviceType is null) + { + serviceType = typeof(NullServiceType); + } + lock (_lockObject) { var lifeTimeScope = _lifetimeScope ?? _internalLifetimeScope; @@ -138,8 +148,13 @@ public bool HasRegistration(Type serviceType, string? contract = null) /// The type which is used for the registration. /// A optional contract value which will indicates to only generate the value if this contract is specified. [Obsolete("Because Autofac 5+ containers are immutable, this method should not be used by the end-user.")] - public virtual void Register(Func factory, Type serviceType, string? contract = null) + public virtual void Register(Func factory, Type? serviceType, string? contract = null) { + if (serviceType is null) + { + serviceType = typeof(NullServiceType); + } + lock (_lockObject) { if (_lifetimeScopeSet) @@ -184,7 +199,7 @@ public virtual void Register(Func factory, Type serviceType, string? co /// [Obsolete("Because Autofac 5+ containers are immutable, UnregisterCurrent method is not available anymore. " + "Instead, simply register your service after InitializeReactiveUI to override it https://autofaccn.readthedocs.io/en/latest/register/registration.html#default-registrations.")] - public virtual void UnregisterCurrent(Type serviceType, string? contract = null) => + public virtual void UnregisterCurrent(Type? serviceType, string? contract = null) => throw new NotImplementedException("Because Autofac 5+ containers are immutable, UnregisterCurrent method is not available anymore. " + "Instead, simply register your service after InitializeReactiveUI to override it https://autofaccn.readthedocs.io/en/latest/register/registration.html#default-registrations."); @@ -199,7 +214,7 @@ public virtual void UnregisterCurrent(Type serviceType, string? contract = null) /// [Obsolete("Because Autofac 5+ containers are immutable, UnregisterAll method is not available anymore. " + "Instead, simply register your service after InitializeReactiveUI to override it https://autofaccn.readthedocs.io/en/latest/register/registration.html#default-registrations.")] - public virtual void UnregisterAll(Type serviceType, string? contract = null) => + public virtual void UnregisterAll(Type? serviceType, string? contract = null) => throw new NotImplementedException("Because Autofac 5+ containers are immutable, UnregisterAll method is not available anymore. " + "Instead, simply register your service after InitializeReactiveUI to override it https://autofaccn.readthedocs.io/en/latest/register/registration.html#default-registrations."); @@ -230,7 +245,7 @@ protected virtual void Dispose(bool disposing) } } - private object? Resolve(Type serviceType, string? contract) + private object? Resolve(Type? serviceType, string? contract) { object serviceInstance; @@ -238,11 +253,11 @@ protected virtual void Dispose(bool disposing) if (contract is null || string.IsNullOrWhiteSpace(contract)) { - lifeTimeScope.TryResolve(serviceType, out serviceInstance!); + lifeTimeScope.TryResolve(serviceType!, out serviceInstance!); } else { - lifeTimeScope.TryResolveNamed(contract, serviceType, out serviceInstance!); + lifeTimeScope.TryResolveNamed(contract, serviceType!, out serviceInstance!); } return serviceInstance; diff --git a/src/Splat.Common.Test/IDummyInterface.cs b/src/Splat.Common.Test/IDummyInterface.cs index 10befa033..9a61fbe84 100644 --- a/src/Splat.Common.Test/IDummyInterface.cs +++ b/src/Splat.Common.Test/IDummyInterface.cs @@ -8,7 +8,9 @@ namespace Splat.Tests.Mocks /// /// A dummy interface used during Locator testing. /// +#pragma warning disable CA1040 // Avoid empty interfaces public interface IDummyInterface +#pragma warning restore CA1040 // Avoid empty interfaces { } } diff --git a/src/Splat.Common.Test/IViewModelOne.cs b/src/Splat.Common.Test/IViewModelOne.cs index d0de11aa5..9a4ce992a 100644 --- a/src/Splat.Common.Test/IViewModelOne.cs +++ b/src/Splat.Common.Test/IViewModelOne.cs @@ -8,7 +8,9 @@ namespace Splat.Common.Test /// /// Interface for ViewModelOne. /// +#pragma warning disable CA1040 // Avoid empty interfaces public interface IViewModelOne +#pragma warning restore CA1040 // Avoid empty interfaces { } } diff --git a/src/Splat.DryIoc.Tests/DependencyResolverTests.cs b/src/Splat.DryIoc.Tests/DependencyResolverTests.cs index 5afe55e28..f484b49f0 100644 --- a/src/Splat.DryIoc.Tests/DependencyResolverTests.cs +++ b/src/Splat.DryIoc.Tests/DependencyResolverTests.cs @@ -20,6 +20,29 @@ namespace Splat.DryIoc.Tests /// public class DependencyResolverTests { + /// + /// Shoulds the resolve nulls. + /// + [Fact] + public void Can_Register_And_Resolve_Null_Types() + { + var builder = new Container(); + builder.UseDryIocDependencyResolver(); + + var foo = 5; + Locator.CurrentMutable.Register(() => foo, null); + + var bar = 4; + var contract = "foo"; + Locator.CurrentMutable.Register(() => bar, null, contract); + + var value = Locator.Current.GetService(null); + Assert.Equal(foo, value); + + value = Locator.Current.GetService(null, contract); + Assert.Equal(bar, value); + } + /// /// Should resolve the views. /// diff --git a/src/Splat.DryIoc/DryIocDependencyResolver.cs b/src/Splat.DryIoc/DryIocDependencyResolver.cs index 6a89a93c8..dffada080 100644 --- a/src/Splat.DryIoc/DryIocDependencyResolver.cs +++ b/src/Splat.DryIoc/DryIocDependencyResolver.cs @@ -29,20 +29,41 @@ public DryIocDependencyResolver(IContainer? container = null) } /// - public virtual object? GetService(Type serviceType, string? contract = null) => - string.IsNullOrEmpty(contract) - ? _container.ResolveMany(serviceType).LastOrDefault() - : _container.ResolveMany(serviceType, serviceKey: contract).LastOrDefault(); + public virtual object? GetService(Type? serviceType, string? contract = null) + { + var isNull = serviceType is null; + if (serviceType is null) + { + serviceType = typeof(NullServiceType); + } + + return string.IsNullOrEmpty(contract) + ? _container.ResolveMany(serviceType).Select(x => isNull ? ((NullServiceType)x).Factory()! : x).LastOrDefault() + : _container.ResolveMany(serviceType, serviceKey: contract).Select(x => isNull ? ((NullServiceType)x).Factory()! : x).LastOrDefault(); + } /// - public virtual IEnumerable GetServices(Type? serviceType, string? contract = null) => - string.IsNullOrEmpty(contract) - ? _container.ResolveMany(serviceType) - : _container.ResolveMany(serviceType, serviceKey: contract); + public virtual IEnumerable GetServices(Type? serviceType, string? contract = null) + { + var isNull = serviceType is null; + if (serviceType is null) + { + serviceType = typeof(NullServiceType); + } + + return string.IsNullOrEmpty(contract) + ? _container.ResolveMany(serviceType).Select(x => isNull ? ((NullServiceType)x).Factory()! : x) + : _container.ResolveMany(serviceType, serviceKey: contract).Select(x => isNull ? ((NullServiceType)x).Factory()! : x); + } /// - public bool HasRegistration(Type serviceType, string? contract = null) + public bool HasRegistration(Type? serviceType, string? contract = null) { + if (serviceType is null) + { + serviceType = typeof(NullServiceType); + } + return _container.GetServiceRegistrations().Any(x => { if (x.ServiceType != serviceType) @@ -61,26 +82,44 @@ public bool HasRegistration(Type serviceType, string? contract = null) } /// - public virtual void Register(Func factory, Type serviceType, string? contract = null) + public virtual void Register(Func factory, Type? serviceType, string? contract = null) { if (factory is null) { throw new ArgumentNullException(nameof(factory)); } + var isNull = serviceType is null; + if (serviceType is null) + { + serviceType = typeof(NullServiceType); + } + if (string.IsNullOrEmpty(contract)) { - _container.UseInstance(serviceType, factory(), IfAlreadyRegistered.AppendNewImplementation); + _container.UseInstance( + serviceType, + isNull ? new NullServiceType(factory) : factory(), + IfAlreadyRegistered.AppendNewImplementation); } else { - _container.UseInstance(serviceType, factory(), IfAlreadyRegistered.AppendNewImplementation, serviceKey: contract); + _container.UseInstance( + serviceType, + isNull ? new NullServiceType(factory) : factory(), + IfAlreadyRegistered.AppendNewImplementation, + serviceKey: contract); } } /// - public virtual void UnregisterCurrent(Type serviceType, string? contract = null) + public virtual void UnregisterCurrent(Type? serviceType, string? contract = null) { + if (serviceType is null) + { + serviceType = typeof(NullServiceType); + } + if (string.IsNullOrEmpty(contract)) { _container.Unregister(serviceType); @@ -92,8 +131,13 @@ public virtual void UnregisterCurrent(Type serviceType, string? contract = null) } /// - public virtual void UnregisterAll(Type serviceType, string? contract = null) + public virtual void UnregisterAll(Type? serviceType, string? contract = null) { + if (serviceType is null) + { + serviceType = typeof(NullServiceType); + } + if (string.IsNullOrEmpty(contract)) { _container.Unregister(serviceType); diff --git a/src/Splat.Microsoft.Extensions.DependencyInjection/MicrosoftDependencyResolver.cs b/src/Splat.Microsoft.Extensions.DependencyInjection/MicrosoftDependencyResolver.cs index ed43722fc..a37e1a20e 100644 --- a/src/Splat.Microsoft.Extensions.DependencyInjection/MicrosoftDependencyResolver.cs +++ b/src/Splat.Microsoft.Extensions.DependencyInjection/MicrosoftDependencyResolver.cs @@ -4,14 +4,11 @@ // See the LICENSE file in the project root for full license information. using System; -using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.Data; using System.Diagnostics.CodeAnalysis; using System.Linq; -using System.Security.Cryptography; -using System.Security.Cryptography.X509Certificates; using Microsoft.Extensions.DependencyInjection; namespace Splat.Microsoft.Extensions.DependencyInjection @@ -85,8 +82,8 @@ public void UpdateContainer(IServiceProvider serviceProvider) } /// - public virtual object? GetService(Type serviceType, string? contract = null) => - GetServices(serviceType, contract).LastOrDefault()!; + public virtual object? GetService(Type? serviceType, string? contract = null) => + GetServices(serviceType, contract).LastOrDefault(); /// public virtual IEnumerable GetServices(Type? serviceType, string? contract = null) @@ -118,7 +115,7 @@ public virtual IEnumerable GetServices(Type? serviceType, string? contra var dic = GetContractDictionary(serviceType, false); services = dic? .GetFactories(contract) - .Select(f => f()) + .Select(f => f()!) ?? Array.Empty(); } @@ -126,10 +123,7 @@ public virtual IEnumerable GetServices(Type? serviceType, string? contra } /// -#pragma warning disable CS8614 // Nullability of reference types in type of parameter doesn't match implicitly implemented member. - - public virtual void Register(Func factory, Type? serviceType, string? contract = null) -#pragma warning restore CS8614 // Nullability of reference types in type of parameter doesn't match implicitly implemented member. + public virtual void Register(Func factory, Type? serviceType, string? contract = null) { if (_isImmutable) { @@ -165,7 +159,7 @@ public virtual void Register(Func factory, Type? serviceType, string? co } /// - public virtual void UnregisterCurrent(Type serviceType, string? contract = null) + public virtual void UnregisterCurrent(Type? serviceType, string? contract = null) { if (_isImmutable) { @@ -212,7 +206,7 @@ public virtual void UnregisterCurrent(Type serviceType, string? contract = null) /// /// The service type to unregister. /// This parameter is ignored. Service will be removed from all contracts. - public virtual void UnregisterAll(Type serviceType, string? contract = null) + public virtual void UnregisterAll(Type? serviceType, string? contract = null) { if (_isImmutable) { @@ -263,7 +257,7 @@ public virtual IDisposable ServiceRegistrationCallback(Type serviceType, string? } /// - public virtual bool HasRegistration(Type serviceType, string? contract = null) + public virtual bool HasRegistration(Type? serviceType, string? contract = null) { if (serviceType is null) { @@ -363,31 +357,31 @@ private void RemoveContractService(Type serviceType) private class ContractDictionary { - private readonly ConcurrentDictionary>> _dictionary = new(); + private readonly ConcurrentDictionary>> _dictionary = new(); public bool IsEmpty => _dictionary.IsEmpty; public bool TryRemoveContract(string contract) => _dictionary.TryRemove(contract, out var _); - public Func? GetFactory(string contract) => + public Func? GetFactory(string contract) => GetFactories(contract) .LastOrDefault(); - public IEnumerable> GetFactories(string contract) => + public IEnumerable> GetFactories(string contract) => _dictionary.TryGetValue(contract, out var collection) - ? collection ?? Enumerable.Empty>() - : Array.Empty>(); + ? collection ?? Enumerable.Empty>() + : Array.Empty>(); - public void AddFactory(string contract, Func factory) => - _dictionary.AddOrUpdate(contract, _ => new List> { factory }, (_, list) => + public void AddFactory(string contract, Func factory) => + _dictionary.AddOrUpdate(contract, _ => new List> { factory }, (_, list) => { - (list ??= new List>()).Add(factory); + (list ??= new List>()).Add(factory); return list; }); public void RemoveLastFactory(string contract) => - _dictionary.AddOrUpdate(contract, new List>(), (_, list) => + _dictionary.AddOrUpdate(contract, new List>(), (_, list) => { var lastIndex = list.Count - 1; if (lastIndex > 0) @@ -406,15 +400,5 @@ public void RemoveLastFactory(string contract) => private class ContractDictionary : ContractDictionary { } - - private class NullServiceType - { - public NullServiceType(Func factory) - { - Factory = factory; - } - - public Func Factory { get; } - } } } diff --git a/src/Splat.Ninject/NinjectDependencyResolver.cs b/src/Splat.Ninject/NinjectDependencyResolver.cs index 9bf019d5c..d25cef382 100644 --- a/src/Splat.Ninject/NinjectDependencyResolver.cs +++ b/src/Splat.Ninject/NinjectDependencyResolver.cs @@ -30,7 +30,7 @@ public NinjectDependencyResolver(IKernel kernel) } /// - public virtual object? GetService(Type serviceType, string? contract = null) => + public virtual object? GetService(Type? serviceType, string? contract = null) => GetServices(serviceType, contract).LastOrDefault()!; /// @@ -55,8 +55,13 @@ public virtual IEnumerable GetServices(Type? serviceType, string? contra } /// - public bool HasRegistration(Type serviceType, string? contract = null) + public bool HasRegistration(Type? serviceType, string? contract = null) { + if (serviceType is null) + { + serviceType = typeof(NullServiceType); + } + return _kernel.CanResolve(serviceType, metadata => IsCorrectMetadata(metadata, contract)); } @@ -166,16 +171,5 @@ private static bool IsCorrectMetadata(global::Ninject.Planning.Bindings.IBinding return (metadata?.Name is null && string.IsNullOrWhiteSpace(contract)) || (metadata?.Name is not null && metadata.Name.Equals(contract, StringComparison.OrdinalIgnoreCase)); } - - [SuppressMessage("Design", "CA1812: Uninitialized class.", Justification = "Used in reflection.")] - private class NullServiceType - { - public NullServiceType(Func factory) - { - Factory = factory; - } - - public Func Factory { get; } - } } } diff --git a/src/Splat.SimpleInjector/SimpleInjectorDependencyResolver.cs b/src/Splat.SimpleInjector/SimpleInjectorDependencyResolver.cs index 1f120f64d..0768f9696 100644 --- a/src/Splat.SimpleInjector/SimpleInjectorDependencyResolver.cs +++ b/src/Splat.SimpleInjector/SimpleInjectorDependencyResolver.cs @@ -32,8 +32,13 @@ public SimpleInjectorDependencyResolver(Container container, SimpleInjectorIniti } /// - public object? GetService(Type serviceType, string? contract = null) + public object? GetService(Type? serviceType, string? contract = null) { + if (serviceType is null) + { + serviceType = typeof(NullServiceType); + } + try { InstanceProducer? registration = _container.GetRegistration(serviceType); @@ -56,7 +61,7 @@ public IEnumerable GetServices(Type? serviceType, string? contract = nul { if (serviceType is null) { - throw new ArgumentNullException(nameof(serviceType)); + serviceType = typeof(NullServiceType); } try @@ -76,26 +81,31 @@ public IEnumerable GetServices(Type? serviceType, string? contract = nul } /// - public bool HasRegistration(Type serviceType, string? contract = null) + public bool HasRegistration(Type? serviceType, string? contract = null) { + if (serviceType is null) + { + serviceType = typeof(NullServiceType); + } + return _container.GetCurrentRegistrations().Any(x => x.ServiceType == serviceType); } /// - public void Register(Func factory, Type serviceType, string? contract = null) + public void Register(Func factory, Type? serviceType, string? contract = null) { // The function does nothing because there should be no registration called on this object. // Anyway, Locator.SetLocator performs some unnecessary registrations. } /// - public void UnregisterCurrent(Type serviceType, string? contract = null) + public void UnregisterCurrent(Type? serviceType, string? contract = null) { throw new NotImplementedException(); } /// - public void UnregisterAll(Type serviceType, string? contract = null) + public void UnregisterAll(Type? serviceType, string? contract = null) { throw new NotImplementedException(); } diff --git a/src/Splat.SimpleInjector/SimpleInjectorInitializer.cs b/src/Splat.SimpleInjector/SimpleInjectorInitializer.cs index 534014c8c..5f711d7be 100644 --- a/src/Splat.SimpleInjector/SimpleInjectorInitializer.cs +++ b/src/Splat.SimpleInjector/SimpleInjectorInitializer.cs @@ -24,8 +24,13 @@ public class SimpleInjectorInitializer : IDependencyResolver = new(); /// - public object? GetService(Type serviceType, string? contract = null) + public object? GetService(Type? serviceType, string? contract = null) { + if (serviceType is null) + { + serviceType = typeof(NullServiceType); + } + lock (_lockObject) { Func? fact = RegisteredFactories[serviceType].LastOrDefault(); @@ -38,7 +43,7 @@ public IEnumerable GetServices(Type? serviceType, string? contract = nul { if (serviceType is null) { - throw new ArgumentNullException(nameof(serviceType)); + serviceType = typeof(NullServiceType); } lock (_lockObject) @@ -49,8 +54,13 @@ public IEnumerable GetServices(Type? serviceType, string? contract = nul } /// - public bool HasRegistration(Type serviceType, string? contract = null) + public bool HasRegistration(Type? serviceType, string? contract = null) { + if (serviceType is null) + { + serviceType = typeof(NullServiceType); + } + lock (_lockObject) { return RegisteredFactories.TryGetValue(serviceType, out var values) @@ -59,8 +69,14 @@ public bool HasRegistration(Type serviceType, string? contract = null) } /// - public void Register(Func factory, Type serviceType, string? contract = null) + public void Register(Func factory, Type? serviceType, string? contract = null) { + var isNull = serviceType is null; + if (serviceType is null) + { + serviceType = typeof(NullServiceType); + } + lock (_lockObject) { if (!RegisteredFactories.ContainsKey(serviceType)) @@ -68,19 +84,27 @@ public void Register(Func factory, Type serviceType, string? contract = RegisteredFactories.Add(serviceType, new List>()); } - RegisteredFactories[serviceType].Add(factory); + RegisteredFactories[serviceType].Add(() => + isNull + ? new NullServiceType(factory) + : factory()); } } /// - public void UnregisterCurrent(Type serviceType, string? contract = null) + public void UnregisterCurrent(Type? serviceType, string? contract = null) { throw new NotImplementedException(); } /// - public void UnregisterAll(Type serviceType, string? contract = null) + public void UnregisterAll(Type? serviceType, string? contract = null) { + if (serviceType is null) + { + serviceType = typeof(NullServiceType); + } + lock (_lockObject) { if (RegisteredFactories.ContainsKey(serviceType)) diff --git a/src/Splat.Tests/API/ApiApprovalTests.SplatProject.net5.0.approved.txt b/src/Splat.Tests/API/ApiApprovalTests.SplatProject.net5.0.approved.txt index 99f7f793d..b2fe1c7e7 100644 --- a/src/Splat.Tests/API/ApiApprovalTests.SplatProject.net5.0.approved.txt +++ b/src/Splat.Tests/API/ApiApprovalTests.SplatProject.net5.0.approved.txt @@ -161,16 +161,13 @@ namespace Splat { public static T? GetService(this Splat.IReadonlyDependencyResolver resolver, string? contract = null) { } public static System.Collections.Generic.IEnumerable GetServices(this Splat.IReadonlyDependencyResolver resolver, string? contract = null) { } - public static void Register(this Splat.IMutableDependencyResolver resolver, System.Func factory, string? contract = null) - where T : notnull { } + public static void Register(this Splat.IMutableDependencyResolver resolver, System.Func factory, string? contract = null) { } public static void Register(this Splat.IMutableDependencyResolver resolver, string? contract = null) where T : new() { } - public static void RegisterConstant(this Splat.IMutableDependencyResolver resolver, object value, System.Type serviceType, string? contract = null) { } - public static void RegisterConstant(this Splat.IMutableDependencyResolver resolver, T value, string? contract = null) - where T : notnull { } - public static void RegisterLazySingleton(this Splat.IMutableDependencyResolver resolver, System.Func valueFactory, System.Type serviceType, string? contract = null) { } - public static void RegisterLazySingleton(this Splat.IMutableDependencyResolver resolver, System.Func valueFactory, string? contract = null) - where T : notnull { } + public static void RegisterConstant(this Splat.IMutableDependencyResolver resolver, object? value, System.Type? serviceType, string? contract = null) { } + public static void RegisterConstant(this Splat.IMutableDependencyResolver resolver, T? value, string? contract = null) { } + public static void RegisterLazySingleton(this Splat.IMutableDependencyResolver resolver, System.Func valueFactory, System.Type? serviceType, string? contract = null) { } + public static void RegisterLazySingleton(this Splat.IMutableDependencyResolver resolver, System.Func valueFactory, string? contract = null) { } public static System.IDisposable ServiceRegistrationCallback(this Splat.IMutableDependencyResolver resolver, System.Type serviceType, System.Action callback) { } public static void UnregisterAll(this Splat.IMutableDependencyResolver resolver, string? contract = null) { } public static void UnregisterCurrent(this Splat.IMutableDependencyResolver resolver, string? contract = null) { } @@ -196,16 +193,16 @@ namespace Splat } public class FuncDependencyResolver : Splat.IDependencyResolver, Splat.IMutableDependencyResolver, Splat.IReadonlyDependencyResolver, System.IDisposable { - public FuncDependencyResolver(System.Func> getAllServices, System.Action, System.Type, string?>? register = null, System.Action? unregisterCurrent = null, System.Action? unregisterAll = null, System.IDisposable? toDispose = null) { } + public FuncDependencyResolver(System.Func> getAllServices, System.Action, System.Type?, string?>? register = null, System.Action? unregisterCurrent = null, System.Action? unregisterAll = null, System.IDisposable? toDispose = null) { } public void Dispose() { } protected virtual void Dispose(bool isDisposing) { } - public object? GetService(System.Type serviceType, string? contract = null) { } + public object? GetService(System.Type? serviceType, string? contract = null) { } public System.Collections.Generic.IEnumerable GetServices(System.Type? serviceType, string? contract = null) { } - public bool HasRegistration(System.Type serviceType, string? contract = null) { } - public void Register(System.Func factory, System.Type serviceType, string? contract = null) { } + public bool HasRegistration(System.Type? serviceType, string? contract = null) { } + public void Register(System.Func factory, System.Type? serviceType, string? contract = null) { } public System.IDisposable ServiceRegistrationCallback(System.Type serviceType, string? contract, System.Action callback) { } - public void UnregisterAll(System.Type serviceType, string? contract = null) { } - public void UnregisterCurrent(System.Type serviceType, string? contract = null) { } + public void UnregisterAll(System.Type? serviceType, string? contract = null) { } + public void UnregisterCurrent(System.Type? serviceType, string? contract = null) { } } public class FuncLogManager : Splat.ILogManager { @@ -412,15 +409,15 @@ namespace Splat } public interface IMutableDependencyResolver { - bool HasRegistration(System.Type serviceType, string? contract = null); - void Register(System.Func factory, System.Type serviceType, string? contract = null); + bool HasRegistration(System.Type? serviceType, string? contract = null); + void Register(System.Func factory, System.Type? serviceType, string? contract = null); System.IDisposable ServiceRegistrationCallback(System.Type serviceType, string? contract, System.Action callback); - void UnregisterAll(System.Type serviceType, string? contract = null); - void UnregisterCurrent(System.Type serviceType, string? contract = null); + void UnregisterAll(System.Type? serviceType, string? contract = null); + void UnregisterCurrent(System.Type? serviceType, string? contract = null); } public interface IReadonlyDependencyResolver { - object? GetService(System.Type serviceType, string? contract = null); + object? GetService(System.Type? serviceType, string? contract = null); System.Collections.Generic.IEnumerable GetServices(System.Type? serviceType, string? contract = null); } public interface IStaticFullLogger @@ -519,19 +516,19 @@ namespace Splat public class ModernDependencyResolver : Splat.IDependencyResolver, Splat.IMutableDependencyResolver, Splat.IReadonlyDependencyResolver, System.IDisposable { public ModernDependencyResolver() { } - protected ModernDependencyResolver([System.Runtime.CompilerServices.TupleElementNames(new string[] { + protected ModernDependencyResolver([System.Runtime.CompilerServices.TupleElementNames(new string?[]?[] { "serviceType", "contract"})] System.Collections.Generic.Dictionary, System.Collections.Generic.List>>? registry) { } public void Dispose() { } protected virtual void Dispose(bool isDisposing) { } public Splat.ModernDependencyResolver Duplicate() { } - public object? GetService(System.Type serviceType, string? contract = null) { } + public object? GetService(System.Type? serviceType, string? contract = null) { } public System.Collections.Generic.IEnumerable GetServices(System.Type? serviceType, string? contract = null) { } - public bool HasRegistration(System.Type serviceType, string? contract = null) { } - public void Register(System.Func factory, System.Type serviceType, string? contract = null) { } + public bool HasRegistration(System.Type? serviceType, string? contract = null) { } + public void Register(System.Func factory, System.Type? serviceType, string? contract = null) { } public System.IDisposable ServiceRegistrationCallback(System.Type serviceType, string? contract, System.Action callback) { } - public void UnregisterAll(System.Type serviceType, string? contract = null) { } - public void UnregisterCurrent(System.Type serviceType, string? contract = null) { } + public void UnregisterAll(System.Type? serviceType, string? contract = null) { } + public void UnregisterCurrent(System.Type? serviceType, string? contract = null) { } } public class NullLogger : Splat.ILogger { @@ -542,6 +539,11 @@ namespace Splat public void Write([System.ComponentModel.Localizable(false)] string message, [System.ComponentModel.Localizable(false)] System.Type type, Splat.LogLevel logLevel) { } public void Write(System.Exception exception, [System.ComponentModel.Localizable(false)] string message, [System.ComponentModel.Localizable(false)] System.Type type, Splat.LogLevel logLevel) { } } + public class NullServiceType + { + public NullServiceType(System.Func factory) { } + public System.Func Factory { get; } + } public static class PointMathExtensions { public static float AngleInDegrees(this System.Drawing.PointF value) { } diff --git a/src/Splat.Tests/API/ApiApprovalTests.SplatProject.netcoreapp3.1.approved.txt b/src/Splat.Tests/API/ApiApprovalTests.SplatProject.netcoreapp3.1.approved.txt index 4b39dc0c7..9d1aed7f6 100644 --- a/src/Splat.Tests/API/ApiApprovalTests.SplatProject.netcoreapp3.1.approved.txt +++ b/src/Splat.Tests/API/ApiApprovalTests.SplatProject.netcoreapp3.1.approved.txt @@ -161,16 +161,13 @@ namespace Splat { public static T? GetService(this Splat.IReadonlyDependencyResolver resolver, string? contract = null) { } public static System.Collections.Generic.IEnumerable GetServices(this Splat.IReadonlyDependencyResolver resolver, string? contract = null) { } - public static void Register(this Splat.IMutableDependencyResolver resolver, System.Func factory, string? contract = null) - where T : notnull { } + public static void Register(this Splat.IMutableDependencyResolver resolver, System.Func factory, string? contract = null) { } public static void Register(this Splat.IMutableDependencyResolver resolver, string? contract = null) where T : new() { } - public static void RegisterConstant(this Splat.IMutableDependencyResolver resolver, object value, System.Type serviceType, string? contract = null) { } - public static void RegisterConstant(this Splat.IMutableDependencyResolver resolver, T value, string? contract = null) - where T : notnull { } - public static void RegisterLazySingleton(this Splat.IMutableDependencyResolver resolver, System.Func valueFactory, System.Type serviceType, string? contract = null) { } - public static void RegisterLazySingleton(this Splat.IMutableDependencyResolver resolver, System.Func valueFactory, string? contract = null) - where T : notnull { } + public static void RegisterConstant(this Splat.IMutableDependencyResolver resolver, object? value, System.Type? serviceType, string? contract = null) { } + public static void RegisterConstant(this Splat.IMutableDependencyResolver resolver, T? value, string? contract = null) { } + public static void RegisterLazySingleton(this Splat.IMutableDependencyResolver resolver, System.Func valueFactory, System.Type? serviceType, string? contract = null) { } + public static void RegisterLazySingleton(this Splat.IMutableDependencyResolver resolver, System.Func valueFactory, string? contract = null) { } public static System.IDisposable ServiceRegistrationCallback(this Splat.IMutableDependencyResolver resolver, System.Type serviceType, System.Action callback) { } public static void UnregisterAll(this Splat.IMutableDependencyResolver resolver, string? contract = null) { } public static void UnregisterCurrent(this Splat.IMutableDependencyResolver resolver, string? contract = null) { } @@ -196,16 +193,16 @@ namespace Splat } public class FuncDependencyResolver : Splat.IDependencyResolver, Splat.IMutableDependencyResolver, Splat.IReadonlyDependencyResolver, System.IDisposable { - public FuncDependencyResolver(System.Func> getAllServices, System.Action, System.Type, string?>? register = null, System.Action? unregisterCurrent = null, System.Action? unregisterAll = null, System.IDisposable? toDispose = null) { } + public FuncDependencyResolver(System.Func> getAllServices, System.Action, System.Type?, string?>? register = null, System.Action? unregisterCurrent = null, System.Action? unregisterAll = null, System.IDisposable? toDispose = null) { } public void Dispose() { } protected virtual void Dispose(bool isDisposing) { } - public object? GetService(System.Type serviceType, string? contract = null) { } + public object? GetService(System.Type? serviceType, string? contract = null) { } public System.Collections.Generic.IEnumerable GetServices(System.Type? serviceType, string? contract = null) { } - public bool HasRegistration(System.Type serviceType, string? contract = null) { } - public void Register(System.Func factory, System.Type serviceType, string? contract = null) { } + public bool HasRegistration(System.Type? serviceType, string? contract = null) { } + public void Register(System.Func factory, System.Type? serviceType, string? contract = null) { } public System.IDisposable ServiceRegistrationCallback(System.Type serviceType, string? contract, System.Action callback) { } - public void UnregisterAll(System.Type serviceType, string? contract = null) { } - public void UnregisterCurrent(System.Type serviceType, string? contract = null) { } + public void UnregisterAll(System.Type? serviceType, string? contract = null) { } + public void UnregisterCurrent(System.Type? serviceType, string? contract = null) { } } public class FuncLogManager : Splat.ILogManager { @@ -412,15 +409,15 @@ namespace Splat } public interface IMutableDependencyResolver { - bool HasRegistration(System.Type serviceType, string? contract = null); - void Register(System.Func factory, System.Type serviceType, string? contract = null); + bool HasRegistration(System.Type? serviceType, string? contract = null); + void Register(System.Func factory, System.Type? serviceType, string? contract = null); System.IDisposable ServiceRegistrationCallback(System.Type serviceType, string? contract, System.Action callback); - void UnregisterAll(System.Type serviceType, string? contract = null); - void UnregisterCurrent(System.Type serviceType, string? contract = null); + void UnregisterAll(System.Type? serviceType, string? contract = null); + void UnregisterCurrent(System.Type? serviceType, string? contract = null); } public interface IReadonlyDependencyResolver { - object? GetService(System.Type serviceType, string? contract = null); + object? GetService(System.Type? serviceType, string? contract = null); System.Collections.Generic.IEnumerable GetServices(System.Type? serviceType, string? contract = null); } public interface IStaticFullLogger @@ -519,19 +516,19 @@ namespace Splat public class ModernDependencyResolver : Splat.IDependencyResolver, Splat.IMutableDependencyResolver, Splat.IReadonlyDependencyResolver, System.IDisposable { public ModernDependencyResolver() { } - protected ModernDependencyResolver([System.Runtime.CompilerServices.TupleElementNames(new string[] { + protected ModernDependencyResolver([System.Runtime.CompilerServices.TupleElementNames(new string?[]?[] { "serviceType", "contract"})] System.Collections.Generic.Dictionary, System.Collections.Generic.List>>? registry) { } public void Dispose() { } protected virtual void Dispose(bool isDisposing) { } public Splat.ModernDependencyResolver Duplicate() { } - public object? GetService(System.Type serviceType, string? contract = null) { } + public object? GetService(System.Type? serviceType, string? contract = null) { } public System.Collections.Generic.IEnumerable GetServices(System.Type? serviceType, string? contract = null) { } - public bool HasRegistration(System.Type serviceType, string? contract = null) { } - public void Register(System.Func factory, System.Type serviceType, string? contract = null) { } + public bool HasRegistration(System.Type? serviceType, string? contract = null) { } + public void Register(System.Func factory, System.Type? serviceType, string? contract = null) { } public System.IDisposable ServiceRegistrationCallback(System.Type serviceType, string? contract, System.Action callback) { } - public void UnregisterAll(System.Type serviceType, string? contract = null) { } - public void UnregisterCurrent(System.Type serviceType, string? contract = null) { } + public void UnregisterAll(System.Type? serviceType, string? contract = null) { } + public void UnregisterCurrent(System.Type? serviceType, string? contract = null) { } } public class NullLogger : Splat.ILogger { @@ -542,6 +539,11 @@ namespace Splat public void Write([System.ComponentModel.Localizable(false)] string message, [System.ComponentModel.Localizable(false)] System.Type type, Splat.LogLevel logLevel) { } public void Write(System.Exception exception, [System.ComponentModel.Localizable(false)] string message, [System.ComponentModel.Localizable(false)] System.Type type, Splat.LogLevel logLevel) { } } + public class NullServiceType + { + public NullServiceType(System.Func factory) { } + public System.Func Factory { get; } + } public static class PointMathExtensions { public static float AngleInDegrees(this System.Drawing.PointF value) { } diff --git a/src/Splat.Tests/LocatorSerialRegisterTests.cs b/src/Splat.Tests/LocatorSerialRegisterTests.cs index ca5f7f1f7..fbc29d608 100644 --- a/src/Splat.Tests/LocatorSerialRegisterTests.cs +++ b/src/Splat.Tests/LocatorSerialRegisterTests.cs @@ -311,8 +311,8 @@ public void ModernDependencyResolver_UnregisterCurrent_NoValuesWorks() public void FuncDependencyResolver_UnregisterAll() { bool unregisterAllCalled = false; - Type type = null; - string contract = null; + Type? type = null; + string? contract = null; var currentMutable = new FuncDependencyResolver( (funcType, funcContract) => Array.Empty(), @@ -343,8 +343,8 @@ public void FuncDependencyResolver_UnregisterAll() public void FuncDependencyResolver_UnregisterCurrent() { bool unregisterAllCalled = false; - Type type = null; - string contract = null; + Type? type = null; + string? contract = null; var currentMutable = new FuncDependencyResolver( (funcType, funcContract) => Array.Empty(), diff --git a/src/Splat.Tests/LocatorTests.cs b/src/Splat.Tests/LocatorTests.cs index 5157af9af..3bff4c5cd 100644 --- a/src/Splat.Tests/LocatorTests.cs +++ b/src/Splat.Tests/LocatorTests.cs @@ -17,6 +17,28 @@ namespace Splat.Tests /// public class LocatorTests { + /// + /// Shoulds the resolve nulls. + /// + [Fact] + public void Can_Register_And_Resolve_Null_Types() + { + var container = new InternalLocator(); + + var foo = 5; + container.CurrentMutable.Register(() => foo, null!); + + var bar = 4; + var contract = "foo"; + container.CurrentMutable.Register(() => bar, null!, contract); + + var value = container.Current.GetService(null!); + Assert.Equal(foo, value); + + value = container.Current.GetService(null!, contract); + Assert.Equal(bar, value); + } + /// /// Tests if the registrations are not empty on no external registrations. /// diff --git a/src/Splat.Tests/ServiceLocation/BaseDependencyResolverTests.cs b/src/Splat.Tests/ServiceLocation/BaseDependencyResolverTests.cs index 4e9c7522e..d9acf3526 100644 --- a/src/Splat.Tests/ServiceLocation/BaseDependencyResolverTests.cs +++ b/src/Splat.Tests/ServiceLocation/BaseDependencyResolverTests.cs @@ -178,9 +178,10 @@ public void ILogManager_Resolvable() [Fact] public void NullResolverTests() { - IReadonlyDependencyResolver resolver = default; - IMutableDependencyResolver resolver1 = default; - IDependencyResolver resolver2 = default; + IReadonlyDependencyResolver? resolver = default; + IMutableDependencyResolver? resolver1 = default; + IDependencyResolver? resolver2 = default; +#pragma warning disable CS8604 // Possible null reference argument. Assert.Throws(() => resolver.GetService()); Assert.Throws(() => resolver.GetServices()); Assert.Throws(() => resolver1.ServiceRegistrationCallback(typeof(ILogManager), (IDisposable d) => { d.Dispose(); })); @@ -201,6 +202,7 @@ public void NullResolverTests() Assert.Throws(() => resolver1.RegisterConstantAnd(new ViewModelOne())); Assert.Throws(() => resolver1.RegisterConstantAnd(new ViewModelOne(), typeof(ViewModelOne))); Assert.Throws(() => resolver1.RegisterConstantAnd()); +#pragma warning restore CS8604 // Possible null reference argument. } /// @@ -210,7 +212,7 @@ public void NullResolverTests() public void RegisterAndTests() { var resolver = GetDependencyResolver(); - Assert.Throws(() => resolver.RegisterAnd(null)); + Assert.Throws(() => resolver.RegisterAnd(default!)); resolver.RegisterAnd("one") .RegisterAnd("two") .RegisterAnd(() => new DefaultLogManager(), "three") diff --git a/src/Splat/ServiceLocation/DependencyResolverMixins.cs b/src/Splat/ServiceLocation/DependencyResolverMixins.cs index b286f172b..236a602f8 100644 --- a/src/Splat/ServiceLocation/DependencyResolverMixins.cs +++ b/src/Splat/ServiceLocation/DependencyResolverMixins.cs @@ -43,14 +43,14 @@ public static class DependencyResolverMixins /// A optional value which will retrieve only a object registered with the same contract. /// A sequence of instances of the requested . The sequence /// should be empty (not null) if no objects of the given type are available. - public static IEnumerable GetServices(this IReadonlyDependencyResolver resolver, string? contract = null) + public static IEnumerable GetServices(this IReadonlyDependencyResolver resolver, string? contract = null) { if (resolver is null) { throw new ArgumentNullException(nameof(resolver)); } - return resolver.GetServices(typeof(T), contract).Cast(); + return resolver.GetServices(typeof(T), contract).Cast(); } /// @@ -139,7 +139,7 @@ public static void Register(this IMutableDependencyResolver resolver, st /// The specified instance to always return. /// The type of service to register. /// A optional contract value which will indicates to only return the value if this contract is specified. - public static void RegisterConstant(this IMutableDependencyResolver resolver, object? value, Type serviceType, string? contract = null) + public static void RegisterConstant(this IMutableDependencyResolver resolver, object? value, Type? serviceType, string? contract = null) { if (resolver is null) { @@ -174,7 +174,7 @@ public static void RegisterConstant(this IMutableDependencyResolver resolver, /// A factory method for generating a object of the specified type. /// The type of service to register. /// A optional contract value which will indicates to only return the value if this contract is specified. - public static void RegisterLazySingleton(this IMutableDependencyResolver resolver, Func valueFactory, Type serviceType, string? contract = null) + public static void RegisterLazySingleton(this IMutableDependencyResolver resolver, Func valueFactory, Type? serviceType, string? contract = null) { if (resolver is null) { diff --git a/src/Splat/ServiceLocation/FuncDependencyResolver.cs b/src/Splat/ServiceLocation/FuncDependencyResolver.cs index 75c93cc1f..0679690ea 100644 --- a/src/Splat/ServiceLocation/FuncDependencyResolver.cs +++ b/src/Splat/ServiceLocation/FuncDependencyResolver.cs @@ -17,11 +17,11 @@ namespace Splat /// public class FuncDependencyResolver : IDependencyResolver { - private readonly Func> _innerGetServices; - private readonly Action, Type, string?>? _innerRegister; - private readonly Action? _unregisterCurrent; - private readonly Action? _unregisterAll; - private readonly Dictionary<(Type type, string callback), List>> _callbackRegistry = new(); + private readonly Func> _innerGetServices; + private readonly Action, Type?, string?>? _innerRegister; + private readonly Action? _unregisterCurrent; + private readonly Action? _unregisterAll; + private readonly Dictionary<(Type? type, string callback), List>> _callbackRegistry = new(); private IDisposable _inner; private bool _isDisposed; @@ -35,10 +35,10 @@ public class FuncDependencyResolver : IDependencyResolver /// A func which will unregister all the registered elements for a service type and contract. /// A optional disposable which is called when this resolver is disposed. public FuncDependencyResolver( - Func> getAllServices, - Action, Type, string?>? register = null, - Action? unregisterCurrent = null, - Action? unregisterAll = null, + Func> getAllServices, + Action, Type?, string?>? register = null, + Action? unregisterCurrent = null, + Action? unregisterAll = null, IDisposable? toDispose = null) { _innerGetServices = getAllServices; @@ -49,37 +49,53 @@ public FuncDependencyResolver( } /// - public object? GetService(Type serviceType, string? contract = null) - { - return (GetServices(serviceType, contract) ?? Array.Empty()).LastOrDefault(); - } + public object? GetService(Type? serviceType, string? contract = null) => + GetServices(serviceType, contract).LastOrDefault(); /// public IEnumerable GetServices(Type? serviceType, string? contract = null) { if (serviceType is null) { - throw new ArgumentNullException(nameof(serviceType)); + serviceType = typeof(NullServiceType); } - return _innerGetServices(serviceType, contract); + return _innerGetServices(serviceType, contract) ?? Array.Empty(); } /// - public bool HasRegistration(Type serviceType, string? contract = null) + public bool HasRegistration(Type? serviceType, string? contract = null) { + if (serviceType is null) + { + serviceType = typeof(NullServiceType); + } + return _innerGetServices(serviceType, contract) is not null; } /// - public void Register(Func factory, Type serviceType, string? contract = null) + public void Register(Func factory, Type? serviceType, string? contract = null) { if (_innerRegister is null) { throw new NotImplementedException(); } - _innerRegister(factory, serviceType, contract); + var isNull = serviceType is null; + + if (serviceType is null) + { + serviceType = typeof(NullServiceType); + } + + _innerRegister( + () => + isNull + ? new NullServiceType(factory) + : factory(), + serviceType, + contract); var pair = (serviceType, contract ?? string.Empty); @@ -110,24 +126,34 @@ public void Register(Func factory, Type serviceType, string? contract = } /// - public void UnregisterCurrent(Type serviceType, string? contract = null) + public void UnregisterCurrent(Type? serviceType, string? contract = null) { if (_unregisterCurrent is null) { throw new NotImplementedException(); } + if (serviceType is null) + { + serviceType = typeof(NullServiceType); + } + _unregisterCurrent.Invoke(serviceType, contract); } /// - public void UnregisterAll(Type serviceType, string? contract = null) + public void UnregisterAll(Type? serviceType, string? contract = null) { if (_unregisterAll is null) { throw new NotImplementedException(); } + if (serviceType is null) + { + serviceType = typeof(NullServiceType); + } + _unregisterAll.Invoke(serviceType, contract); } diff --git a/src/Splat/ServiceLocation/IMutableDependencyResolver.cs b/src/Splat/ServiceLocation/IMutableDependencyResolver.cs index 234114b30..861c2c8cc 100644 --- a/src/Splat/ServiceLocation/IMutableDependencyResolver.cs +++ b/src/Splat/ServiceLocation/IMutableDependencyResolver.cs @@ -18,7 +18,7 @@ public interface IMutableDependencyResolver /// The type to check for registration. /// Whether there is a registration for the type. /// A optional contract value which will indicates to only generate the value if this contract is specified. - bool HasRegistration(Type serviceType, string? contract = null); + bool HasRegistration(Type? serviceType, string? contract = null); /// /// Register a function with the resolver which will generate a object @@ -30,21 +30,21 @@ public interface IMutableDependencyResolver /// The factory function which generates our object. /// The type which is used for the registration. /// A optional contract value which will indicates to only generate the value if this contract is specified. - void Register(Func factory, Type serviceType, string? contract = null); + void Register(Func factory, Type? serviceType, string? contract = null); /// /// Unregisters the current item based on the specified type and contract. /// /// The service type to unregister. /// The optional contract value, which will only remove the value associated with the contract. - void UnregisterCurrent(Type serviceType, string? contract = null); + void UnregisterCurrent(Type? serviceType, string? contract = null); /// /// Unregisters all the values associated with the specified type and contract. /// /// The service type to unregister. /// The optional contract value, which will only remove the value associated with the contract. - void UnregisterAll(Type serviceType, string? contract = null); + void UnregisterAll(Type? serviceType, string? contract = null); /// /// Register a callback to be called when a new service matching the type diff --git a/src/Splat/ServiceLocation/IReadonlyDependencyResolver.cs b/src/Splat/ServiceLocation/IReadonlyDependencyResolver.cs index 28451743a..a34735818 100644 --- a/src/Splat/ServiceLocation/IReadonlyDependencyResolver.cs +++ b/src/Splat/ServiceLocation/IReadonlyDependencyResolver.cs @@ -19,7 +19,7 @@ public interface IReadonlyDependencyResolver /// The object type. /// A optional value which will retrieve only a object registered with the same contract. /// The requested object, if found; null otherwise. - object? GetService(Type serviceType, string? contract = null); + object? GetService(Type? serviceType, string? contract = null); /// /// Gets all instances of the given . Must return an empty diff --git a/src/Splat/ServiceLocation/ModernDependencyResolver.cs b/src/Splat/ServiceLocation/ModernDependencyResolver.cs index a1b0e6d64..c154ad43f 100644 --- a/src/Splat/ServiceLocation/ModernDependencyResolver.cs +++ b/src/Splat/ServiceLocation/ModernDependencyResolver.cs @@ -53,33 +53,48 @@ protected ModernDependencyResolver(Dictionary<(Type serviceType, string? contrac } /// - public bool HasRegistration(Type serviceType, string? contract = null) + public bool HasRegistration(Type? serviceType, string? contract = null) { if (_registry is null) { return false; } + if (serviceType is null) + { + serviceType = typeof(NullServiceType); + } + var pair = GetKey(serviceType, contract); return _registry.TryGetValue(pair, out var registrations) && registrations.Count > 0; } /// - public void Register(Func factory, Type serviceType, string? contract = null) + public void Register(Func factory, Type? serviceType, string? contract = null) { - var pair = GetKey(serviceType, contract); - if (_registry is null) { return; } + var isNull = serviceType is null; + + if (serviceType is null) + { + serviceType = typeof(NullServiceType); + } + + var pair = GetKey(serviceType, contract); + if (!_registry.ContainsKey(pair)) { _registry[pair] = new List>(); } - _registry[pair].Add(factory); + _registry[pair].Add(() => + isNull + ? new NullServiceType(factory) + : factory()); if (_callbackRegistry.ContainsKey(pair)) { @@ -108,13 +123,18 @@ public void Register(Func factory, Type serviceType, string? contract = } /// - public object? GetService(Type serviceType, string? contract = null) + public object? GetService(Type? serviceType, string? contract = null) { if (_registry is null) { return default; } + if (serviceType is null) + { + serviceType = typeof(NullServiceType); + } + var pair = GetKey(serviceType, contract); if (!_registry.ContainsKey(pair)) { @@ -122,20 +142,30 @@ public void Register(Func factory, Type serviceType, string? contract = } var ret = _registry[pair].LastOrDefault(); - return ret is null ? default : ret(); + object? returnValue = default; + if (ret != null) + { + returnValue = ret(); + if (returnValue is NullServiceType nullServiceType) + { + return nullServiceType.Factory()!; + } + } + + return returnValue; } /// public IEnumerable GetServices(Type? serviceType, string? contract = null) { - if (serviceType == null) + if (_registry is null) { - throw new ArgumentNullException(nameof(serviceType)); + return Array.Empty(); } - if (_registry is null) + if (serviceType is null) { - return Array.Empty(); + serviceType = typeof(NullServiceType); } var pair = GetKey(serviceType, contract); @@ -148,13 +178,18 @@ public IEnumerable GetServices(Type? serviceType, string? contract = nul } /// - public void UnregisterCurrent(Type serviceType, string? contract = null) + public void UnregisterCurrent(Type? serviceType, string? contract = null) { if (_registry is null) { return; } + if (serviceType is null) + { + serviceType = typeof(NullServiceType); + } + var pair = GetKey(serviceType, contract); if (!_registry.TryGetValue(pair, out var list)) @@ -172,13 +207,18 @@ public void UnregisterCurrent(Type serviceType, string? contract = null) } /// - public void UnregisterAll(Type serviceType, string? contract = null) + public void UnregisterAll(Type? serviceType, string? contract = null) { if (_registry is null) { return; } + if (serviceType is null) + { + serviceType = typeof(NullServiceType); + } + var pair = GetKey(serviceType, contract); _registry[pair] = new List>(); @@ -229,10 +269,7 @@ public IDisposable ServiceRegistrationCallback(Type serviceType, string? contrac /// Useful if you want to generate temporary resolver using the method. /// /// The newly generated class with the current registrations. - public ModernDependencyResolver Duplicate() - { - return new ModernDependencyResolver(_registry); - } + public ModernDependencyResolver Duplicate() => new(_registry); /// public void Dispose() @@ -261,8 +298,8 @@ protected virtual void Dispose(bool isDisposing) } private static (Type type, string contract) GetKey( - Type serviceType, + Type? serviceType, string? contract = null) => - (serviceType, contract ?? string.Empty); + (serviceType!, contract ?? string.Empty); } } diff --git a/src/Splat/ServiceLocation/NullServiceType.cs b/src/Splat/ServiceLocation/NullServiceType.cs new file mode 100644 index 000000000..64dd58589 --- /dev/null +++ b/src/Splat/ServiceLocation/NullServiceType.cs @@ -0,0 +1,26 @@ +// Copyright (c) 2021 .NET Foundation and Contributors. All rights reserved. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for full license information. + +using System; + +namespace Splat +{ + /// + /// Null Service Type. + /// + public class NullServiceType + { + /// + /// Initializes a new instance of the class. + /// + /// The value factory. + public NullServiceType(Func factory) => Factory = factory; + + /// + /// Gets the Factory. + /// + public Func Factory { get; } + } +} From 74290f87f3cb7de5f6c5da304115df7084f6d8ae Mon Sep 17 00:00:00 2001 From: Chris Pulman Date: Thu, 22 Jul 2021 01:23:45 +0100 Subject: [PATCH 7/9] fix Dryloc resolver contract issue resolved items registered with Dryloc resolver were not retained but overwritten where multiple registrations were made with the same serviceType and different contracts --- src/Splat.DryIoc/DryIocDependencyResolver.cs | 114 ++++++++++++------- 1 file changed, 72 insertions(+), 42 deletions(-) diff --git a/src/Splat.DryIoc/DryIocDependencyResolver.cs b/src/Splat.DryIoc/DryIocDependencyResolver.cs index dffada080..cb118105c 100644 --- a/src/Splat.DryIoc/DryIocDependencyResolver.cs +++ b/src/Splat.DryIoc/DryIocDependencyResolver.cs @@ -37,9 +37,20 @@ public DryIocDependencyResolver(IContainer? container = null) serviceType = typeof(NullServiceType); } - return string.IsNullOrEmpty(contract) - ? _container.ResolveMany(serviceType).Select(x => isNull ? ((NullServiceType)x).Factory()! : x).LastOrDefault() - : _container.ResolveMany(serviceType, serviceKey: contract).Select(x => isNull ? ((NullServiceType)x).Factory()! : x).LastOrDefault(); + var key = (serviceType, contract ?? string.Empty); + var registeredinSplat = _container.ResolveMany(serviceType, serviceKey: key).Select(x => isNull ? ((NullServiceType)x).Factory()! : x); + if (registeredinSplat.Any()) + { + return registeredinSplat.LastOrDefault(); + } + + var registeredWithContract = _container.ResolveMany(serviceType, serviceKey: contract).Select(x => isNull ? ((NullServiceType)x).Factory()! : x); + if (registeredWithContract.Any()) + { + return registeredWithContract.LastOrDefault(); + } + + return _container.ResolveMany(serviceType).Select(x => isNull ? ((NullServiceType)x).Factory()! : x).LastOrDefault(); } /// @@ -51,9 +62,20 @@ public virtual IEnumerable GetServices(Type? serviceType, string? contra serviceType = typeof(NullServiceType); } - return string.IsNullOrEmpty(contract) - ? _container.ResolveMany(serviceType).Select(x => isNull ? ((NullServiceType)x).Factory()! : x) - : _container.ResolveMany(serviceType, serviceKey: contract).Select(x => isNull ? ((NullServiceType)x).Factory()! : x); + var key = (serviceType, contract ?? string.Empty); + var registeredinSplat = _container.ResolveMany(serviceType, serviceKey: key).Select(x => isNull ? ((NullServiceType)x).Factory()! : x); + if (registeredinSplat.Any()) + { + return registeredinSplat; + } + + var registeredWithContract = _container.ResolveMany(serviceType, serviceKey: contract).Select(x => isNull ? ((NullServiceType)x).Factory()! : x); + if (registeredWithContract.Any()) + { + return registeredWithContract; + } + + return _container.ResolveMany(serviceType).Select(x => isNull ? ((NullServiceType)x).Factory()! : x); } /// @@ -71,13 +93,12 @@ public bool HasRegistration(Type? serviceType, string? contract = null) return false; } - if (contract is null) - { - return x.OptionalServiceKey is null; - } + var key = (serviceType, contract ?? string.Empty); - return x.OptionalServiceKey is string serviceKeyAsString - && contract.Equals(serviceKeyAsString, StringComparison.Ordinal); + return key.Equals(x.OptionalServiceKey) || + (contract is null && x.OptionalServiceKey is null) || + (x.OptionalServiceKey is string serviceKeyAsString + && contract is not null && contract.Equals(serviceKeyAsString, StringComparison.Ordinal)); }); } @@ -95,21 +116,12 @@ public virtual void Register(Func factory, Type? serviceType, string? c serviceType = typeof(NullServiceType); } - if (string.IsNullOrEmpty(contract)) - { - _container.UseInstance( - serviceType, - isNull ? new NullServiceType(factory) : factory(), - IfAlreadyRegistered.AppendNewImplementation); - } - else - { - _container.UseInstance( - serviceType, - isNull ? new NullServiceType(factory) : factory(), - IfAlreadyRegistered.AppendNewImplementation, - serviceKey: contract); - } + var key = (serviceType, contract ?? string.Empty); + + _container.UseInstance( + serviceType, + isNull ? new NullServiceType(factory) : factory(), + serviceKey: key); } /// @@ -120,14 +132,35 @@ public virtual void UnregisterCurrent(Type? serviceType, string? contract = null serviceType = typeof(NullServiceType); } - if (string.IsNullOrEmpty(contract)) - { - _container.Unregister(serviceType); - } - else + var hadvalue = _container.GetServiceRegistrations().Any(x => { - _container.Unregister(serviceType, contract); - } + if (x.ServiceType != serviceType) + { + return false; + } + + var key = (serviceType, contract ?? string.Empty); + if (key.Equals(x.OptionalServiceKey)) + { + _container.Unregister(serviceType, key); + return true; + } + + if (contract is null && x.OptionalServiceKey is null) + { + _container.Unregister(serviceType); + return true; + } + + if (x.OptionalServiceKey is string serviceKeyAsString + && contract is not null && contract.Equals(serviceKeyAsString, StringComparison.Ordinal)) + { + _container.Unregister(serviceType, contract); + return true; + } + + return false; + }); } /// @@ -138,14 +171,11 @@ public virtual void UnregisterAll(Type? serviceType, string? contract = null) serviceType = typeof(NullServiceType); } - if (string.IsNullOrEmpty(contract)) - { - _container.Unregister(serviceType); - } - else - { - _container.Unregister(serviceType, contract); - } + var key = (serviceType, contract ?? string.Empty); + + _container.Unregister(serviceType, key); + _container.Unregister(serviceType, contract); + _container.Unregister(serviceType); } /// From e830edaed64929014c3f7f365603fee9e81d57bb Mon Sep 17 00:00:00 2001 From: Chris Pulman Date: Sun, 25 Jul 2021 20:12:32 +0100 Subject: [PATCH 8/9] updated some tests need to refresh codecov to discover remaining tests required --- .../DependencyResolverTests.cs | 15 ++++++ .../AutofacDependencyResolver.cs | 50 ++++++++++++++----- src/Splat.Common.Test/DummyObjectClass1.cs | 3 ++ src/Splat.Common.Test/DummyObjectClass2.cs | 3 ++ src/Splat.Common.Test/DummyObjectClass3.cs | 3 ++ src/Splat.Common.Test/MockScreen.cs | 3 ++ src/Splat.Common.Test/ViewModelOne.cs | 3 ++ src/Splat.Common.Test/ViewModelTwo.cs | 3 ++ src/Splat.Common.Test/ViewOne.cs | 3 ++ src/Splat.Common.Test/ViewTwo.cs | 3 ++ .../DependencyResolverTests.cs | 12 +++++ src/Splat.DryIoc/DryIocDependencyResolver.cs | 8 +-- .../MicrosoftDependencyResolverTests.cs | 16 ++++-- .../NInjectDependencyResolverTests.cs | 22 +++++--- .../NinjectDependencyResolver.cs | 15 +++--- src/Splat.Tests/LocatorTests.cs | 11 +++- 16 files changed, 138 insertions(+), 35 deletions(-) diff --git a/src/Splat.Autofac.Tests/DependencyResolverTests.cs b/src/Splat.Autofac.Tests/DependencyResolverTests.cs index 71d3ec117..99a88784c 100644 --- a/src/Splat.Autofac.Tests/DependencyResolverTests.cs +++ b/src/Splat.Autofac.Tests/DependencyResolverTests.cs @@ -4,6 +4,7 @@ // See the LICENSE file in the project root for full license information. using System; +using System.Linq; using Autofac; using FluentAssertions; @@ -36,11 +37,25 @@ public void Can_Register_And_Resolve_Null_Types() Locator.CurrentMutable.Register(() => bar, null, contract); autofacResolver.SetLifetimeScope(builder.Build()); + Assert.True(Locator.CurrentMutable.HasRegistration(null)); var value = Locator.Current.GetService(null); Assert.Equal(foo, value); + Assert.True(Locator.CurrentMutable.HasRegistration(null, contract)); value = Locator.Current.GetService(null, contract); Assert.Equal(bar, value); + + var values = Locator.Current.GetServices(null); + Assert.Equal(foo, (int)values.First()); + Assert.Equal(1, values.Count()); + + Assert.Throws(() => Locator.CurrentMutable.UnregisterCurrent(null)); + var valuesNC = Locator.Current.GetServices(null); + Assert.Equal(1, valuesNC.Count()); + Assert.Equal(foo, (int)valuesNC.First()); + var valuesC = Locator.Current.GetServices(null, contract); + Assert.Equal(1, valuesC.Count()); + Assert.Equal(bar, (int)valuesC.First()); } /// diff --git a/src/Splat.Autofac/AutofacDependencyResolver.cs b/src/Splat.Autofac/AutofacDependencyResolver.cs index ef10a3dae..8e97b064f 100644 --- a/src/Splat.Autofac/AutofacDependencyResolver.cs +++ b/src/Splat.Autofac/AutofacDependencyResolver.cs @@ -52,6 +52,7 @@ public AutofacDependencyResolver(ContainerBuilder builder) /// public virtual object? GetService(Type? serviceType, string? contract = null) { + var isNull = serviceType is null; if (serviceType is null) { serviceType = typeof(NullServiceType); @@ -59,7 +60,8 @@ public AutofacDependencyResolver(ContainerBuilder builder) lock (_lockObject) { - return Resolve(serviceType, contract); + var result = Resolve(serviceType, contract); + return isNull ? (result as NullServiceType)?.Factory() : result; } } @@ -90,6 +92,7 @@ public void SetLifetimeScope(ILifetimeScope lifetimeScope) /// public virtual IEnumerable GetServices(Type? serviceType, string? contract = null) { + var isNull = serviceType is null; if (serviceType is null) { serviceType = typeof(NullServiceType); @@ -102,17 +105,27 @@ public virtual IEnumerable GetServices(Type? serviceType, string? contra var enumerableType = typeof(IEnumerable<>).MakeGenericType(serviceType); var instance = Resolve(enumerableType, contract); - if (instance is not null) + if (isNull && instance is IEnumerable nullService) { - return new object[] { instance }; + foreach (var item in nullService) + { + yield return item.Factory()!; + } + + yield break; + } + else if (!isNull && instance is not null) + { + yield return new object[] { instance }; + yield break; } } - catch (DependencyResolutionException) + finally { // no op } - return Enumerable.Empty(); + yield return Array.Empty(); } } @@ -150,6 +163,7 @@ public bool HasRegistration(Type? serviceType, string? contract = null) [Obsolete("Because Autofac 5+ containers are immutable, this method should not be used by the end-user.")] public virtual void Register(Func factory, Type? serviceType, string? contract = null) { + var isNull = serviceType is null; if (serviceType is null) { serviceType = typeof(NullServiceType); @@ -167,21 +181,33 @@ public virtual void Register(Func factory, Type? serviceType, string? c // Second to child lifetimes in a temporary container, that is used only to satisfy ReactiveUI dependencies. if (contract is null || string.IsNullOrWhiteSpace(contract)) { - _builder.Register(_ => factory()!) + _builder.Register(_ => + isNull + ? new NullServiceType(factory) + : factory()!) .As(serviceType) .AsImplementedInterfaces(); _internalLifetimeScope = _internalLifetimeScope.BeginLifetimeScope(internalBuilder => - internalBuilder.Register(_ => factory()!) + internalBuilder.Register(_ => + isNull + ? new NullServiceType(factory) + : factory()!) .As(serviceType) .AsImplementedInterfaces()); } else { - _builder.Register(_ => factory()!) + _builder.Register(_ => + isNull + ? new NullServiceType(factory) + : factory()!) .Named(contract, serviceType) .AsImplementedInterfaces(); _internalLifetimeScope = _internalLifetimeScope.BeginLifetimeScope(internalBuilder => - internalBuilder.Register(_ => factory()!) + internalBuilder.Register(_ => + isNull + ? new NullServiceType(factory) + : factory()!) .Named(contract, serviceType) .AsImplementedInterfaces()); } @@ -245,7 +271,7 @@ protected virtual void Dispose(bool disposing) } } - private object? Resolve(Type? serviceType, string? contract) + private object? Resolve(Type serviceType, string? contract) { object serviceInstance; @@ -253,11 +279,11 @@ protected virtual void Dispose(bool disposing) if (contract is null || string.IsNullOrWhiteSpace(contract)) { - lifeTimeScope.TryResolve(serviceType!, out serviceInstance!); + lifeTimeScope.TryResolve(serviceType, out serviceInstance!); } else { - lifeTimeScope.TryResolveNamed(contract, serviceType!, out serviceInstance!); + lifeTimeScope.TryResolveNamed(contract, serviceType, out serviceInstance!); } return serviceInstance; diff --git a/src/Splat.Common.Test/DummyObjectClass1.cs b/src/Splat.Common.Test/DummyObjectClass1.cs index 74ded1409..65151b4c4 100644 --- a/src/Splat.Common.Test/DummyObjectClass1.cs +++ b/src/Splat.Common.Test/DummyObjectClass1.cs @@ -3,11 +3,14 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. +using System.Diagnostics.CodeAnalysis; + namespace Splat.Tests.Mocks { /// /// A dummy class used during Locator testing. /// + [ExcludeFromCodeCoverage] public class DummyObjectClass1 : IDummyInterface { } diff --git a/src/Splat.Common.Test/DummyObjectClass2.cs b/src/Splat.Common.Test/DummyObjectClass2.cs index 468f1ffc1..199c574ad 100644 --- a/src/Splat.Common.Test/DummyObjectClass2.cs +++ b/src/Splat.Common.Test/DummyObjectClass2.cs @@ -3,11 +3,14 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. +using System.Diagnostics.CodeAnalysis; + namespace Splat.Tests.Mocks { /// /// A dummy class used during Locator testing. /// + [ExcludeFromCodeCoverage] public class DummyObjectClass2 : IDummyInterface { } diff --git a/src/Splat.Common.Test/DummyObjectClass3.cs b/src/Splat.Common.Test/DummyObjectClass3.cs index c98e40fc2..4cd476c71 100644 --- a/src/Splat.Common.Test/DummyObjectClass3.cs +++ b/src/Splat.Common.Test/DummyObjectClass3.cs @@ -3,11 +3,14 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. +using System.Diagnostics.CodeAnalysis; + namespace Splat.Tests.Mocks { /// /// A dummy class used during Locator testing. /// + [ExcludeFromCodeCoverage] public class DummyObjectClass3 : IDummyInterface { } diff --git a/src/Splat.Common.Test/MockScreen.cs b/src/Splat.Common.Test/MockScreen.cs index 640dff6ed..2f0bf0f84 100644 --- a/src/Splat.Common.Test/MockScreen.cs +++ b/src/Splat.Common.Test/MockScreen.cs @@ -3,12 +3,15 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. +using System.Diagnostics.CodeAnalysis; + namespace Splat.Common.Test { /// /// An implementation. /// /// + [ExcludeFromCodeCoverage] public class MockScreen : IScreen { } diff --git a/src/Splat.Common.Test/ViewModelOne.cs b/src/Splat.Common.Test/ViewModelOne.cs index f2da11f66..f2b68af09 100644 --- a/src/Splat.Common.Test/ViewModelOne.cs +++ b/src/Splat.Common.Test/ViewModelOne.cs @@ -3,11 +3,14 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. +using System.Diagnostics.CodeAnalysis; + namespace Splat.Common.Test { /// /// View Model One. /// + [ExcludeFromCodeCoverage] public class ViewModelOne : IViewModelOne { /// diff --git a/src/Splat.Common.Test/ViewModelTwo.cs b/src/Splat.Common.Test/ViewModelTwo.cs index 327e7dd77..42e0ec53b 100644 --- a/src/Splat.Common.Test/ViewModelTwo.cs +++ b/src/Splat.Common.Test/ViewModelTwo.cs @@ -3,11 +3,14 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. +using System.Diagnostics.CodeAnalysis; + namespace Splat.Common.Test { /// /// View Model Two. /// + [ExcludeFromCodeCoverage] public class ViewModelTwo { } diff --git a/src/Splat.Common.Test/ViewOne.cs b/src/Splat.Common.Test/ViewOne.cs index 62ce609dc..fdaee051a 100644 --- a/src/Splat.Common.Test/ViewOne.cs +++ b/src/Splat.Common.Test/ViewOne.cs @@ -3,12 +3,15 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. +using System.Diagnostics.CodeAnalysis; + namespace Splat.Common.Test { /// /// View One. /// /// + [ExcludeFromCodeCoverage] public class ViewOne : IViewFor { /// diff --git a/src/Splat.Common.Test/ViewTwo.cs b/src/Splat.Common.Test/ViewTwo.cs index 550495fa3..ed019d12d 100644 --- a/src/Splat.Common.Test/ViewTwo.cs +++ b/src/Splat.Common.Test/ViewTwo.cs @@ -3,12 +3,15 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. +using System.Diagnostics.CodeAnalysis; + namespace Splat.Common.Test { /// /// View Two. /// /// + [ExcludeFromCodeCoverage] public class ViewTwo : IViewFor { /// diff --git a/src/Splat.DryIoc.Tests/DependencyResolverTests.cs b/src/Splat.DryIoc.Tests/DependencyResolverTests.cs index f484b49f0..8746bcee3 100644 --- a/src/Splat.DryIoc.Tests/DependencyResolverTests.cs +++ b/src/Splat.DryIoc.Tests/DependencyResolverTests.cs @@ -36,11 +36,23 @@ public void Can_Register_And_Resolve_Null_Types() var contract = "foo"; Locator.CurrentMutable.Register(() => bar, null, contract); + Assert.True(Locator.CurrentMutable.HasRegistration(null)); var value = Locator.Current.GetService(null); Assert.Equal(foo, value); + Assert.True(Locator.CurrentMutable.HasRegistration(null, contract)); value = Locator.Current.GetService(null, contract); Assert.Equal(bar, value); + + var values = Locator.Current.GetServices(null); + Assert.Equal(foo, (int)values.First()); + Assert.Equal(1, values.Count()); + + Locator.CurrentMutable.UnregisterCurrent(null); + var valuesNC = Locator.Current.GetServices(null); + Assert.Equal(0, valuesNC.Count()); + var valuesC = Locator.Current.GetServices(null, contract); + Assert.Equal(1, valuesC.Count()); } /// diff --git a/src/Splat.DryIoc/DryIocDependencyResolver.cs b/src/Splat.DryIoc/DryIocDependencyResolver.cs index cb118105c..b2c9b3515 100644 --- a/src/Splat.DryIoc/DryIocDependencyResolver.cs +++ b/src/Splat.DryIoc/DryIocDependencyResolver.cs @@ -69,13 +69,7 @@ public virtual IEnumerable GetServices(Type? serviceType, string? contra return registeredinSplat; } - var registeredWithContract = _container.ResolveMany(serviceType, serviceKey: contract).Select(x => isNull ? ((NullServiceType)x).Factory()! : x); - if (registeredWithContract.Any()) - { - return registeredWithContract; - } - - return _container.ResolveMany(serviceType).Select(x => isNull ? ((NullServiceType)x).Factory()! : x); + return Array.Empty(); } /// diff --git a/src/Splat.Microsoft.Extensions.DependencyInjection.Tests/MicrosoftDependencyResolverTests.cs b/src/Splat.Microsoft.Extensions.DependencyInjection.Tests/MicrosoftDependencyResolverTests.cs index 4fe4936db..7adc42545 100644 --- a/src/Splat.Microsoft.Extensions.DependencyInjection.Tests/MicrosoftDependencyResolverTests.cs +++ b/src/Splat.Microsoft.Extensions.DependencyInjection.Tests/MicrosoftDependencyResolverTests.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Text; using Microsoft.Extensions.DependencyInjection; using Splat.Microsoft.Extensions.DependencyInjection; @@ -24,15 +25,24 @@ public void Can_Register_And_Resolve_Null_Types() var foo = 5; resolver.Register(() => foo, null!); - var value = resolver.GetService(null!); - Assert.Equal(foo, value); - var bar = 4; var contract = "foo"; resolver.Register(() => bar, null!, contract); + Assert.True(resolver.HasRegistration(null)); + var value = resolver.GetService(null!); + Assert.Equal(foo, value); + + Assert.True(resolver.HasRegistration(null, contract)); value = resolver.GetService(null!, contract); Assert.Equal(bar, value); + + var values = resolver.GetServices(null); + Assert.Equal(1, values.Count()); + + resolver.UnregisterCurrent(null); + values = resolver.GetServices(null); + Assert.Equal(0, values.Count()); } /// diff --git a/src/Splat.Ninject.Tests/NInjectDependencyResolverTests.cs b/src/Splat.Ninject.Tests/NInjectDependencyResolverTests.cs index a9ad149b7..6ebe9303c 100644 --- a/src/Splat.Ninject.Tests/NInjectDependencyResolverTests.cs +++ b/src/Splat.Ninject.Tests/NInjectDependencyResolverTests.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Text; using Ninject; using Splat.Tests.ServiceLocation; @@ -22,17 +23,26 @@ public void Can_Register_And_Resolve_Null_Types() { var resolver = GetDependencyResolver(); var foo = 5; - resolver.Register(() => foo, null!); - - var value = resolver.GetService(null!); - Assert.Equal(foo, value); + resolver.Register(() => foo, null); var bar = 4; var contract = "foo"; - resolver.Register(() => bar, null!, contract); + resolver.Register(() => bar, null, contract); + + Assert.True(resolver.HasRegistration(null)); + var value = resolver.GetService(null); + Assert.Equal(foo, value); - value = resolver.GetService(null!, contract); + Assert.True(resolver.HasRegistration(null, contract)); + value = resolver.GetService(null, contract); Assert.Equal(bar, value); + + var values = resolver.GetServices(null); + Assert.Equal(1, values.Count()); + + resolver.UnregisterCurrent(null); + values = resolver.GetServices(null); + Assert.Equal(0, values.Count()); } /// diff --git a/src/Splat.Ninject/NinjectDependencyResolver.cs b/src/Splat.Ninject/NinjectDependencyResolver.cs index d25cef382..958091a79 100644 --- a/src/Splat.Ninject/NinjectDependencyResolver.cs +++ b/src/Splat.Ninject/NinjectDependencyResolver.cs @@ -44,14 +44,17 @@ public virtual IEnumerable GetServices(Type? serviceType, string? contra if (isNull) { - return _kernel.GetAll( - typeof(NullServiceType), - contract); + try + { + return _kernel.GetAll(typeof(NullServiceType), contract).ToArray(); + } + catch + { + return Array.Empty(); + } } - return _kernel.GetAll( - serviceType, - contract); + return _kernel.GetAll(serviceType, contract); } /// diff --git a/src/Splat.Tests/LocatorTests.cs b/src/Splat.Tests/LocatorTests.cs index 3bff4c5cd..7bba548bb 100644 --- a/src/Splat.Tests/LocatorTests.cs +++ b/src/Splat.Tests/LocatorTests.cs @@ -4,7 +4,7 @@ // See the LICENSE file in the project root for full license information. using System; - +using System.Linq; using FluentAssertions; using Splat.Tests.Mocks; @@ -32,11 +32,20 @@ public void Can_Register_And_Resolve_Null_Types() var contract = "foo"; container.CurrentMutable.Register(() => bar, null!, contract); + Assert.True(container.CurrentMutable.HasRegistration(null)); var value = container.Current.GetService(null!); Assert.Equal(foo, value); + Assert.True(container.CurrentMutable.HasRegistration(null, contract)); value = container.Current.GetService(null!, contract); Assert.Equal(bar, value); + + var values = container.Current.GetServices(null); + Assert.Equal(1, values.Count()); + + container.CurrentMutable.UnregisterCurrent(null); + values = container.Current.GetServices(null); + Assert.Equal(0, values.Count()); } /// From a31ba906c159b1d13634b79dcc3e4330d6e67b41 Mon Sep 17 00:00:00 2001 From: Chris Pulman Date: Sun, 25 Jul 2021 21:05:24 +0100 Subject: [PATCH 9/9] updated unregisterAll for Dryloc DR and updated tests --- .../DependencyResolverTests.cs | 8 +++++ src/Splat.DryIoc/DryIocDependencyResolver.cs | 29 ++++++++++++++++--- .../MicrosoftDependencyResolverTests.cs | 14 +++++++-- .../NInjectDependencyResolverTests.cs | 14 +++++++-- src/Splat.Tests/LocatorTests.cs | 14 +++++++-- 5 files changed, 69 insertions(+), 10 deletions(-) diff --git a/src/Splat.DryIoc.Tests/DependencyResolverTests.cs b/src/Splat.DryIoc.Tests/DependencyResolverTests.cs index 8746bcee3..3ba6868fe 100644 --- a/src/Splat.DryIoc.Tests/DependencyResolverTests.cs +++ b/src/Splat.DryIoc.Tests/DependencyResolverTests.cs @@ -53,6 +53,14 @@ public void Can_Register_And_Resolve_Null_Types() Assert.Equal(0, valuesNC.Count()); var valuesC = Locator.Current.GetServices(null, contract); Assert.Equal(1, valuesC.Count()); + + Locator.CurrentMutable.UnregisterAll(null); + valuesNC = Locator.Current.GetServices(null); + Assert.Equal(0, valuesNC.Count()); + + Locator.CurrentMutable.UnregisterAll(null, contract); + valuesC = Locator.Current.GetServices(null, contract); + Assert.Equal(0, valuesC.Count()); } /// diff --git a/src/Splat.DryIoc/DryIocDependencyResolver.cs b/src/Splat.DryIoc/DryIocDependencyResolver.cs index b2c9b3515..ba08857fc 100644 --- a/src/Splat.DryIoc/DryIocDependencyResolver.cs +++ b/src/Splat.DryIoc/DryIocDependencyResolver.cs @@ -126,6 +126,7 @@ public virtual void UnregisterCurrent(Type? serviceType, string? contract = null serviceType = typeof(NullServiceType); } + var key = (serviceType, contract ?? string.Empty); var hadvalue = _container.GetServiceRegistrations().Any(x => { if (x.ServiceType != serviceType) @@ -133,7 +134,6 @@ public virtual void UnregisterCurrent(Type? serviceType, string? contract = null return false; } - var key = (serviceType, contract ?? string.Empty); if (key.Equals(x.OptionalServiceKey)) { _container.Unregister(serviceType, key); @@ -166,10 +166,31 @@ public virtual void UnregisterAll(Type? serviceType, string? contract = null) } var key = (serviceType, contract ?? string.Empty); + foreach (var x in _container.GetServiceRegistrations()) + { + if (x.ServiceType != serviceType) + { + continue; + } + + if (key.Equals(x.OptionalServiceKey)) + { + _container.Unregister(serviceType, key); + continue; + } - _container.Unregister(serviceType, key); - _container.Unregister(serviceType, contract); - _container.Unregister(serviceType); + if (contract is null && x.OptionalServiceKey is null) + { + _container.Unregister(serviceType); + continue; + } + + if (x.OptionalServiceKey is string serviceKeyAsString + && contract is not null && contract.Equals(serviceKeyAsString, StringComparison.Ordinal)) + { + _container.Unregister(serviceType, contract); + } + } } /// diff --git a/src/Splat.Microsoft.Extensions.DependencyInjection.Tests/MicrosoftDependencyResolverTests.cs b/src/Splat.Microsoft.Extensions.DependencyInjection.Tests/MicrosoftDependencyResolverTests.cs index 7adc42545..60f782884 100644 --- a/src/Splat.Microsoft.Extensions.DependencyInjection.Tests/MicrosoftDependencyResolverTests.cs +++ b/src/Splat.Microsoft.Extensions.DependencyInjection.Tests/MicrosoftDependencyResolverTests.cs @@ -41,8 +41,18 @@ public void Can_Register_And_Resolve_Null_Types() Assert.Equal(1, values.Count()); resolver.UnregisterCurrent(null); - values = resolver.GetServices(null); - Assert.Equal(0, values.Count()); + var valuesNC = resolver.GetServices(null); + Assert.Equal(0, valuesNC.Count()); + var valuesC = resolver.GetServices(null, contract); + Assert.Equal(1, valuesC.Count()); + + resolver.UnregisterAll(null); + valuesNC = resolver.GetServices(null); + Assert.Equal(0, valuesNC.Count()); + + resolver.UnregisterAll(null, contract); + valuesC = resolver.GetServices(null, contract); + Assert.Equal(0, valuesC.Count()); } /// diff --git a/src/Splat.Ninject.Tests/NInjectDependencyResolverTests.cs b/src/Splat.Ninject.Tests/NInjectDependencyResolverTests.cs index 6ebe9303c..5239c3f12 100644 --- a/src/Splat.Ninject.Tests/NInjectDependencyResolverTests.cs +++ b/src/Splat.Ninject.Tests/NInjectDependencyResolverTests.cs @@ -41,8 +41,18 @@ public void Can_Register_And_Resolve_Null_Types() Assert.Equal(1, values.Count()); resolver.UnregisterCurrent(null); - values = resolver.GetServices(null); - Assert.Equal(0, values.Count()); + var valuesNC = resolver.GetServices(null); + Assert.Equal(0, valuesNC.Count()); + var valuesC = resolver.GetServices(null, contract); + Assert.Equal(1, valuesC.Count()); + + resolver.UnregisterAll(null); + valuesNC = resolver.GetServices(null); + Assert.Equal(0, valuesNC.Count()); + + resolver.UnregisterAll(null, contract); + valuesC = resolver.GetServices(null, contract); + Assert.Equal(0, valuesC.Count()); } /// diff --git a/src/Splat.Tests/LocatorTests.cs b/src/Splat.Tests/LocatorTests.cs index 7bba548bb..7900da21d 100644 --- a/src/Splat.Tests/LocatorTests.cs +++ b/src/Splat.Tests/LocatorTests.cs @@ -44,8 +44,18 @@ public void Can_Register_And_Resolve_Null_Types() Assert.Equal(1, values.Count()); container.CurrentMutable.UnregisterCurrent(null); - values = container.Current.GetServices(null); - Assert.Equal(0, values.Count()); + var valuesNC = container.Current.GetServices(null); + Assert.Equal(0, valuesNC.Count()); + var valuesC = container.Current.GetServices(null, contract); + Assert.Equal(1, valuesC.Count()); + + container.CurrentMutable.UnregisterAll(null); + valuesNC = container.Current.GetServices(null); + Assert.Equal(0, valuesNC.Count()); + + container.CurrentMutable.UnregisterAll(null, contract); + valuesC = container.Current.GetServices(null, contract); + Assert.Equal(0, valuesC.Count()); } ///