Подтвердить что ты не робот

Вложенные конфликты имен и имен имен

Здесь есть несколько связанных вопросов здесь и , но они действительно не дали мне удовлетворительных ответов, Проблема в том, что перечисления, вложенные в класс в С#, не могут иметь то же имя, что и свойство класса. Мой пример:

public class Card
{
    public enum Suit
    {
        Clubs,
        Diamonds,
        Spades,
        Hearts
    }

    public enum Rank
    {
        Two,
        Three,
        ...
        King,
        Ace
    }

    public Suit Suit { get; private set; }
    public Rank Rank { get; private set; }
    ...
}

Есть несколько вариантов взломать это, но они мне кажутся не такими.

Я мог бы перемещать enums вне класса, но тогда вы просто сказали бы Suit вместо Card.Suit, что кажется мне неправильным. Что такое Suit вне контекста Card?

Я мог бы перемещать их за пределы класса и менять их на что-то вроде CardSuit и CardRank, но тогда я хотел бы, чтобы я выпекал контекстную информацию в имя перечисления, когда это должно быть обработано имя класса или имени пространства.

Я мог бы изменить имена перечислений на Suits и Ranks, но это нарушает Принципы именования Microsoft. И это просто не так.

Я могу изменить имена свойств. Но к чему? Мне кажется, что я хочу сказать, Suit = Card.Suit.Spades.

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

Так что мне интересно, что сделали другие люди в подобных ситуациях. Было бы также неплохо узнать, почему это запрещено. Может быть, Эрик Липперт или кто-то может вмешаться в решение о его запрете? Похоже, он только создает неоднозначность внутри класса, и это можно решить, заставив использовать this.Suit для имени свойства. (Подобно неоднозначности между местными жителями и членами.) Я предполагаю, что это было исключено из-за "каждая функция начинается с -100 пунктов" , но мне было бы интересно узнать об этом.

4b9b3361

Ответ 1

Было бы неплохо узнать, почему это запрещено. Может быть, Эрик Липперт или кто-то может вмешаться в решение о его запрете?

Точка правила состоит в том, чтобы убедиться, что в классе нет двусмысленности при поиске имени. Определенные регионы кода обозначаются как определяющие "пространство декларации". Основное правило пространств декларации никакие две вещи, объявленные в одном пространстве декларации, имеют одно и то же имя (кроме методов, которые должны отличаться по сигнатуре, а не имени.)

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

Обратите внимание, что это правило применяется к вещам, объявленным в пространстве декларации, а не к вещам, используемым в пространстве декларации. Совершенно законно говорить "публичный Suit Suit {get; set;}" при условии, что тип Suit не объявлен в том же пространстве декларации, что и свойство. Когда кто-то говорит "Suit.X", выясняя, есть ли X в типе (т.е. X является статическим членом), или свойство (то есть X является членом экземпляра) немного сложно. См. Мою статью о том, как мы это делаем для деталей:

http://blogs.msdn.com/ericlippert/archive/2009/07/06/color-color.aspx

Ответ 2

Я предпочитаю называть перечисления с использованием существительного, за которым следуют опции. В вашем случае:

SuitOptions
RankOptions

В конце концов, перечисление представляет собой всего лишь набор возможных вариантов, правильно?

У вас будет следующее:

myCard.Suit = Card.SuitOptions.Clubs;

Что, на мой взгляд, имеет смысл, и вы все еще можете знать при просмотре текста, является ли это перечислением или свойством.

Ответ 3

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

if (card.CardSuit == Card.Suit.Ace) { }  //need different name for Suit field

Если вы переместили его в отдельное определение, вы можете сделать это, если вы сделали его глобальным:

if (card.Suit == Suit.Ace) { } //no naming clashes, easier to read

Ответ 4

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

Ответ 5

Ваши перечисления - это в основном типы данных, которые вы определили. Вы не использовали бы "int" или "string" в качестве имени участника, поэтому я думаю, что это плохая идея использовать имена вашего имени и имена членов в вашем случае.

Ответ 6

Интересно видеть, что, хотя Microsoft Naming Guidelines говорят, что вы должны использовать уникальное имя для большинства перечислений и множественных имен для битных полей, образец кода для ключевого слова enum делает, используя множественное имя!

enum Days { Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday };