Problem
The data source attribute system has grown to 26+ types with a deeply nested core return type:
IAsyncEnumerable<Func<Task<object?[]?>>>
This is three levels of wrapping. Every data source must pack results into object?[] even for single values, and every consumer must unpack them.
The many variants exist to provide simpler semantics for sync vs async use cases, which is good — but the naming and hierarchy could be cleaned up.
Specific issues
- Naming inconsistencies —
InstanceMethodDataSourceSourceAttribute and AsyncDependencyInjectionDataSourceSourceAttribute have a double "Source" typo
- Inconsistent naming patterns — mix of
DataSource, Source, SourceGenerator in attribute names
- Return type complexity —
IAsyncEnumerable<Func<Task<object?[]?>>> is hard to reason about. The Func<Task<...>> wrapping (deferred lazy evaluation) could be opt-in rather than required by default
- Arity explosion —
DataSourceGeneratorAttribute<T> through <T1,T2,T3,T4,T5> plus async variants (10 classes for the same concept)
Proposed Direction
- Fix the double-"Source" typos
- Establish a consistent naming convention across all data source attributes
- Consider simplifying the core return type (e.g. a
TestDataRow struct to replace raw object?[])
- Evaluate whether the arity variants can be reduced
Notes
- The sync/async split is intentional and provides good ergonomics — keep that
- This is a source-breaking change for anyone implementing custom data sources
- Deferred to v2
Problem
The data source attribute system has grown to 26+ types with a deeply nested core return type:
This is three levels of wrapping. Every data source must pack results into
object?[]even for single values, and every consumer must unpack them.The many variants exist to provide simpler semantics for sync vs async use cases, which is good — but the naming and hierarchy could be cleaned up.
Specific issues
InstanceMethodDataSourceSourceAttributeandAsyncDependencyInjectionDataSourceSourceAttributehave a double "Source" typoDataSource,Source,SourceGeneratorin attribute namesIAsyncEnumerable<Func<Task<object?[]?>>>is hard to reason about. TheFunc<Task<...>>wrapping (deferred lazy evaluation) could be opt-in rather than required by defaultDataSourceGeneratorAttribute<T>through<T1,T2,T3,T4,T5>plus async variants (10 classes for the same concept)Proposed Direction
TestDataRowstruct to replace rawobject?[])Notes