我经常发现自己实现了一个类,它维护某种自己的状态属性作为枚举:我有一个 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,因此在类之外声明枚举没有意义。
在这种情况下,您使用什么命名约定?
注意:这个问题在 this question 答案的评论中得到了部分讨论。由于这不是 主要 问题,因此它没有得到太多可见度。
编辑:Filip Ekberg 针对“状态”的特定情况提出了一个 IMO 极好的解决方法。然而,我会很高兴阅读有关枚举/属性名称不同的解决方案,如 Michael Prewecki 的回答。
EDIT2(2010 年 5 月):我最喜欢的解决方案是将枚举类型名称复数,正如 Chris S 所建议的那样。根据 MS 指南,这应该仅用于标志枚举。但我越来越喜欢它了。我现在也将它用于常规枚举。
“关闭”、“开始”和“移动”的定义就是我所说的“状态”。当您暗示您正在使用“状态”时,它就是您的“状态”。所以!
public class Car
{
public enum State
{
Off,
Starting,
Moving
};
State state = State.Off;
public State Status
{
get { return state ; }
set { state= value; DoSomething(); }
}
}
如果我们从您想在这种情况下使用“类型”一词的说明中再举一个例子:
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 欧元,但它可能不会添加任何新内容。
显而易见的解决方案是将 Status 移出嵌套枚举。大多数 .NET 枚举(可能除了 Windows.Forms 命名空间中的一些枚举)都没有嵌套,这使得使用 API 的开发人员很烦人,必须在类名前面加上前缀。
没有提到的一件事是,根据 MSDN 指南的标志枚举应该 be pluralized nouns 您可能已经知道(状态是一个简单的枚举,所以应该使用单数名词)。
State(枚举称为States)是呼格,“Status”是名词的主格,英语喜欢我们的大多数语言从拉丁语中吸收。呼格是您根据其条件命名的名词,而主格是动词的主语。
所以换句话说,当汽车在移动时,这就是动词——移动就是它的状态。但是汽车不会熄火,它的引擎会。它也不会启动,引擎会启动(您可能在这里选择了一个示例,因此这可能无关紧要)。
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;
实际上,这永远不会发生,因为它们是作为驱动程序和继承链而不是使用枚举实现的,这就是为什么上面的行看起来不自然的原因。
public class EngineState
应该是 public enum EngineState
,对吧?
我认为这里真正的问题是枚举状态被封装在您的类中,因此 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
的 outside 状态,我不妨也将其定义为 outside。
因此,我可能会将其重命名为:
public enum CarStatus
{...}
public class Car
{
...
public CarStatus Status { get; set; }
}
但是,如果该枚举将在汽车类内且仅在汽车类内使用,那么我可以在那里声明该枚举。
OR
和 CR
。两者都有自己的一组状态,因此不能在自己的范围之外定义它们。
我知道我的建议违反了 .NET 命名约定,但我个人在枚举前加上“E”前缀,在枚举标志前加上“F”(类似于我们在接口前加上“I”前缀的方式)。我真的不明白为什么这不是惯例。枚举/标志是一种特殊情况,例如永远不会改变其类型的接口。它不仅清楚地说明了它是什么,而且很容易输入智能感知,因为前缀将过滤大多数其他类型/变量/等,并且您不会遇到这些命名冲突。
这也将解决另一个问题,对于 WPF 中的示例,它们使用静态类,例如具有预定义类型实例的枚举(例如 FontWeights),但如果不搜索它,您将不知道。如果他们只是在它们前面加上'E',那么你所要做的就是在字符上键入以找到这些特殊的静态类。
讨厌匈牙利符号及其变体的人该死。我使用带有后缀的枚举约定 - 等待它 - Enum
。因此,我从来没有遇到过您描述的问题,浪费时间担心如何调用它们,并且代码是可读且自描述的引导。
public class Car
{
public enum StatusEnum
{
Off,
Starting,
Moving
};
public StatusEnum Status { get; set; }
}
我会将属性名称更改为“CurrentStatus”之类的名称。快速简单:)
我建议在类型名称中添加“选项”(如果包含位标志,则添加标志),即类型为 Car.StatusOption,属性为 Car.Status。
与复数相比,这避免了在创建枚举类型的集合时出现命名冲突,在这种情况下,您通常希望对集合属性而不是枚举类型进行复数。
我通常在枚举前加上前缀,例如 CarStatus。我想这一切都取决于您正在与之合作的团队(如果他们对这类事情有任何规则/流程)和对象的使用。只是我的 2 美分(: