C#方法分辨率分辨率为通用和类型推理



我今天对方法解决方案感到惊讶。

这是一个典范的代码:

class Program
{
    static class Mapper<TSource, TTarget>
    {
        public static void Map<TMember>(Expression<Func<TSource, TMember>> source, Expression<Func<TTarget, TMember>> target)
        {
            Console.WriteLine("A");
        }
        public static void Map<TMember, TSourceCollection>(Expression<Func<TSource, TSourceCollection>> source, Expression<Func<TTarget, TMember[]>> target)
            where TSourceCollection : IEnumerable<TMember>
        {
            Console.WriteLine("B");
        }
    }
    class A
    {
        public byte[] prop { get; set; }
    }
    class B
    {
        public byte[] prop { get; set; }
    }
    static void Main(string[] args)
    {
        Mapper<A, B>.Map(x => x.prop, x => x.prop);
    }
}

正如您所看到的,方法映射有两个过载,一个当属性的类型相同时,一个源属性是一个枚举,正确的属性是一个数组。

然后,当我调用两侧数组的方法时,它调用了第二个过载,但是由于类型与我期望的第一个过载完全相同。

我认为第一个过载的评分会更好,因为它取决于比第二个较少的通用参数,并且与我传递给该方法的参数类型更适合。

有人可以解释为什么编译器选择调用第二个过载,而不是第一个过载?

谢谢。

超载分辨率很复杂,您可以阅读规格以了解原因。我很确定的一件事是,考虑到哪个过载更好时,它并不需要指定更少的通用参数(尽管它将需要非一般的通用,但是当两者都是通用时,它会将它们视为平等)。

查看过载时,除了第二个参数是TMember还是TMember[]

规格关于选择最具体的成员的经常讨论,我无法确定在这里实际上适用的哪一部分(在许多地方谈论在x更具体时更喜欢X而不是y)。我本来以为是第7.6.5.1节(C#5规格的),它是构造候选列表的地方,或者是处理过载分辨率的7.5.3节。但是,前者似乎并不排除任何一种方法过载,而后者的阅读仅处理了通用参数之后的参数。规格中可能还有其他某个地方来处理此问题(例如,何时添加类型参数)。

用羊毛术语,我相信编译器正在考虑TMember[]TMember更具体。这可以广泛地认为是正确的,因为TMember比TMember []接受更多的东西,因此TMember[]更具体。

第一种方法TMember和第二种方法的匹配TSourceCollection对于满足where TSourceCollection : IEnumerable<TMember>条件的任何类型的值均等。

TMember相比,TMember[]类型是byte[]的更详细的类型匹配。因此,这应该是第二种方法得分优于第一个方法的点。因此,这种"更好"的匹配击败了事实,该方法两个具有更多的通用参数。

相关内容

  • 没有找到相关文章

最新更新