Почему имя члена класса не может совпадать с именем его вложенного класса? - PullRequest
15 голосов
/ 19 января 2011

Или почему невозможно следующее:

class Material
{
    class Keys
    {
        ...
    }

    Material.Keys Keys { get; set; } // Illegal
}

Не вижу никакой двусмысленности.При обращении к экземпляру верните свойство.При доступе статически вернуть класс.Или я что-то упустил?

Я не прошу "исправить" (я знаю, что могу просто назвать его по-другому, например, MaterialKeys или тому подобное), но это скорее техническая причина, стоящая за этим ограничением.

Ответы [ 5 ]

12 голосов
/ 19 января 2011

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

Кроме того, ваша идея, что я должен предоставить вам оправдание для того, чтобы не делатьособенность задом наперед.Нам не нужно когда-либо предоставлять обоснование для , а не для выполнения функции.Скорее, предлагаемые функции должны быть обоснованы, демонстрируя, что их преимущества перевешивают их огромные затраты .Функции очень дороги, и у нас ограниченный бюджет;мы должны использовать только самые лучшие функции, чтобы предоставить их клиентам преимущества.

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

Если ответ «такой выгоды нет», то теперь вы знаете, почему языкне имеет такой возможности: потому что это делает язык хуже, нет.

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

12 голосов
/ 19 января 2011

Но представьте, что у вас было это:

class Material
{
    class Keys
    {
        ...
    }

    static Material.Keys Keys = new Keys();
}

Теперь оба находятся в "статической" области видимости.Теперь, может ли компилятор устранить неоднозначность во всех случаях?Если нет, то это нельзя допустить.

Полагаю, возможно, что устранение неоднозначности будет работать для статических полей / свойств / методов, а не для элементов-экземпляров.Или наоборот.Если бы это было так, хотели бы вы, чтобы спецификация языка позволяла члену экземпляра иметь то же имя, что и внутренний класс, но запрещать его для статики?Это просто сбивает с толку.

Но тогда в любом случае наличие совпадения с именем внутреннего класса довольно сложно.

4 голосов
/ 19 января 2011

Вы сказали,

При обращении к экземпляру возвращать свойство. При доступе статически вернуть класс.

Но что если вы скажете просто Keys где-то внутри Material? Это статический или экземплярный доступ? Относится ли это к свойству Keys или к вложенному типу Keys? Это на самом деле неоднозначно.

Например,

class Material
{
    class Keys
    {
        public static int Length;
    }

    string Keys { get; set; }

    public void Process()
    {
        // Does this refer to string.Length (via property Keys)
        // or Material.Keys.Length? It actually refers to both.
        Console.WriteLine(Keys.Length);
    }
}

Как указано в комментариях, это не вся история; но почти. Допустимо иметь свойство с именем Color типа Color, и нет конфликта:

public Color Color { get; set; }

Color.FromName(...)   // refers to static method on the type ‘Color’
Color.ToString()      // refers to instance method on the property’s value

Но это легко решить просто потому, что вещи в текущей области выигрывают у вещей в более внешних областях:

public class MyType { public string FromName(string name) { return null; } }
public MyType Color;

Color.FromName(...)   // unambiguously refers to MyType::FromName(string)
                      // via the property Color

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

3 голосов
/ 19 января 2011

Мой ответ подходит к вопросу с несколько иной точки зрения, по сравнению с другими вопросами.Из следующих двух операторов в спецификации языка C #:

The same identifier may not be used in different definitions within one scope

и

The same identifier may not be used in different definitions within one scope, unless it is probably impossible for any ambiguity to arise when the identifier is used

, первое намного проще.

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

2 голосов
/ 19 января 2011

Поскольку вложенный класс Keys является членом Material, как и свойство Keys. У вас есть два участника с именем Keys.

Точно так же вы не можете иметь два свойства, называемых одним и тем же:

public class Bar
{
    private bool Foo { get; set; }
    private string Foo { get; set; }
}

Когда вы получаете доступ к Foo, к какому из них вы пытаетесь получить доступ?

public class Material : Keys
{

    private Keys K { get; set; }
}

public class Keys
{

}

Работает нормально, но, вероятно, это не то, что вам нужно.

...