【问题标题】:Extension methods conflict扩展方法冲突
【发布时间】:2011-07-14 02:31:21
【问题描述】:

假设我有 2 个字符串扩展方法,位于 2 个不同的命名空间中:

namespace test1
{
    public static class MyExtensions
    {
        public static int TestMethod(this String str)
        {
            return 1;
        }
    } 
}

namespace test2
{
    public static class MyExtensions2
    {
        public static int TestMethod(this String str)
        {
            return 2;
        }
    } 
}

这些方法只是举例,它们并没有真正做任何事情。

现在让我们考虑这段代码:

using System;
using test1;
using test2;

namespace blah {
    public static class Blah {
        public Blah() {
        string a = "test";
        int i = a.TestMethod(); //Which one is chosen ?
        }
    }
}

问题

我知道只会选择其中一种扩展方法。
会是哪一个?为什么?

编辑:

这也让我很困扰,但不是因为它毕竟是静态类中的静态方法:

如何从某个命名空间中选择某个方法?
通常我会使用Namespace.ClassNAME.Method() ...但这只是超越了扩展方法的整个想法。而且我认为你不能使用Variable.Namespace.Method()

【问题讨论】:

  • 如果有疑问,您可以拨打test1.MyExtensions.TestMethod(a)而不是a.TestMethod()
  • 我不知道,但我认为这不应该真的发生......在类中给方法一个更具描述性的名称,而不是试图强制编译器自动选择一个。我有兴趣查看回复。
  • 我不会说我会那样做。但是假设您正在使用某个库,并且在不知不觉中,那里有一个同名的扩展方法....只是想知道它是如何选择的
  • 我认为这是一个很好的问题 - 不管其他建议如何,知道这一点会很高兴。
  • test1.MyExtensions.TestMethod(a) 超越了扩展方法的想法。我已经编辑了我的问题,这并不是真正困扰我的问题。

标签: c# methods namespaces extension-methods conflict


【解决方案1】:

不会选择任何方法:调用不明确,不会编译。

你为什么不能Namespace.ClassNAME.Method()?当然,没有什么可以阻止您将扩展方法视为普通的静态方法,事实上,这是您解决歧义并让程序编译的唯一方法。

【讨论】:

  • 好的,但是有没有关于编译器将选择哪一个以及为什么的描述?我在想我不能做 Variable.namespace.Method()
  • 编译器不会选择,你的代码不会编译。
  • @Yochai:编译器不会选择,因为如果两个扩展方法都可见,它将拒绝编译。正如您所说,variable.Namespace.Method() 在语法上无效,因此也无法编译。
【解决方案2】:

正如 Jon 所说,如果在编译时这两个都存在,编译就会失败。

但是,如果在编译时只存在一个,并且后来更新了外部库以添加第二个,那么您编译的代码仍将继续使用第一个。这是因为编译器内部会将您的代码转换为调用 namespace.classname.method 的简写形式。

【讨论】:

    【解决方案3】:

    我有这个确切的问题,所以两年后我找到了这篇文章。但是,我认为重要的是要注意,如果调用重复扩展方法的代码与其中之一。

    如果 OP 要将他的类 Blah 的命名空间更改为 test1test2,则代码编译,并使用与调用者相同命名空间中的扩展 -即使 两个命名空间 都在 usings 中表示。因此,如果 Blahtest1 命名空间中,则返回“1”,如果 Blahtest2 命名空间中,则返回“2”。

    我认为添加到上述答案中很重要,因为我认为一个主流用例是在引用外部扩展库的本地类库中进行扩展(例如,开发人员共享一个通用实用程序库,但有一些本地可能无意中具有相同名称的自定义扩展)。通过在与使用它们的代码相同的命名空间中维护自定义本地扩展,您可以维护扩展调用语法,而不必恢复为将它们视为静态方法调用。

    【讨论】:

    • 非常重要的一点。这实际上解决了我一直在与之斗争的痛苦冲突。谢谢!
    • nb。命名空间是分层的,因此如果您想在整个项目中覆盖某些第三方库的扩展,您可以将自己的扩展放在项目使用的顶级命名空间中
    • 很棒的评论。我一直对“此代码无法编译”的 cmets 感到困惑,直到我找到了这个。我的代码肯定可以编译,这就解释了为什么首先选择了所选择的特定方法。对于我的具体情况,这是完美的,因为我需要覆盖其他扩展方法的逻辑。
    【解决方案4】:

    我将大型解决方案从 .Net 4.7.1 迁移到 .Net 4.7.2。我们在代码中使用 LINQ,并使用名称为 MoreLinq https://www.nuget.org/packages/morelinq/ 的知名且已建立的库。

    .Net 4.7.1 没有.ToHashSet() 方法。我们使用了来自 MoreLinq 库的.ToHashSet()。在同一个 cs 文件的同一个类中,我们同时拥有 using System.Linq;using MoreLinq;

    我将一个项目重新定位到 .Net 4.7.2,编译器显示The call is ambiguous 错误,如上所述。原因是.Net 4.7.2 新增了同名.ToHashSet() 的扩展方法。

    我无法重新实现庞大的代码库。我不能用另一个库替换 MoreLinq。这就是我所做的。我在有using System.Linq; 但没有using MoreLinq; 的新文件中创建了一个新类。这是文件(ToHashsetHelpers.cs):

    using System.Collections.Generic;
    using System.Linq;
    
    namespace Common.Helpers
    {
        /// <summary>
        /// This class with only one method helps to resolve
        /// name conflict between .Net 4.7.2 and MoreLinq libraries.
        ///
        /// .Net 4.7.2 introduced a new extension method named '.ToHashSet()'.
        /// But MoreLinq already has the same method.
        ///
        /// After migrating our solution from .Net 4.7.1 to 4.7.2
        /// C# compiler shows "The call is ambiguous" error.
        ///
        /// We cannot have both "using System.Linq;" and "using MoreLinq;" in the same C# file that
        /// uses '.ToHashSet()'.
        ///
        /// The solution is to have method with different name in a file like this.
        /// </summary>
        public static class ToHashsetHelpers
        {
            /// <summary>
            /// The name of this method is ToHashset (not ToHashSet)
            /// </summary>
            public static HashSet<TSource> ToHashset<TSource>(this IEnumerable<TSource> source)
            {
                // Calling System.Linq.Enumerable.ToHashSet()
                return source.ToHashSet();
            }
        }
    }
    

    我在整个解决方案中将所有 .ToHashSet() 重命名为 .ToHashset()

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-12-30
      • 2014-11-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-18
      相关资源
      最近更新 更多