枚举和匹配属性的C#命名约定


93

我经常发现自己实现了一个类,该类维护作为枚举的某种状态属性:我有一个Status枚举和一个Status类型的Status属性。我应该如何解决此名称冲突?

public class Car
{
  public enum Status
  {
    Off,
    Starting,
    Moving
  };

  Status status = Status.Off;

  public Status Status // <===== Won't compile =====
  {
    get { return status; }
    set { status = value; DoSomething(); }
  }
}

如果Status枚举对于不同类型是通用的,那么我将其放在类之外,这样就可以解决问题。但是Status仅适用于Car,因此在类外声明该枚举没有意义。

在这种情况下,您使用什么命名约定?

NB:这个问题在对这个问题的答案的评论中被部分辩论。由于这不是主要问题,因此可见性不高。

编辑:菲利普·埃克伯格(Filip Ekberg)针对特定的“状态”案例提出了IMO出色的解决方法。但是,我会很感兴趣地阅读有关枚举/属性名称不同的解决方案的信息,例如Michael Prewecki的答案

EDIT2(2010年5月):我最喜欢的解决方案是按照Chris S的建议对枚举类型名称进行复数。根据MS准则,此名称仅应用于标记枚举。但是我变得越来越喜欢它。我现在也将其用于常规枚举。


1
如果您想将枚举嵌套在类中,我认为没有很多好的解决方案。实际上,我更喜欢将枚举分开,这样就不会出现问题,但是我可以从哲学上理解您想要嵌套它的观点。
Craig Shearer

Answers:


32

我将在讨论中添加1欧元,但可能未添加任何新内容。

显而易见的解决方案是将Status移出嵌套Enum。大多数.NET枚举(可能不是Windows.Forms命名空间中的某些枚举)都没有嵌套,这使得使用消耗您的API的开发人员不得不为类名加上前缀会很烦人。

尚未提及的一件事是,根据MSDN指南,标志枚举应您可能已经知道的复数名词(状态是一个简单的枚举,因此应使用单数名词)。

状态(称为状态的枚举)是指称谓,“状态”是一个名词的名词,该名词像我们的大多数语言一样,英语是从拉丁语中吸收的。名词是名词,名词是名词,名词是动词的主语。

因此,换句话说,当汽车正在移动,这就是动词-移动是其状态。但是汽车不会熄火,引擎会熄火。引擎也不会启动(您可能在此处选择了一个示例,因此可能无关紧要)。

public class Car
{
  VehicleState _vehicleState= VehicleState.Stationary;

  public VehicleState VehicleState 
  {
    get { return _vehicleState; }
    set { _vehicleState = value; DoSomething(); }
  }
}

public enum VehicleState
{
    Stationary, Idle, Moving
}

状态是一个广义名词,描述它所指的状态不是更好吗?就像我上面所做的一样

在我看来,类型示例也不是指阅读器类型,而是它的数据库。如果您要描述读者的数据库产品,而该产品与读者的类型不一定相关(例如,读者的类型可能仅是转发的,已缓存的,等等),我希望使用它。所以

reader.Database = Databases.Oracle;

实际上,这永远不会发生,因为它们被实现为驱动程序和继承链,而不是使用枚举,这就是为什么上面的代码看起来不自然的原因。


24
我的理解是,标志应该是多元的,而不是简单的枚举。
Serge Wautier,09年

8
关于将枚举移出课堂,我还没有理解为什么CarState比Car.State更方便。但是,当该枚举仅描述此类的行为时,我不理解从该类中获取枚举的积极方面。
Serge Wautier 09年

我应该写像FileOptions这样的名词短语,而不仅仅是名词,我已经更新了答案。我想classname.Enum只是一个首选项-我在最终复制的框架中找不到任何示例。
克里斯S

即使MS表示应保留标志的复数形式,但随着时间的流逝,我越来越喜欢这种解决方案。我现在也将其用于枚举。因此,我改变了主意,接受了您的回答,而不是菲利普的回答。
Serge Wautier 09年

1
我知道我在这里迟到了1 1/2年,但public class EngineState应该public enum EngineState在示例中,对吗?
大卫·默多克

36

我将“关闭”,“开始”和“移动”的定义称为“状态”。当您暗示您使用的是“状态”时,它就是您的“状态”。所以!

public class Car
{
  public enum State
  {
    Off,
    Starting,
    Moving
  };

  State state = State.Off;

  public State Status
  {
    get { return state ; }
    set { state= value; DoSomething(); }
  }
}

如果我们从陈述的例子中拿另一个例子,在这种情况下,您想使用单词“ Type”:

public class DataReader
{
    public enum Type
    {
        Sql,
        Oracle,
        OleDb
    }

    public Type Type { get; set; } // <===== Won't compile =====

}

您确实需要看到枚举和枚举之间有区别,对吗?但是,当创建框架或谈论架构时,您需要专注于相似性,好的,让我们找到它们:

将某物设置为状态时,将其定义为“事物”状态

示例:汽车的状态为“运行状态”,“停止状态”等。

在第二个示例中要达到的目标是:

myDataReader.Type = DataReader.Database.OleDb

您可能会认为这与我一直在向别人宣讲的内容背道而驰,您需要遵循一个标准。但是,您正在遵循一个标准!Sql-case也是一个特定的案例,因此需要某种特定的解决方案。

但是,枚举将在您的System.Data空间内可重复使用,这就是所有模式的意义所在。

使用“类型”查看的另一种情况是“动物”,其中类型定义了种类。

public class Animal
    {
        public enum Type
        {
            Mammal,
            Reptile,
            JonSkeet
        }

        public Type Species{ get; set; }

    }

这是遵循一种模式的,您不需要为此专门“知道”对象,也无需指定“ AnimalType”或“ DataReaderType”,就可以重用所选命名空间中的枚举。


1
我相信“状态”名称只是一个例子。当您不能依赖状态/状态时,其他情况又如何呢?例如,类型枚举...
丹·C,2009年

您能提供一个示例方案吗?生病的尝试扩大我的答案,也据此:)
Filip Ekberg

2
@Filip:动物类型样本准确指出了我在第一条评论中的意思,即,这几乎是枚举的“改写”。我认为,为枚举和属性名称使用同义词会使代码有些混乱。
Dan C.

1
我也认为“物种”只是一种改写(在这种情况下,对于动物而言)。
LegendLength

2
简单地重命名并不总是那么干净-例如考虑一个带有枚举Suit和属性Suit的扑克牌类-重命名为确切的名称?笨拙的方式。
annakata

9

我认为这里的真正问题是枚举Status封装在您的类中,这样Car.Status既对属性Status又对枚举模棱两可Status

更好的是,将您的枚举放在课堂之外:

public enum Status
{
    Off,
    Starting,
    Moving
}

public class Car
{
    public Status Status
    { ... }
}

更新

由于以下评论,我将在上面解释我的设计。

我是一个不相信枚举或类或任何其他对象应该驻留另一个类中的人,除非它在该类中是完全私有的。以上面的示例为例:

public class Car
{
    public enum Status
    {...}
    ...
    public Status CarStatus { get; set;}
}

尽管有些评论者认为Status不在Car类的范围之内,但是您正在设置公共属性的事实意味着程序的其他部分使用该枚举:

public Car myCar = new Car();
myCar.CarStatus = Car.Status.Off;

对我来说是一个代码味道。如果我要去看看那个状态之外Car,我还不如把它定义之外也是如此。

因此,我可能会将其重命名为:

public enum CarStatus
{...}

public class Car
{
    ...
    public CarStatus Status { get; set; }
}

但是,如果该枚举仅在汽车类中使用,那么我可以在那里声明枚举。


这将使Status变为全局,您可能希望将其仅放在特定区域内。其他类型(例如“人类”)的“状态”可能没有“正在启动”。但是您应该遵循一种模式。
Filip Ekberg,2009年

不,他在现场。在99%的情况下,枚举与要用于属性的单词相同。枚举只是一个已命名的标志,因此它在
户外

乔恩,这正是我的观点:Status枚举仅对Car有意义。完全不同类型的对象将具有完全不同的状态
Serge Wautier 09年

它们将位于不同的命名空间中,所以这无关紧要
Chris S

想要在Car之外看它的解释很有意义。但就我而言,我有两个课程,ORCR。两者都有自己的状态集,因此不能在自己的范围之外定义它们。
deed02392 2013年

4

我知道我的建议违反了.NET命名约定,但是我个人将枚举以'E'开头,枚举标志以'F'开头(类似于我们以'I'开头的方式)。我真的不明白为什么这不是惯例。枚举/标志是一种特殊情况,例如“接口”,它永远不会改变其类型。它不仅可以清楚地说明其含义,而且很容易键入intellisense,因为该前缀将过滤大多数其他类型/变量/等,并且您不会遇到这些命名冲突。

这也将解决另一个问题,例如对于WPF中的示例,它们使用诸如枚举之类的静态类(例如FontWeights),它们具有预定义的类型实例,但您不知道是否不进行搜索。如果它们只是以“ E”作为前缀,您要做的就是键入字符以找到这些特殊的静态类。


4

讨厌匈牙利符号及其变体。我使用带有-后缀-的枚举后缀的约定Enum。因此,我永远不会遇到您所描述的问题,浪费时间来担心如何称呼它们,并且代码可读且可自我描述。

public class Car
{
  public enum StatusEnum
  {
    Off,
    Starting,
    Moving
  };

  public StatusEnum Status { get; set; }

}

9
请注意,尽管Microsoft的命名枚举约定表示:X请勿 在枚举类型名称中使用“ Enum”后缀。
DavidRR 2014年

2
因为Microsoft的约定已被证明经受了时间的考验。
nathanchere 2014年

2

我将属性的名称更改为“ CurrentStatus”。快速简单:)


1

我建议在类型名称(如果包含位标志,则为Flag)上添加“ Option”,即类型为Car.StatusOption,属性为Car.Status。

与复数相比,这可以避免在创建枚举类型的集合时命名冲突,在这种情况下,通常需要对集合属性(而不是枚举类型)进行复数。


0

我通常在枚举前面加上前缀,例如CarStatus。我想这一切都取决于您与之合作的团队(如果他们有某种规则/流程用于此类事情)和对象的使用情况。只有我的2美分(:


1
实际上,这将取消具有MyObjectName in Status的命名约定。
Filip Ekberg

从类的命名空间足以应对这种反正
annakata
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.