Конфликт методов расширения - PullRequest
37 голосов
/ 12 марта 2011

Допустим, у меня есть 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 ?
        }
    }
}

Вопрос :

Я знаю, что будет выбран только один из методов расширения.
Какой это будет? и почему ?

Edit:

Это также беспокоит меня, но не так сильно, потому что в конце концов это статический метод в статическом классе:

Как я могу выбрать определенный метод из определенного пространства имен?
Обычно я бы использовал Namespace.ClassNAME.Method() ... Но это только превосходит саму идею методов расширения. И я не думаю, что вы можете использовать Variable.Namespace.Method()

Ответы [ 4 ]

29 голосов
/ 12 марта 2011

Метод не будет выбран: вызов неоднозначен и не будет компилироваться.

Почему ты не можешь сделать Namespace.ClassNAME.Method()? Конечно, ничто не мешает вам рассматривать методы расширения как обычные статические методы, и на самом деле это единственный способ исправить неоднозначность и выполнить компиляцию программы.

24 голосов
/ 09 сентября 2013

У меня был именно этот вопрос, поэтому я нашел этот пост два года спустя.Тем не менее, я думаю, важно отметить, что это только не скомпилирует и выдаст ошибку « Вызов неоднозначный » , если код, вызывающий дублирующие методы расширения, не находится в том же пространстве имен, что ииз них .

Если ОП должен был изменить пространство имен своего класса Бла на test1 или test2, то код компилируется, а расширение виспользуется то же пространство имен, что и для вызывающего абонента - даже когда оба пространства имен представлены в usings.Поэтому, если Blah находится в пространстве имен test1, возвращается «1», а если Blah находится в пространстве имен test2, возвращается «2».

Я думаю, что это важно добавить к вышеприведенным ответам, потому что я думаю, что одним из основных сценариев использования является наличие расширений в локальной библиотеке классов, которая ссылается на внешние библиотеки расширений (например, у разработчиков есть общая библиотека утилит, но есть некоторые локальные пользовательские настройки).расширения, которые могут неумышленно иметь одно и то же имя).Поддерживая пользовательские локальные расширения в том же пространстве имен, что и код, который их использует, вы можете поддерживать синтаксис вызова расширения и не возвращаться к его обработке как статическим вызовам методов.

12 голосов
/ 12 марта 2011

Как говорит Джон, если и то и другое существует, когда вы выполняете компиляцию, компиляция просто не удастся.

Но если во время компиляции существует только один, а внешняя библиотека позже обновляется для добавления второго, скомпилированный код все равно будет продолжать использовать первый. Это связано с тем, что компилятор полностью превращает ваш код в простую форму вызова namespace.classname.method.

2 голосов
/ 01 ноября 2018

Я перенес большое решение из .Net 4.7.1 в .Net 4.7.2. Мы используем LINQ в нашем коде, и мы используем хорошо известную и известную библиотеку с именем MoreLinq https://www.nuget.org/packages/morelinq/.

.Net 4.7.1 не имеет .ToHashSet() методов. Мы использовали .ToHashSet() из библиотеки MoreLinq. И в одном и том же классе в одном и том же 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() во всем решении.

...