Implicit generic type arguments #8905
-
OverviewIt would be extremely nice if C# had some kind of "implicit" generic type arguments, which can be constrained/used inside a generic function/class, but are not visible outside the type/method signature. Use caseI'd like to build a pipeline using some kind of "builder syntax", which should (ideally) look as follows: var pipeline = PipelineStart.With<string>()
.Add<ConvertToInt32>();
var result = await pipeline.Execute("1");
// result should have a value of 1 and should be of type int32 Currently, I have to do the following: var pipeline = PipelineStart.With<string>()
.Add(new ConvertToInt32().Execute);
var result = await pipeline.Execute("1");
// result should have a value of 1 and should be of type int32 The reason that I cannot use the first example is, that C# doesn't support some kind of "implicit" generic type arguments, which could be deferred from type arguments but should not appear in the method declaration. Let's take a look at the current implementation: /// <summary>
/// A pipeline that transforms input data into output data.
/// </summary>
/// <typeparam name="TInput">The type of the input data.</typeparam>
/// <typeparam name="TOutput">The type of the output data.</typeparam>
public delegate ValueTask<TOutput> Pipeline<in TInput, TOutput>(TInput input, CancellationToken ct);
/// <summary>
/// Contains a static function to create a starting point of a pipeline.
/// </summary>
public static class PipelineStart
{
/// <summary>
/// Creates a starting point of a pipeline.
/// </summary>
/// <typeparam name="TData">The type of the data.</typeparam>
/// <returns>The starting point of a pipeline.</returns>
public static Pipeline<TData, TData> With<TData>()
{
return (x, _) => new ValueTask<TData>(x);
}
}
/// <summary>
/// Extension methods for the pipeline delegates.
/// </summary>
public static partial class PipelineExtensions
{
/// <summary>
/// Adds a new step to the pipeline.
/// </summary>
/// <param name="input">The input pipeline.</param>
/// <param name="convert">The new step to add.</param>
/// <typeparam name="TInput">The input type of the pipeline.</typeparam>
/// <typeparam name="TTemp">The intermediate type of the pipeline data.</typeparam>
/// <typeparam name="TOutput">The output type of the pipeline.</typeparam>
/// <returns></returns>
public static Pipeline<TInput, TOutput> Add<TInput, TTemp, TOutput>(
this Pipeline<TInput, TTemp> input,
Pipeline<TTemp, TOutput> convert)
{
return async (value, ct) => await convert(await input(value, ct), ct);
}
} What I'd like to create is an extension method like this: public interface IPipelineMiddleware<in TInput, TOutput>
{
ValueTask<TOutput> Execute(TInput input, CancellationToken ct);
}
public static partial class PipelineExtensions
{
public static Pipeline<TInput, TOutput> Add<TMiddleware>(
this Pipeline<TInput, TTemp> input)
where TMiddleware : IPipelineMiddleware<TTemp, TOutput>, new()
{
var middleware = new TMiddleware();
return input.Add(middleware.Execute);
}
}
SuggestionI suggest the following syntax: public static Pipeline<TInput, TOutput> Add<TMiddleware, TInput?, TTemp?, TOutput?>(
this Pipeline<TInput, TTemp> input)
where TMiddleware : IPipelineMiddleware<TTemp, TOutput>, new()
{
var middleware = new TMiddleware();
return input.Add(middleware.Execute);
} The question mark denotes an implicit generic type argument, which the compiler could translate to: public static Pipeline<TInput, TOutput> Add<TMiddleware, [Implicit] TInput, [Implicit] TTemp, [Implicit] TOutput>(
this Pipeline<TInput, TTemp> input)
where TMiddleware : IPipelineMiddleware<TTemp, TOutput>, new()
{
var middleware = new TMiddleware();
return input.Add(middleware.Execute);
} And the var pipeline = PipelineStart.With<string>()
.Add<ConvertToInt32>(); It gets translated to: var pipeline = PipelineStart.With<string>()
.Add<ConvertToInt32, string, string, int>(); RisksProbably none, as it's only syntactic sugar. |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments
-
Beta Was this translation helpful? Give feedback.
-
@ufcpp Partial type inference (#7467) is most likely what I was looking for, so closing as duplicate. |
Beta Was this translation helpful? Give feedback.
#339 ?
#1349 ?
or #8712 ?