嵌套枚举和属性命名冲突

发布于 2024-08-21 04:36:15 字数 1540 浏览 1 评论 0原文

有一些相关的问题此处这里,但他们并没有真正给我满意的答案。问题在于,C# 中嵌套在类中的枚举不能与该类的属性同名。我的例子:

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; }
    ...
}

有一些选项可以解决这个问题,但它们对我来说似乎并不合适。

我可以将枚举移到类之外,但是您只需说 Suit 而不是 Card.Suit,这对我来说似乎是错误的。 Card 之外的Suit 是什么?

我可以将它们移到类之外,并将它们更改为 CardSuitCardRank 之类的内容,但随后我会觉得我正在将上下文信息烘焙到枚举的名称中,当它应该由类或命名空间名称处理时。

我可以将枚举的名称更改为 SuitsRanks,但这违反了Microsoft 的命名指南。感觉不太对劲。

我可以更改属性名称。但为了什么呢?我直觉上觉得说 Suit = Card.Suit.Spades 是正确的。

我可以将枚举移动到一个名为 CardInfo 的单独静态类中,该类仅包含这些枚举。如果我想不出其他的办法,我想这是最好的选择。

所以我想知道其他人在类似情况下做了什么。很高兴知道为什么这是不允许的。也许埃里克·利珀特(Eric Lippert)或其他人可以参与禁止它的决定?看起来它只会在类内产生歧义,这可以通过强制使用 this.Suit 作为属性名称来解决。 (类似于消除当地人和成员之间的歧义。)我认为由于 “每个功能都以 -100 点开头” 之类的东西,但我对围绕此的讨论感到好奇。

There are some related questions here and here, but they didn't really give me satisfactory answers. The problem is that enums nested in a class in C# cannot have the same name as a property of the class. My example:

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; }
    ...
}

There are a few options to hack around this, but they don't seem right to me.

I could move the enums outside the class, but then you would just say Suit instead of Card.Suit, which seems wrong to me. What is a Suit outside the context of a Card?

I could move them outside the class and change them to something like CardSuit and CardRank, but then I'd feel like I'm baking context information into the name of the enum, when that should be handled by a class or namespace name.

I could change the names of the enums to Suits and Ranks, but this violates Microsoft's naming guidelines. And it just doesn't feel right.

I could change the property names. But to what? It feels intuitively right to me to want to say Suit = Card.Suit.Spades.

I could move the enums into a separate static class called CardInfo containing only these enums. If I can't come up with anything else, I think this is the best option.

So I'm wondering what other people have done in similar situations. It would also be nice to know why this is disallowed. Maybe Eric Lippert or someone could chime in on the decision to forbid it? It seems like it only creates ambiguity within the class, and this could be resolved by forcing the use of this.Suit for the property name. (Similar to disambiguating between locals and members.) I assume this was left out due to the "every feature starts with -100 points" thing, but I would be curious about discussions around this.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

只是偏爱你 2024-08-28 04:36:15

如果知道为什么不允许这样做也很好。也许埃里克·利珀特(Eric Lippert)或其他人可以参与禁止它的决定?

该规则的要点是确保在查找名称时类内不存在歧义。某些代码区域被指定为定义“声明空间”。声明空间的基本规则是在同一声明空间中声明的两个事物不能具有相同的名称(方法除外,它们必须通过签名来区分,而不是名称。)

对这条规则做出例外只会让事情变得更加混乱,而不是减少混乱。我同意,令人烦恼的是,您不能在同一个声明空间中声明同名的属性和枚举,但是一旦您开始例外,那么它就会变得一团糟。名称​​唯一标识方法组、类型参数、属性等,这通常是一个很好的属性。

请注意,此规则适用于声明空间中声明的事物,而不是声明空间中使用的事物。如果类型 Suit 未在与属性相同的声明空间中声明,那么“public Suit Suit { get; set; }”是完全合法的。当有人说“Suit.X”时,确定 X 是属于类型(即 X 是静态成员)还是属于属性(即 X 是实例成员)有点棘手。有关详细信息,请参阅我的文章,了解如何做到这一点:

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

It would also be nice to know why this is disallowed. Maybe Eric Lippert or someone could chime in on the decision to forbid it?

The point of the rule is to ensure that there is no ambiguity within the class when looking up a name. Certain regions of code are designated as defining a 'declaration space'. The fundamental rule of declaration spaces is no two things declared in the same declaration space have the same name (except for methods, which must differ by signature, not name.)

Making exceptions to this rule just makes things more confusing, not less confusing. I agree that it is vexing that you cannot have a property and an enum of the same name declared in the same declaration space, but once you start making exceptions then it just gets to be a mess. It's usually a nice property that a name uniquely identifies a method group, type parameter, property, and so on.

Note that this rule applies to things declared in a declaration space, not things used in a declaration space. It is perfectly legal to say "public Suit Suit { get; set; }" provided that the type Suit is not declared in the same declaration space as the property. When someone says "Suit.X", figuring out whether X is on the type (that is, X is a static member) or the property (that is, X is an instance member) is a bit tricky. See my article on how we do that for details:

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

枫以 2024-08-28 04:36:15

我更喜欢使用名词后跟选项来命名枚举。
就您而言:

SuitOptions
RankOptions

毕竟,枚举只是一组可能的选项,对吧?

然后你将得到:

myCard.Suit = Card.SuitOptions.Clubs;

在我看来这是有道理的,并且在查看文本时你仍然能够知道 then 是枚举还是属性。

I prefer to name enums using a noun followed by Options.
In your case:

SuitOptions
RankOptions

After all, the enum is just a set of possible options, right?

You will have then:

myCard.Suit = Card.SuitOptions.Clubs;

Which in my opinion makes sense and you are still able to know when viewing the text whether is then enum or property.

栖迟 2024-08-28 04:36:15

我同意将枚举定义移至单独的位置。目前,枚举只能通过卡片可见,因此如果您想检查 ace,则必须执行

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

Where,如果您将其移动到单独的定义,则如果将其设为全局,则可以执行此操作:

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

I would agree with moving the enum definition to a separate place. Currently, the enums are only visible through card, so if you wanted to check for an ace, you would have to do

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

Where if you moved it to a separate definition, you could do this if you made it global:

if (card.Suit == Suit.Ace) { } //no naming clashes, easier to read
狂之美人 2024-08-28 04:36:15

看到微软命名指南< /a> 表示您应该对大多数枚举使用单数名称,对位字段使用复数名称,enum 关键字的代码示例 确实使用复数名称!

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

It't interesting to see that while the Microsoft Naming Guidelines say you should use a singular name for most enums and plural names for bit fields, the code sample for the enum keyword does use a plural name!

enum Days { Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday };
生生漫 2024-08-28 04:36:15

我会将枚举移到类定义之外,并使用命名空间来指示它们与卡片相关。我通常不喜欢嵌套在类中的枚举。不过,您对复数的看法是正确的:单数表示常规枚举,复数表示标志枚举。

I would move the enumerations outside the class definition and use the namespace to indicate that they relate to cards. I generally don't like enums nested inside classes. You're right about the plurality, though: singular for regular enums, plural for flags enums.

断爱 2024-08-28 04:36:15

enum 包装在 struct 中非常适合我的特定情况,因为还有其他数据在起作用(int Value,它也是一种值类型)。

public class Record
{
    public enum DurationUnit { Minutes, Hours }

    public struct DurationStruct
    {
        public readonly int Value;
        public readonly DurationUnit Unit;

        public DurationStruct(int value, DurationUnit unit)
        {
            Value = value;
            Unit = unit;
        }
    }
    public DurationStruct Duration; //{get; set;} -can't return a ref to a val type (in C#)

    public void Init()
    {   
        // initialize struct (not really "new" like a ref type)
        // -helpful syntax if DurationStruct ever graduated/ascended to class
        Duration = new DurationStruct(1, DurationUnit.Hours);
    }
}    

因此,对于上面的 Card 类,它将类似于以下内容

public class Card
{
    public enum Suit { Clubs, Diamonds, Spades, Hearts }
    public enum Rank { Two, Three, ...  King, Ace }

    public struct CardStruct
    {
        public Card.Suit Suit { get; private set; }
        public Card.Rank Rank { get; private set; }
    }

    //public CardStruct Card {get; set;} -can't be same as enclosing class either
    public CardStruct Identity {get; set;}

    public int Value
    {
        get    
        {
            //switch((Suit)Card.Suit)
            switch((Suit)Identity.Suit)
            {
                //case Suit.Hearts:   return Card.Rank + 0*14;
                case Suit.Hearts:   return Identity.Rank + 0*14;
                case Suit.Clubs:    return Identity.Rank + 1*14;
                case Suit.Diamonds: return Identity.Rank + 2*14;
                case Suit.Spades:   return Identity.Rank + 3*14;                
            }
        }
    }
}

Wrapping the enum in a struct was well suited for my particular case b/c there was other data at play (the int Value, which is also a value type).

public class Record
{
    public enum DurationUnit { Minutes, Hours }

    public struct DurationStruct
    {
        public readonly int Value;
        public readonly DurationUnit Unit;

        public DurationStruct(int value, DurationUnit unit)
        {
            Value = value;
            Unit = unit;
        }
    }
    public DurationStruct Duration; //{get; set;} -can't return a ref to a val type (in C#)

    public void Init()
    {   
        // initialize struct (not really "new" like a ref type)
        // -helpful syntax if DurationStruct ever graduated/ascended to class
        Duration = new DurationStruct(1, DurationUnit.Hours);
    }
}    

So for the Card class above, it would be something like the following

public class Card
{
    public enum Suit { Clubs, Diamonds, Spades, Hearts }
    public enum Rank { Two, Three, ...  King, Ace }

    public struct CardStruct
    {
        public Card.Suit Suit { get; private set; }
        public Card.Rank Rank { get; private set; }
    }

    //public CardStruct Card {get; set;} -can't be same as enclosing class either
    public CardStruct Identity {get; set;}

    public int Value
    {
        get    
        {
            //switch((Suit)Card.Suit)
            switch((Suit)Identity.Suit)
            {
                //case Suit.Hearts:   return Card.Rank + 0*14;
                case Suit.Hearts:   return Identity.Rank + 0*14;
                case Suit.Clubs:    return Identity.Rank + 1*14;
                case Suit.Diamonds: return Identity.Rank + 2*14;
                case Suit.Spades:   return Identity.Rank + 3*14;                
            }
        }
    }
}
迷乱花海 2024-08-28 04:36:15

您的枚举基本上是您定义的数据类型。您不会使用“int”或“string”作为成员名称,因此我认为在您的情况下使用枚举名称和成员名称同样是一个坏主意。

Your enums are basically data types which you have defined. You would not use 'int' or 'string' as a member name, so I think it is an equally bad idea to use the your enum names and member names in your case.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文