扩展方法冲突

发布于 2024-10-21 07:24:26 字数 984 浏览 5 评论 0原文

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

Lets say I have 2 extension methods to string, in 2 different namespaces:

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;
        }
    } 
}

These methods are just for example, they don't really do anything.

Now lets consider this piece of code:

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 ?
        }
    }
}

The Question:

I know that only one of the extension methods will be chosen.
Which one will it be ? and why ?

Edit:

This also bothers me, but not as much because it's a static method in a static class after all:

How can I choose a certain method from a certain namespace ?
Usually I'd use Namespace.ClassNAME.Method() ... But that just beats the whole idea of extension methods. And I don't think you can use Variable.Namespace.Method()

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

愛上了 2024-10-28 07:24:26

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

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

No method will be chosen: the call is ambiguous and will not compile.

Why can't you do Namespace.ClassNAME.Method()? Certainly there is nothing that prevents you from treating extension methods as normal static methods, and in fact this is the only way for you to fix the ambiguity and have the program compile.

夜雨飘雪 2024-10-28 07:24:26

我有这个确切的问题,所以两年后我找到了这篇文章。但是,我认为重要的是要注意,如果调用重复扩展方法的代码与以下代码不在同一命名空间中,则这不会编译并给出“调用不明确”错误其中之一。

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

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

I had this exact question so I found this post two years later. However, I think it is important to note that this will only not compile and give the "The call is ambiguous" error if the code calling the duplicate extension methods is not in the same namespace as one of them.

If the OP were to change the namespace of his class Blah to either test1 or test2, then the code compiles, and the extension in the same namespace as the caller is used - even when both namespaces are represented in the usings. So if Blah is in the test1 namespace, "1" is returned, and if Blah is in the test2 namespace, "2" is returned.

I think this is important to add to the above answers, because I think one mainstream use-case is to have extensions in a local class library that references external extension libraries (e.g. devs share a common utility library, but have some local custom extensions that might unwittingly have the same name). By maintaining the custom local extensions in the same namespace as the code that uses them, you can maintain the extension call syntax and not have to revert to treating them as static method calls.

百合的盛世恋 2024-10-28 07:24:26

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

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

As Jon says, if both of these exist when you do the compilation, the compilation will just fail.

But if only one exists at the time of compilation and a external library later gets updated to add the second, the code you compiled will still continue to use the first one. This is because the compiler interally turns your code into the longhand form of calling namespace.classname.method.

凑诗 2024-10-28 07:24:26

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

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

我将项目重新定位到 .Net 4.7.2,编译器显示如上所述的 调用不明确 错误。原因是.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()

I migrated big solution from .Net 4.7.1 to .Net 4.7.2. We use LINQ in our code, and we use well known and established library with name MoreLinq https://www.nuget.org/packages/morelinq/.

.Net 4.7.1 does not have .ToHashSet() methods. We used .ToHashSet() from MoreLinq library. And in the same class in the same cs-file we have both using System.Linq; and using MoreLinq;.

I retargeted a project to .Net 4.7.2 and the compiler showed The call is ambiguous error as described above. The reason was that .Net 4.7.2 added new extension methods with the same name .ToHashSet().

I cannot reimplement huge code base. I cannot replace MoreLinq with another library. This is what I did. I created a new class in a new file where I have using System.Linq; but not using MoreLinq;. This is the file (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();
        }
    }
}

And I renamed all .ToHashSet() to .ToHashset() in entire solution.

圈圈圆圆圈圈 2024-10-28 07:24:26

我想知道同样的问题,我在 ASP.NET Core 6 项目中做了一个快速测试。

如果你尝试这样做,它不会编译。与不涉及扩展方法的其他不明确调用或语句非常相似。

using TestExtNs;
using TestExtNs2;

namespace YourBlazorProject.Server
{
    public class TestMe
    {
        public void Test() { }
    }
}

namespace TestNs
{
    public static class Tester
    {
        public static void RunTest() // Exec this
        {
            var x = new YourBlazorProject.Server.TestMe();
            x.Test();
            x.TestExt(); // does not compile !!! error CS0121

            TestExtNs.TesterExt.TestExt(x); //explicit call as working alternative
        }
    }
}

namespace TestExtNs
{
    public static class TesterExt
    {
        public static void TestExt(this YourBlazorProject.Server.TestMe y)
        {
            Console.WriteLine("ExtNs");
            System.Diagnostics.Debug.WriteLine("#> DIAG: ExtNs");
        }
    }
}

namespace TestExtNs2
{
    public static class TesterExt
    {
        public static void TestExt(this YourBlazorProject.Server.TestMe y)
        {
            Console.WriteLine("ExtNs2");
            System.Diagnostics.Debug.WriteLine("#> DIAG: ExtNs2");
        }
    }
}

替代方案:如果同一名称空间中存在扩展方法,则使用“更接近的方法”;否则无法编译。

// SomeTest.cs (example for 'closer namespace')

using TestExtNs; // This is hard REQUIREMENT for bringing the extension method from TestExtNs into scope !!!

namespace YourBlazorProject.Server
{
    public class TestMe
    {
        public void Test() { }
    }
}

namespace TestNs
{
    public static class Tester
    {
        public static void RunTest() // Exec this
        {
            var x = new YourBlazorProject.Server.TestMe();
            x.Test();

            x.TestExt(); //Ns
            TestExt(x); //Ns
            TestExtNs.TesterExt.TestExt(x); //ExtNs
        }

        public static void TestExt(this YourBlazorProject.Server.TestMe y)
        {
            Console.WriteLine("Ns"); //writes to the Console Window of the *.Server.exe if its out-of-process hosted. if hosted on IISExp then its visbible in if IISExp is launched from console according to stackoverflow.
            System.Diagnostics.Debug.WriteLine("#> DIAG: Ns"); //writes to the VS output console
        }
    }
}

namespace TestExtNs
{
    public static class TesterExt
    {
        public static void TestExt(this YourBlazorProject.Server.TestMe y)
        {
            Console.WriteLine("ExtNs");
            System.Diagnostics.Debug.WriteLine("#> DIAG: ExtNs");
        }
    }
}

Output:
Ns
Ns
ExtNs

I was wondering about the same question and I did a quick test inside an asp.net core 6 project.

If you try this, it does not compile. Pretty much similar as other ambiguous calls or statements not involving extension methods.

using TestExtNs;
using TestExtNs2;

namespace YourBlazorProject.Server
{
    public class TestMe
    {
        public void Test() { }
    }
}

namespace TestNs
{
    public static class Tester
    {
        public static void RunTest() // Exec this
        {
            var x = new YourBlazorProject.Server.TestMe();
            x.Test();
            x.TestExt(); // does not compile !!! error CS0121

            TestExtNs.TesterExt.TestExt(x); //explicit call as working alternative
        }
    }
}

namespace TestExtNs
{
    public static class TesterExt
    {
        public static void TestExt(this YourBlazorProject.Server.TestMe y)
        {
            Console.WriteLine("ExtNs");
            System.Diagnostics.Debug.WriteLine("#> DIAG: ExtNs");
        }
    }
}

namespace TestExtNs2
{
    public static class TesterExt
    {
        public static void TestExt(this YourBlazorProject.Server.TestMe y)
        {
            Console.WriteLine("ExtNs2");
            System.Diagnostics.Debug.WriteLine("#> DIAG: ExtNs2");
        }
    }
}

Alternative: If there is an extension method in the same namespace, this 'closer one' is used; otherwise it won't compile.

// SomeTest.cs (example for 'closer namespace')

using TestExtNs; // This is hard REQUIREMENT for bringing the extension method from TestExtNs into scope !!!

namespace YourBlazorProject.Server
{
    public class TestMe
    {
        public void Test() { }
    }
}

namespace TestNs
{
    public static class Tester
    {
        public static void RunTest() // Exec this
        {
            var x = new YourBlazorProject.Server.TestMe();
            x.Test();

            x.TestExt(); //Ns
            TestExt(x); //Ns
            TestExtNs.TesterExt.TestExt(x); //ExtNs
        }

        public static void TestExt(this YourBlazorProject.Server.TestMe y)
        {
            Console.WriteLine("Ns"); //writes to the Console Window of the *.Server.exe if its out-of-process hosted. if hosted on IISExp then its visbible in if IISExp is launched from console according to stackoverflow.
            System.Diagnostics.Debug.WriteLine("#> DIAG: Ns"); //writes to the VS output console
        }
    }
}

namespace TestExtNs
{
    public static class TesterExt
    {
        public static void TestExt(this YourBlazorProject.Server.TestMe y)
        {
            Console.WriteLine("ExtNs");
            System.Diagnostics.Debug.WriteLine("#> DIAG: ExtNs");
        }
    }
}

Output:
Ns
Ns
ExtNs
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文