枚举和匹配属性的 C # 变数命名原则

我经常发现自己实现了一个类,该类维护某种类型的状态属性作为枚举: 我有一个 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,因此在类之外声明枚举是没有意义的。

这种情况下你用什么变数命名原则?

注: 这个问题在 这个问题答案的评论中有部分讨论。因为这不是 总台的问题,所以能见度不高。

编辑: 菲利普埃克伯格建议一个国际海事组织优秀的解决方案的具体情况下的“状态”。然而,如果能够阅读到 Enum/属性名称不同的解决方案,比如 Michael Prewecki 的 回答,我会很感兴趣。

EDIT2(2010年5月) : 我最喜欢的解决方案是将枚举类型名称复数化,正如 Chris S 所建议的那样。根据 MS 指南,这应该只用于标志枚举。但我越来越喜欢它了。我现在也将它用于普通枚举。

50795 次浏览

I usually prefix the enums, e.g. CarStatus. I suppose it all depends on team you're working with (if they have any rules/ processes for that sort of thing) and the objects usage. Just my 2 cents (:

The definition of "Off", "Starting" and "Moving" is what i would call a "State". And when you are implying that you are using a "State", it is your "Status". So!

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


State state = State.Off;


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

If we take another example from the one stated where you'd like to use the word "Type" such in this case:

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


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


}

You really need to see that there is a difference between enums and enums, right? But when creating a framework or talking about architecture you need to focus on the simillarities, ok lets find them:

When something is set to a State, it's defined as the "things" Status

Example: The Car's Status is in Running State, Stopped State, and so on.

What you want to acheive in the second example is somewhat this:

myDataReader.Type = DataReader.Database.OleDb

You might think that this says against what i've been preaching about to others, that you need to follow a standard. But, you are following a standard! The Sql-case is a specific case aswell and therefore need a somewhat specific solution.

However, the enum would be re-usable within your System.Data space, and that's what the patterns is all about.

Another case to look at with the "Type" is "Animal" where Type defines the Species.

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


public Type Species{ get; set; }


}

This is following a pattern, you don't specificly need to "know" the Object for this and you are not specifing "AnimalType" or "DataReaderType", you can re-use the enums in your namespace of choice.

I'd change the name of the property to something like "CurrentStatus". Quick an easy :)

I think the real problem here is that the enum Status is encapsulated within your class, such that Car.Status is ambiguous to both the property Status and the enum Status

Better yet, put your enum outside of the class:

public enum Status
{
Off,
Starting,
Moving
}


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

UPDATE

Due to the comments below, I'll explain my design above.

I'm one who doesn't believe that enums or classes or any other object should reside inside another class, unless it will be totally private within that class. Take the above example, for instance:

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

While some commenters would argue that Status doesn't have any meaning outside the scope of the class Car, the fact that you are setting a public property means that there are other parts of the program that will use that enum:

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

And that to me is a code smell. If I'm going to look at that status outside of Car, I might as well define it outside as well.

As such, I will probably just rename it as:

public enum CarStatus
{...}


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

However, if that enum will be used within and only within the car class, then I'm fine with declaring the enum there.

I'll add my 1 euro to the discussion but it's probably not adding anything new.

The obvious solution is to move Status out of being a nested Enum. Most .NET enums (except possibly some in Windows.Forms namespace) aren't nested and it makes it annoying to use for the developer consuming your API, having to prefix the classname.

One thing that hasn't been mentioned is that flag enums according to MSDN guidelines should be pluralized nouns which you probably already know (Status is a simple enum so singular nouns should be used).

State (enum called States) is the vocative, "Status" is the nominative of a noun that the English like most of our language absorbed from Latin. Vocative is what you name a noun for its condition and nominative is the subject of the verb.

So in other words when the car is moving, that's the verb - moving is its status. But the car doesn't go off, its engine does. Nor does it start, the engine does (you probably picked an example here so this might be irrelevant).

public class Car
{
VehicleState _vehicleState= VehicleState.Stationary;


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


public enum VehicleState
{
Stationary, Idle, Moving
}

State is such a generalised noun wouldn't it be better to describe what state it is referring to? Like I did above

The type example also in my view doesn't refer to the reader type, but its database. I would prefer it if you were describing the reader's database product which isn't necessarily relevant to the type of reader (e.g. the type of reader might be forward only, cached and so on). So

reader.Database = Databases.Oracle;

In reality this never happens as they're implemented as drivers and an inheritance chain instead of using enums which is why the line above doesn't look natural.

I know my suggestion goes against the .NET Naming conventions, but I personally prefix enums with 'E' and enum flags with 'F' (similar to how we prefix Interfaces with 'I'). I really do not understand why this is not the convention. Enums/Flags are a special case like Interfaces that will never change their type. Not only does it make it clear what it is, it's very easy to type in intellisense since the prefix will filter most other types/variables/etc, and you won't have these naming clashes.

And that would also solve another problem where for examples in WPF they use static classes like enums (e.g. FontWeights) that have pre-defined instances of types but you would not know if you don't search for it. If they just prefixed them with 'E', all you would have to do is type on character to find these special static classes.

I suggest adding "Option" to the type name (or Flag if it contains bit flags), i.e. type is Car.StatusOption and property is Car.Status.

Compared to pluralizing, this avoids naming collisions when creating collections of the enum type, where you would normally want to pluralize the collection property, not the enum type.

Haters of Hungarian notation and its variants be damned. I use a convention of suffixing enums with - wait for it - Enum. I consequently never have the problem you describe, waste time worrying about what to call them and the code is readable and self-descriptive to boot.

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


public StatusEnum Status { get; set; }


}