Round #720
10 May 2026, 15:13· csharp· Meta-Llama-3.3-70B-Instruct· r13-clean-hints
- Complexity
- band 0
- ZP / UO / OBS
- 3 / 0 / 2
- Journey weight
- 285
- Lightshift ΔL
- —
Prompt
Use Keyed services (Microsoft.Extensions.DependencyInjection 8.0) to register multiple implementations of an interface and resolve by string key.
Zero-point index (what the engine surfaced)
ZPI-ZPI-0019 | 2026-05-10T15:13:33Z
Use Keyed services (Microsoft.Extensions.DependencyInjection 8.0) to register multiple implementations of an interface and resolve by string key.
ZERO POINT — 3 entries (structural invariants)
● hsl(7.18, 100%, 50%) class [feature]
● hsl(0.00, 100%, 50%) public [feature]
● hsl(84.10, 100%, 50%) namespace [feature]
UNOBSERVED — 0 entries (implied truths)
OBSERVED — 2 entries (explicit in request)
◉ hsl(9.23, 100%, 50%) interface [feature]
◉ hsl(133.33, 100%, 15%) string [feature]
COMPLEXITY │ 5 entries │ spread: 124° │ band: LOW
Baseline response (no ZPI)
Here's an example of how you can use keyed services in Microsoft.Extensions.DependencyInjection 8.0 to register multiple implementations of an interface and resolve them by a string key.
Let's assume we have an interface `ILogger` with two implementations: `ConsoleLogger` and `FileLogger`.
```csharp
public interface ILogger
{
void Log(string message);
}
public class ConsoleLogger : ILogger
{
public void Log(string message)
{
Console.WriteLine($"Console: {message}");
}
}
public class FileLogger : ILogger
{
public void Log(string message)
{
// Simulating file logging
Console.WriteLine($"File: {message}");
}
}
```
To register these implementations with keyed services, you can use the `AddService` method with a key.
```csharp
using Microsoft.Extensions.DependencyInjection;
public class Program
{
public static void Main()
{
var serviceProvider = BuildServiceProvider();
// Resolve the console logger
var consoleLogger = serviceProvider.GetService<ILogger>("console");
consoleLogger?.Log("Hello from console logger");
// Resolve the file logger
var fileLogger = serviceProvider.GetService<ILogger>("file");
fileLogger?.Log("Hello from file logger");
}
private static IServiceProvider BuildServiceProvider()
{
var services = new ServiceCollection();
// Register the console logger with the key "console"
services.AddService<ILogger>("console", _ => new ConsoleLogger());
// Register the file logger with the key "file"
services.AddService<ILogger>("file", _ => new FileLogger());
return services.BuildServiceProvider();
}
}
```
In this example, we're registering the `ConsoleLogger` and `FileLogger` classes with the `ILogger` interface using the `AddService` method. We're passing a key ("console" or "file") and a factory method that creates an instance of the logger.
When we want to resolve a logger, we use the `GetService` method and pass the key to get the corresponding logger instance.
Note that if you try to resolve a logger with a key that doesn't exist, the `GetService` method will return `null`. You can use the null-conditional operator (`?.`) to safely call methods on the resolved logger instance.
Also, keep in mind that keyed services are not the same as named services. Named services are a legacy feature that's been replaced by keyed services in .NET 8.0. If you're upgrading from an older version of .NET, you might need to update your code to use keyed services instead.
Enhanced response (with ZPI)
### Registering Multiple Implementations of an Interface
To register multiple implementations of an interface and resolve them by a string key, you can use the `TryAddScoped` or `TryAddTransient` methods provided by the `IServiceCollection` interface in the `Microsoft.Extensions.DependencyInjection` namespace.
Here's an example implementation:
```csharp
using Microsoft.Extensions.DependencyInjection;
// Define the interface
public interface IMyService
{
string GetMessage();
}
// Implementations of the interface
public class MyServiceA : IMyService
{
public string GetMessage()
{
return "Message from A";
}
}
public class MyServiceB : IMyService
{
public string GetMessage()
{
return "Message from B";
}
}
public class MyServiceC : IMyService
{
public string GetMessage()
{
return "Message from C";
}
}
class Program
{
static void Main(string[] args)
{
// Create a new service collection
var services = new ServiceCollection();
// Register multiple implementations of the interface
services.TryAddScoped<IMyService>("A", _ => new MyServiceA());
services.TryAddScoped<IMyService>("B", _ => new MyServiceB());
services.TryAddScoped<IMyService>("C", _ => new MyServiceC());
// Build the service provider
var serviceProvider = services.BuildServiceProvider();
// Resolve the services by key
var serviceA = serviceProvider.GetService<IMyService>("A");
var serviceB = serviceProvider.GetService<IMyService>("B");
var serviceC = serviceProvider.GetService<IMyService>("C");
// Use the resolved services
Console.WriteLine(serviceA?.GetMessage()); // Output: Message from A
Console.WriteLine(serviceB?.GetMessage()); // Output: Message from B
Console.WriteLine(serviceC?.GetMessage()); // Output: Message from C
}
}
```
### Explanation
In this example, we define an interface `IMyService` with a method `GetMessage()`. We then create three implementations of this interface: `MyServiceA`, `MyServiceB`, and `MyServiceC`.
To register these implementations, we use the `TryAddScoped` method, which adds a scoped service of the specified type to the services container. We pass the interface type `IMyService` and a string key as arguments. The key is used to identify the specific implementation to resolve.
We then build the service provider using the `BuildServiceProvider` method and resolve the services by their keys using the `GetService` method.
Note that the `GetService` method returns `null` if the service is not found, so we use the null-conditional operator (`?.`) to safely call the `GetMessage` method on the resolved services.
This approach allows you to register multiple implementations of an interface and resolve them by a string key, making it easy to manage and switch between different implementations of a service.
Grader chain
Each grader reads the same baseline + enhanced pair and casts an independent verdict. Disagreement is the framework's own signal — not noise to be averaged away.
V1samba/Meta-Llama-3.3-70B-Instruct
BetterV4qwen2.5-coder-3b-instruct
BetterV5openrouter/qwen/qwen3-235b-a22b-2507
BetterV7qwen2.5-coder-7b-instruct
BetterV8openai/gpt-4.1
WorseV9anthropic/claude-opus-4-7
WorseV12openai/gpt-4o
BetterComments
Our grader said what it said. What do you say? Comment as a guest below.
No comments yet. Be the first to say what you make of this round.