【问题标题】:Confused about C#'s extension method overload resolution对 C# 的扩展方法重载解析感到困惑
【发布时间】:2020-04-27 15:20:53
【问题描述】:

考虑以下代码:

using System;
using System.Linq;
using System.Collections.Generic;

public static class Ex
{
    public static IEnumerable<T> Take<T>(this IEnumerable<T> source, long cnt)
    {
        return source;
    }
}

public class C 
{
    public static void Main() 
    {
        foreach(var e in Enumerable.Range(0, 10).Take(5).ToArray())
            Console.Write(e + " ");
    }
}

我在IEnumerable&lt;T&gt; 上为Take(long) 提供了一个扩展名,该框架未提供该扩展名。该框架仅提供Take(int)。由于我使用 int 参数 (Take(5)) 调用它,我本来希望它使用框架版本,但它正在调用我的扩展。

我错过了什么吗?最接近的匹配显然是以int 作为参数的匹配,并且包含System.Linq,因此它应该在有效重载池中。事实上,如果我删除我的扩展,就会调用正确的框架函数。

For reference

编辑:将它们移动到不同的命名空间显示相同的问题:

using System;
using System.Linq;
using System.Collections.Generic;

namespace N1
{
    public static class Ex
    {
        public static IEnumerable<T> Take<T>(this IEnumerable<T> source, long cnt)
        {
            return source;
        }
    }
}

namespace N2
{
    using N1;
    public class C 
    {
        public static void Main() 
        {
            foreach(var e in Enumerable.Range(0, 10).Take(5).ToArray())
                Console.Write(e + " ");
        }
    }
}

For reference

【问题讨论】:

  • 通过阅读linq .Take 上的文档,您永远不需要从IEnumerable 中提取超过20 亿个项目。因此,框架不提供.Take(long) 的原因。
  • 你试过用5L而不是5来调用它吗?
  • 我认为因为你的扩展方法和调用者都在同一个命名空间中,所以那个会赢。暂时不记得具体的规则了。
  • @Sean,我调用long 版本的Take 没有问题,这实际上是我的问题。
  • @Blindy 你的例子没有实际应用,会被认为是糟糕的设计。无论您是否征求意见,我都在指出您的示例中的错误。

标签: c# overloading overload-resolution


【解决方案1】:

因为正如 Eric Lippert 所说:

判断一个潜在过载的基本规则 对于给定的呼叫站点,比另一个更好:越近越好 比更远。

Closer is better

【讨论】:

  • 他列表中的最后一项将适用于我的第二个示例,因为嵌套的using 比外部System.Linq 更接近我的用法。事实上,如果我在嵌套命名空间中添加using System.Linq,它会按预期工作。很奇怪,不过我只是问了原因,你说的没错,就是这个,谢谢!
【解决方案2】:

尝试System.Linq.Enumerable.Take(source, 5) 而不是仅仅Take(source, 5) 强制使用原始的“Take”功能或将您自己的“Take”重命名为其他“Takef”,例如以避免此类问题。

【讨论】:

  • 这是一种扩展方法,你的建议没有意义。
  • 我已经遇到了这个问题,我不知道为什么但它有所帮助(我知道在正常情况下这样做是没有意义的,但如果它有效...... ^^' 7)
  • 您可以将扩展方法称为普通的“前缀”方法,而不是作为“中缀”扩展方法。所以System.Linq.Enumerable.Take(someCollection,5);
猜你喜欢
  • 2017-03-20
  • 1970-01-01
  • 1970-01-01
  • 2013-02-25
  • 1970-01-01
  • 2017-09-08
  • 1970-01-01
  • 2010-10-31
  • 1970-01-01
相关资源
最近更新 更多