扩展方法冲突

时间:2011-03-12 15:55:43

标签: c# methods namespaces extension-methods conflict

假设我在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()

4 个答案:

答案 0 :(得分:29)

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

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

答案 1 :(得分:24)

我有这个确切的问题所以我在两年后发现了这个帖子。但是,我认为重要的是要注意,如果调用重复扩展方法的代码不在同一名称空间中,那么这只会编译并且不会给出“调用是不明确的”错误其中一个

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

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

答案 2 :(得分:12)

正如Jon所说,如果在编译时存在这两种情况,编译就会失败。

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

答案 3 :(得分:2)

我将大型解决方案从.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()