• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Aldaviva / Unfucked / 19128584806

06 Nov 2025 07:47AM UTC coverage: 0.396% (-39.5%) from 39.923%
19128584806

push

github

Aldaviva
DateTime: added IsBefore and IsAfter for ZonedDateTime, not just OffsetDateTime. DI: Allow super registration for keyed services; fixed super registration of a hosted service causing an infinite recursion during injection. STUN: updated fallback server list, most of which have gone offline (including Google, confusingly); made HttpClient optional.

2 of 1605 branches covered (0.12%)

0 of 55 new or added lines in 2 files covered. (0.0%)

945 existing lines in 35 files now uncovered.

9 of 2272 relevant lines covered (0.4%)

0.04 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/DI/DependencyInjectionExtensions.SuperRegistration.cs
1
using Microsoft.Extensions.DependencyInjection;
2
using Microsoft.Extensions.Hosting;
3
using System.Diagnostics.CodeAnalysis;
4
using System.Reflection;
5
using Unfucked.DI;
6

7
namespace Unfucked;
8

9
public static partial class DependencyInjectionExtensions {
10

11
    #region Normal registrations
12

13
    /// <summary>
14
    /// <para>Register a class in the dependency injection context, and also register it so it can be injected as any of its interfaces or superclasses, like Spring does by default and Autofac optionally allows.</para>
15
    /// <para>For example, if <c>MyClass</c> implements <c>IMyInterface</c> and extends <c>MySuperClass</c>, this allows you to easily register <c>MyClass</c> in DI and inject either <c>IMyInterface</c> or <c>MySuperClass</c> into a service's constructor, without injection casting or duplicative unrefactorable registration clutter.</para>
16
    /// </summary>
17
    /// <typeparam name="TImpl">Type of the class to register</typeparam>
18
    /// <param name="services"><see cref="IHostApplicationBuilder.Services"/> or similar</param>
19
    /// <param name="alsoRegister">Also register the class as its own concrete class, all of its extended superclasses, or all of its implemented interfaces, or <see cref="SuperRegistration.NONE"/> to only register it as its own type (default <c>Microsoft.Extensions.DependencyInjection</c> behavior). A union of multiple values can be passed with logical OR (<see cref="SuperRegistration.SUPERCLASSES"/><c> | </c><see cref="SuperRegistration.INTERFACES"/>).</param>
20
    /// <returns>The same collection of service registrations, for chained calls</returns>
21
    public static IServiceCollection AddSingleton<TImpl>(this IServiceCollection services, SuperRegistration alsoRegister) where TImpl: class =>
NEW
22
        Add<TImpl>(services, ServiceLifetime.Singleton, alsoRegister);
×
23

24
    /// <inheritdoc cref="AddSingleton{TImpl}(Microsoft.Extensions.DependencyInjection.IServiceCollection,SuperRegistration)" />
25
    /// <param name="instance">One concrete singleton instance that will always be returned when these types are injected</param>
26
    public static IServiceCollection AddSingleton<TImpl>(this IServiceCollection services, TImpl instance, SuperRegistration alsoRegister) where TImpl: class =>
NEW
27
        Add(services, alsoRegister, instance);
×
28

29
    /// <inheritdoc cref="AddSingleton{TImpl}(Microsoft.Extensions.DependencyInjection.IServiceCollection,SuperRegistration)" />
30
    /// <param name="factory">Function that creates instances of <typeparamref name="TImpl"/></param>
31
    public static IServiceCollection AddSingleton<TImpl>(this IServiceCollection services, Func<IServiceProvider, TImpl> factory, SuperRegistration alsoRegister) where TImpl: class =>
NEW
32
        Add(services, ServiceLifetime.Singleton, alsoRegister, factory);
×
33

34
    /// <inheritdoc cref="AddSingleton{TImpl}(Microsoft.Extensions.DependencyInjection.IServiceCollection,SuperRegistration)" />
35
    public static IServiceCollection AddTransient<TImpl>(this IServiceCollection services, SuperRegistration alsoRegister) where TImpl: class =>
NEW
36
        Add<TImpl>(services, ServiceLifetime.Transient, alsoRegister);
×
37

38
    /// <inheritdoc cref="AddSingleton{TImpl}(Microsoft.Extensions.DependencyInjection.IServiceCollection,SuperRegistration)" />
39
    /// <param name="factory">Function that creates instances of <typeparamref name="TImpl"/></param>
40
    public static IServiceCollection AddTransient<TImpl>(this IServiceCollection services, Func<IServiceProvider, TImpl> factory, SuperRegistration alsoRegister) where TImpl: class =>
NEW
41
        Add(services, ServiceLifetime.Transient, alsoRegister, factory);
×
42

43
    /// <inheritdoc cref="AddSingleton{TImpl}(Microsoft.Extensions.DependencyInjection.IServiceCollection,SuperRegistration)" />
44
    public static IServiceCollection AddScoped<TImpl>(this IServiceCollection services, SuperRegistration alsoRegister) where TImpl: class =>
NEW
45
        Add<TImpl>(services, ServiceLifetime.Scoped, alsoRegister);
×
46

47
    /// <inheritdoc cref="AddSingleton{TImpl}(Microsoft.Extensions.DependencyInjection.IServiceCollection,SuperRegistration)" />
48
    /// <param name="factory">Function that creates instances of <typeparamref name="TImpl"/></param>
49
    public static IServiceCollection AddScoped<TImpl>(this IServiceCollection services, Func<IServiceProvider, TImpl> factory, SuperRegistration alsoRegister) where TImpl: class =>
NEW
50
        Add(services, ServiceLifetime.Scoped, alsoRegister, factory);
×
51

52
    #endregion
53

54
    #region Hosted services
55

56
    /// <inheritdoc cref="AddSingleton{TImpl}(Microsoft.Extensions.DependencyInjection.IServiceCollection,SuperRegistration)" />
57
    public static IServiceCollection AddHostedService<TImpl>(this IServiceCollection services, SuperRegistration alsoRegister) where TImpl: class, IHostedService =>
NEW
58
        Add<TImpl>(services, alsoRegister, () => new ServiceDescriptor(typeof(IHostedService), typeof(TImpl), ServiceLifetime.Singleton),
×
NEW
59
            extra => new ServiceDescriptor(extra, HostedServiceProvider<TImpl>, ServiceLifetime.Singleton));
×
60

61
    /// <inheritdoc cref="AddSingleton{TImpl}(Microsoft.Extensions.DependencyInjection.IServiceCollection,SuperRegistration)" />
62
    /// <param name="factory">Function that creates instances of <typeparamref name="TImpl"/></param>
63
    public static IServiceCollection AddHostedService<TImpl>(this IServiceCollection services, Func<IServiceProvider, TImpl> factory, SuperRegistration alsoRegister)
NEW
64
        where TImpl: class, IHostedService => Add<TImpl>(services, alsoRegister, () => new ServiceDescriptor(typeof(IHostedService), factory, ServiceLifetime.Singleton),
×
NEW
65
        extra => new ServiceDescriptor(extra, HostedServiceProvider<TImpl>, ServiceLifetime.Singleton));
×
66

67
    #endregion
68

69
    #region Keyed services
70

71
    /// <inheritdoc cref="AddSingleton{TImpl}(Microsoft.Extensions.DependencyInjection.IServiceCollection,SuperRegistration)" />
72
    /// <param name="serviceKey">Key that identifies this registration, to be used when injecting using <see cref="ServiceKeyAttribute"/>.</param>
73
    public static IServiceCollection AddKeyedSingleton<TImpl>(this IServiceCollection services, object? serviceKey, SuperRegistration alsoRegister) where TImpl: class =>
NEW
74
        Add<TImpl>(services, ServiceLifetime.Singleton, alsoRegister, serviceKey);
×
75

76
    /// <inheritdoc cref="AddKeyedSingleton{TImpl}(Microsoft.Extensions.DependencyInjection.IServiceCollection,object?,Unfucked.DI.SuperRegistration)" />
77
    /// <param name="instance">One concrete singleton instance that will always be returned when these types are injected</param>
78
    public static IServiceCollection AddKeyedSingleton<TImpl>(this IServiceCollection services, object? serviceKey, TImpl instance, SuperRegistration alsoRegister) where TImpl: class =>
NEW
79
        Add(services, alsoRegister, instance, serviceKey);
×
80

81
    /// <inheritdoc cref="AddKeyedSingleton{TImpl}(Microsoft.Extensions.DependencyInjection.IServiceCollection,object?,Unfucked.DI.SuperRegistration)" />
82
    /// <param name="factory">Function that creates instances of <typeparamref name="TImpl"/></param>
83
    public static IServiceCollection AddKeyedSingleton<TImpl>(this IServiceCollection services, object? serviceKey, Func<IServiceProvider, object?, TImpl> factory, SuperRegistration alsoRegister)
NEW
84
        where TImpl: class => Add(services, ServiceLifetime.Singleton, alsoRegister, factory, serviceKey);
×
85

86
    /// <inheritdoc cref="AddKeyedSingleton{TImpl}(Microsoft.Extensions.DependencyInjection.IServiceCollection,object?,Unfucked.DI.SuperRegistration)" />
87
    public static IServiceCollection AddKeyedTransient<TImpl>(this IServiceCollection services, object? serviceKey, SuperRegistration alsoRegister) where TImpl: class =>
NEW
88
        Add<TImpl>(services, ServiceLifetime.Transient, alsoRegister, serviceKey);
×
89

90
    /// <inheritdoc cref="AddKeyedSingleton{TImpl}(Microsoft.Extensions.DependencyInjection.IServiceCollection,object?,Unfucked.DI.SuperRegistration)" />
91
    /// <param name="factory">Function that creates instances of <typeparamref name="TImpl"/></param>
92
    public static IServiceCollection AddKeyedTransient<TImpl>(this IServiceCollection services, object? serviceKey, Func<IServiceProvider, object?, TImpl> factory, SuperRegistration alsoRegister)
NEW
93
        where TImpl: class => Add(services, ServiceLifetime.Transient, alsoRegister, factory, serviceKey);
×
94

95
    /// <inheritdoc cref="AddKeyedSingleton{TImpl}(Microsoft.Extensions.DependencyInjection.IServiceCollection,object?,Unfucked.DI.SuperRegistration)" />
96
    public static IServiceCollection AddKeyedScoped<TImpl>(this IServiceCollection services, object? serviceKey, SuperRegistration alsoRegister) where TImpl: class =>
NEW
97
        Add<TImpl>(services, ServiceLifetime.Scoped, alsoRegister, serviceKey);
×
98

99
    /// <inheritdoc cref="AddKeyedSingleton{TImpl}(Microsoft.Extensions.DependencyInjection.IServiceCollection,object?,Unfucked.DI.SuperRegistration)" />
100
    /// <param name="factory">Function that creates instances of <typeparamref name="TImpl"/></param>
101
    public static IServiceCollection AddKeyedScoped<TImpl>(this IServiceCollection services, object? serviceKey, Func<IServiceProvider, object?, TImpl> factory, SuperRegistration alsoRegister)
102
        where TImpl: class =>
NEW
103
        Add(services, ServiceLifetime.Scoped, alsoRegister, factory, serviceKey);
×
104

105
    #endregion
106

NEW
107
    private static IServiceCollection Add<TImpl>(IServiceCollection services, ServiceLifetime scope, SuperRegistration alsoRegister) where TImpl: class => Add<TImpl>(services, alsoRegister,
×
NEW
108
        () => new ServiceDescriptor(typeof(TImpl), typeof(TImpl), scope),
×
NEW
109
        extra => scope == ServiceLifetime.Singleton ? new ServiceDescriptor(extra, ConcreteClassProvider<TImpl>, scope) : new ServiceDescriptor(extra, typeof(TImpl), scope));
×
110

NEW
111
    private static IServiceCollection Add<TImpl>(IServiceCollection services, SuperRegistration alsoRegister, TImpl instance) where TImpl: class => Add<TImpl>(services,
×
NEW
112
        alsoRegister, () => new ServiceDescriptor(typeof(TImpl), instance, ServiceLifetime.Singleton), extra => new ServiceDescriptor(extra, _ => instance, ServiceLifetime.Singleton));
×
113

114
    private static IServiceCollection Add<TImpl>(IServiceCollection services, ServiceLifetime scope, SuperRegistration alsoRegister, Func<IServiceProvider, TImpl> factory) where TImpl: class =>
NEW
115
        Add<TImpl>(services, alsoRegister, () => new ServiceDescriptor(typeof(TImpl), factory, scope), extra => new ServiceDescriptor(extra, ConcreteClassProvider<TImpl>, scope));
×
116

NEW
117
    private static IServiceCollection Add<TImpl>(IServiceCollection services, ServiceLifetime scope, SuperRegistration alsoRegister, object? serviceKey) where TImpl: class => Add<TImpl>(services,
×
NEW
118
        alsoRegister, () => new ServiceDescriptor(typeof(TImpl), serviceKey, typeof(TImpl), scope),
×
NEW
119
        extra => scope == ServiceLifetime.Singleton ? new ServiceDescriptor(extra, serviceKey, KeyedConcreteClassProvider<TImpl>, scope)
×
NEW
120
            : new ServiceDescriptor(extra, serviceKey, typeof(TImpl), scope));
×
121

NEW
122
    private static IServiceCollection Add<TImpl>(IServiceCollection services, SuperRegistration alsoRegister, TImpl instance, object? serviceKey) where TImpl: class => Add<TImpl>(services,
×
NEW
123
        alsoRegister, () => new ServiceDescriptor(typeof(TImpl), serviceKey, instance), extra => new ServiceDescriptor(extra, serviceKey, (_, _) => instance, ServiceLifetime.Singleton));
×
124

125
    private static IServiceCollection Add<TImpl>(IServiceCollection services, ServiceLifetime scope, SuperRegistration alsoRegister, Func<IServiceProvider, object?, TImpl> factory, object? serviceKey)
NEW
126
        where TImpl: class => Add<TImpl>(services, alsoRegister, () => new ServiceDescriptor(typeof(TImpl), serviceKey, factory, scope),
×
NEW
127
        extra => new ServiceDescriptor(extra, serviceKey, KeyedConcreteClassProvider<TImpl>, scope));
×
128

129
    [SuppressMessage("ReSharper", "PossibleMultipleEnumeration")] // IEnumerable.Concat obviously never enumerates the lazy sequence, even if it's in a try block
130
    private static IServiceCollection Add<TImpl>(IServiceCollection services, SuperRegistration alsoRegister, Func<ServiceDescriptor> defaultRegistration,
131
                                                 Func<Type, ServiceDescriptor> extraRegistration) where TImpl: class {
NEW
132
        IEnumerable<ServiceDescriptor> registrations = [defaultRegistration()];
×
133
        try {
NEW
134
            Type concreteType = typeof(TImpl);
×
135

NEW
136
            if ((alsoRegister & SuperRegistration.CONCRETE_CLASS) != 0) {
×
NEW
137
                registrations = registrations.Append(extraRegistration(concreteType));
×
138
            }
139

NEW
140
            if ((alsoRegister & SuperRegistration.INTERFACES) != 0) {
×
NEW
141
                registrations = registrations.Concat(concreteType.GetInterfaces().Except(InterfaceRegistrationBlacklist).Select(extraRegistration));
×
142
            }
143

NEW
144
            if ((alsoRegister & SuperRegistration.SUPERCLASSES) != 0) {
×
NEW
145
                IEnumerable<Type> superclasses = [];
×
NEW
146
                Type              @class       = concreteType, @object = typeof(object), valueType = typeof(ValueType);
×
NEW
147
                while (@class.BaseType is { } superclass && superclass != @object && superclass != valueType) {
×
NEW
148
                    superclasses = superclasses.Append(superclass);
×
NEW
149
                    @class       = superclass;
×
NEW
150
                }
×
NEW
151
                registrations = registrations.Concat(superclasses.Select(extraRegistration));
×
152
            }
NEW
153
        } catch (TargetInvocationException) {
×
154
            // if an interface's static initializer is throwing an exception, it will become obvious anyway
NEW
155
        }
×
156

NEW
157
        services.AddAll(registrations); // TryAddEnumerable fails when trying to register a class as itself, such as .AddSingleton<HttpClient>()
×
NEW
158
        return services;
×
159
    }
160

NEW
161
    private static object ConcreteClassProvider<TImpl>(IServiceProvider services) => services.GetService<TImpl>()!;
×
162

NEW
163
    private static object KeyedConcreteClassProvider<TImpl>(IServiceProvider services, object? serviceKey) => services.GetKeyedService<TImpl>(serviceKey)!;
×
164

NEW
165
    private static object HostedServiceProvider<TImpl>(IServiceProvider services) => services.GetServices<IHostedService>().OfTypeExactly<TImpl>().First()!;
×
166

167
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc