假设我在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()
答案 0 :(得分:29)
不会选择任何方法:调用不明确且无法编译。
为什么你不能Namespace.ClassNAME.Method()
?当然没有任何东西可以阻止你将扩展方法视为普通的静态方法,实际上这是你修复歧义并让程序编译的唯一方法。
答案 1 :(得分:24)
我有这个确切的问题所以我在两年后发现了这个帖子。但是,我认为重要的是要注意,如果调用重复扩展方法的代码不在同一名称空间中,那么这只会编译并且不会给出“调用是不明确的”错误其中一个。
如果OP要将其类 Blah 的命名空间更改为test1
或test2
,则代码将编译,并且扩展名与使用调用者 - 即使两个名称空间都在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()
。