泛型扩展方法类型参数无法从上下文推断的问题排查
这个问题的核心在于C#泛型类型推断的两个关键限制,结合你的代码场景就能清晰理解:
1. 无法从TMapping反向推断TSource和TDestination
你的第一个扩展方法虽然约束了TMapping : IMapping<TSource, TDestination>,但编译器没办法从TMapping自动确定TSource和TDestination的具体类型——因为一个类可以实现多个不同泛型参数的IMapping接口。比如:
public class MultiMapping : IMapping<int, string>, IMapping<DateTime, bool> { public string Map(int src) => src.ToString(); public bool Map(DateTime src) => src.Year > 2020; }
当你对Mock<MultiMapping>调用SetupRandomMapping()时,编译器根本不知道你要使用哪一组TSource/TDestination,所以它不会尝试自动推断,必须由你显式指定类型。
2. out var dummy无法提供类型推断依据
在第一个方法里调用mock.SetupRandomMapping(It.IsAny<TSource>(), out var dummy)时,dummy是一个未初始化的变量——编译器没办法从这个变量推断出TDestination的类型,因为变量的类型是由方法的TDestination参数决定的,而不是反过来。这就形成了循环:要确定dummy的类型需要先知道TDestination,但要确定TDestination又需要获取类型信息,而你的第一个方法没有提供任何能让编译器推断TSource/TDestination的输入参数。
解决方案:显式指定类型参数(或调整方法设计)
既然自动推断走不通,最简单的办法就是在第一个方法里显式指定泛型类型参数,打破这个循环:
public static void SetupRandomMapping<TMapping, TSource, TDestination>(this Mock<TMapping> mock) where TMapping : class, IMapping<TSource, TDestination> { // 显式指定泛型参数,让编译器明确类型 mock.SetupRandomMapping<TMapping, TSource, TDestination>(It.IsAny<TSource>(), out var dummy); }
如果你觉得这样不够优雅,也可以调整方法的泛型设计,把TSource和TDestination作为顶层泛型参数,直接约束Mock的类型:
// 直接针对IMapping<TSource, TDestination>的Mock做扩展 public static void SetupRandomMapping<TSource, TDestination>(this Mock<IMapping<TSource, TDestination>> mock) { mock.SetupRandomMapping(It.IsAny<TSource>(), out var dummy); }
不过这个方案的局限是只能直接作用于Mock<IMapping<,>>,如果你的测试代码里用的是具体映射类的Mock(比如Mock<MyConcreteMapping>),就需要先把它转换成Mock<IMapping<TSource,TDestination>>才能调用。
内容的提问来源于stack exchange,提问作者Martin Volek

