c #: Почему эта неоднозначная ссылка на перечисление не разрешается с использованием сигнатуры метода? - PullRequest
9 голосов
/ 20 августа 2011

Рассмотрим следующий код:

namespace ConsoleApplication
{
    using NamespaceOne;
    using NamespaceTwo;

    class Program
    {
        static void Main(string[] args)
        {
            // Compilation error.  MyEnum is an ambiguous reference
            MethodNamespace.MethodClass.Frobble(MyEnum.foo);
        }
    }
}

namespace MethodNamespace
{
    public static class MethodClass
    {
        public static void Frobble(NamespaceOne.MyEnum val)
        {
            System.Console.WriteLine("Frobbled a " + val.ToString());
        }   
    }
}

namespace NamespaceOne
{
    public enum MyEnum
    {
        foo, bar, bat, baz
    }
}

namespace NamespaceTwo
{
    public enum MyEnum
    {
        foo, bar, bat, baz
    }
}

Компилятор жалуется, что MyEnum является неоднозначной ссылкой в ​​вызове Frobble ().Поскольку нет никакой двусмысленности в том, какой метод вызывается, можно ожидать, что компилятор разрешит ссылку на тип на основе сигнатуры метода.Почему бы и нет?

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

Ответы [ 3 ]

14 голосов
/ 20 августа 2011

Павел прав. В большинстве случаев в C # мы рассуждаем «изнутри наружу».

нет никакой двусмысленности в том, какой метод вызывается,

То, что это однозначно для вас не имеет значения для компилятора. Задача разрешения перегрузки состоит в том, чтобы определить, можно ли разрешить группу методов Frobble для конкретного метода с учетом известных аргументов . Если мы не можем определить типы аргументов, мы даже не пытаемся выполнить разрешение перегрузки.

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

Есть случаи, когда мы рассуждаем «извне внутрь», а именно, когда проводим анализ типа лямбд. Это делает алгоритм разрешения перегрузки чрезвычайно сложным и дает компилятору задачу, которая решается, по крайней мере, NP-HARD в плохих случаях. Но в большинстве сценариев мы хотим избежать этой сложности и затрат; выражения анализируются путем анализа дочерних подвыражений перед их родителями , а не наоборот.

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

Если вы предпочитаете более «прощающий» язык, который пытается выяснить, что вы имели в виду, VB или JScript могут быть лучшими языками для вас. Они более «делают то, что я имел в виду, а не то, что я говорил» языки.

6 голосов
/ 20 августа 2011

Я верю, потому что компилятор C # , как правило, не возвращается .

1 голос
/ 20 августа 2011

NamespaceOne и NamespaceTwo определены в одном кодовом файле.Это было бы равносильно помещению их в разные файлы кода и обращению к ним с помощью оператора using.

В этом случае вы можете понять, почему имена конфликтуют.Вы одинаково назвали enum в двух разных именах, и компилятор не может угадать, какой это, хотя Frobble имеет параметр NamespaceOne.MyEnum.Вместо

MethodNamespace.MethodClass.Frobble(MyEnum.foo)

используйте

MethodNamespace.MethodClass.Frobble(NamespaceOne.MyEnum.foo)
...