Analyzer
SF0006
Flags generic types or methods whose type parameter is only ever bound to one concrete type in source, signaling abstraction without flexibility.
Diagnostic contract
Generics are powerful when multiple real specializations exist. When there is only one, they hide the real contract behind a pretend flexibility story.
A generic definition is specialized in source, but a given type parameter is only ever bound to one concrete type.
Generic parameter {0} on {1} is only specialized as {2}. Remove the generic parameter or use the concrete type directly.
/analyzers/sf0006/
When it fires
These are the concrete cases to look for in code review and IDE diagnostics.
- The analyzer collects generic type and method definitions from source, then records how their type parameters are specialized across source usage.
- It reports a parameter only when exactly one concrete specialization is found for that slot.
- The warning applies to generic methods and generic types alike.
Bad / better example
Use these examples to explain the rule, not just silence it.
Before
public interface IRepository<TDocument>
{
Task<TDocument?> LoadAsync(Guid id);
}
public sealed class SqlOrderRepository : IRepository<Order>
{
public Task<Order?> LoadAsync(Guid id) => Task.FromResult<Order?>(null);
}
public sealed class CheckoutHandler(IRepository<Order> repository)
{
} If TDocument is only ever Order, the generic parameter is storytelling, not flexibility.
After
public interface IOrderRepository
{
Task<Order?> LoadAsync(Guid id);
}
public sealed class SqlOrderRepository : IOrderRepository
{
public Task<Order?> LoadAsync(Guid id) => Task.FromResult<Order?>(null);
} The concrete contract makes the real shape obvious and removes one axis of pretend generality.
Code fix
There is no automatic code fix for this rule today. Treat it as a prompt to simplify deliberately.
- Check whether the team is planning multiple specializations soon or just preserving a hypothetical future.
- If the abstraction is shared across package boundaries, simplify carefully and communicate the contract change.
- This rule often pairs with SF0001 when generic interfaces also have one implementation.
Source and follow-up links
Use these links when you need to validate behavior against the source or connect the docs back to project tracking.
Analyzer implementation
SingleSpecializationGenericParameterAnalyzer.cs
TrackingIssue #55
Documentation tracker for the analyzer pages and related integration guidance.
FilterHalfRule
Single-specialization generics are another form of speculative abstraction.
GuideLibrary usage
Use the library docs to decide when an API surface should stay generic across package boundaries.