Improve type inference with generic interfaces that themselves are used as generic type constraints #2845
Replies: 3 comments
-
This appears to be a language change request. As such, it should go in: dotnet/csharplang. |
Beta Was this translation helpful? Give feedback.
-
this comes up from time to time for me as well, especially when doing "handler"-type logic. for example, given the following method: public TResponse Dispatch<TRequest, TResponse>(TRequest request)
where TRequest: IRequest<TResponse> // TRequest implies a TResponse
{
...
} as a caller of var request = new SomeRequest(); // assuming SomeRequest: IRequest<SomeResponse>
dispatcher.Dispatch(request); the above code will not compile; the last line gets the error "The type arguments [...] cannot be inferred from the usage. Try specifying the type arguments explicitly." but it feels like the type arguments could be unambiguously inferred by the compiler. the above might be achieved "for free" by adding smarter type inference to the underlying types. for example: public interface IRequest<TResponse> { }
// currently, the following will not compile; we must write IHandler<TRequest, TResponse>
// however, it feels like TResponse can be inferred from the constraint on TRequest
public interface IHandler<TRequest>
where TRequest : IRequest<TResponse>
{
TResponse Handle(TRequest request);
}
public class DispatchService
{
// again, the following will not compile; Dispatch<TRequest, TResponse> is expected,
// and again, it feels like TResponse could be inferred
public TResponse Dispatch<TRequest>(TRequest request)
where TRequest: IRequest<TResponse>
{
var handler = GetTheHandlerSomehow<TRequest>();
return handler.Handle(request);
}
} if C# was able to infer the types and compile that code, then calls to the following issues/discussions seem similarish, seeking to decrease friction when using generics: |
Beta Was this translation helpful? Give feedback.
-
Perhaps it can be designed in this way, placing the necessary generic types on the left and the optional ones on the right. When used, specifying all necessary generic arguments from left to right should be enough. interface IAdapter<TValue> { ... }
T Func<TAdapter, TValue>() where TAdapter : IAdapter<TValue> { ... }
// Use
class IntAdapter : IAdapter<int> { ... }
class GenericAdapter<T> : IAdapter<T> { ... }
int intValue = Func<IntAdapter>();
string stringValue = Func<GenericAdapter<string>>(); IDEs can prompt designers to place necessary generic types on the left and also remind users to omit unnecessary generic type arguments. |
Beta Was this translation helpful? Give feedback.
-
Version Used: 3.0.19.12206 (VS 2019 RC1)
Motivation
Nowadays in order to avoid boxing of a value type that is "viewed" through an interface one has to use generic constraints as illustrated below. This approach works fine when the interface is non-generic.
However as soon as the interface itself becomes generic, the approach below is no longer as useful from the programming convenience point of view. The introduction of the 2nd generic type parameter (
TInterface
being 1st, andT
inSomeInterface<T>
being second) prevents type inference from correctly inferring all types as illustrated in the example below, causing one to specify both generic type parameters at every call site!This seems to be completely unnecessary, as in the example below the
var xr1 = new Range<double>
clearly contains all the information needed for the type inference to work: theIntersects
method requires typeTRange
to be something that implementsIRange<T>
interface. Well' that's justRange
struct. And then theT
must be implementingIComparable<T>
. In the example it'sdouble
, which indeed satisfies the type constraints. So, all the information needed by the compiler to infer types correctly seems to be present.Steps to Reproduce:
Expected Behavior:
No need to manually specify generic type parameters at every call site. Types should be inferred.
Actual Behavior:
Compiler complains: CS0411: The type arguments for method cannot be inferred from the usage. Try specifying the type arguments explicitly.
Beta Was this translation helpful? Give feedback.
All reactions