最初,我希望对枚举进行某种封装,但显然不是yet possible with C#。我的目的是用枚举存储某种数据。理想情况下,拥有一个对象的枚举会很棒。但显然没有办法做到这一点。所以我创建了一个状态类,一个公共枚举,并使用一个setter创建了一个公共getter / setter,该setter初始化一个方法,在该方法中我可以将对象填充为属性。 我想知道是否有更好的方法。对我来说,理想的解决方案是以正常方式设置状态(枚举):
car.State = CarStates.Idle;
然后访问有关该状态的更多数据,如下所示:
string message = car.State.Message();
但是这会涉及将属性附加到State枚举。有没有很酷的技巧来达到这个效果?枚举是唯一可以通过简单地将.Idle
添加到结尾来制作可切换,类似单身的值的方法吗?
这是我现在拥有的代码,通过添加一个可通过的图层将状态信息保持在一个级别,但在声明car.Mode.State = CarModeStates.Idle;
之类的内容时感觉多余。
class Car
{
public CarState Mode;
public Car()
{
Mode = new CarState();
}
}
class CarState //holds any metadata for given enum value
{
private int _EnumInt;
private string _Message;
private bool _IsError = false;
public CarModeStates State
{
get { return (CarModeStates)_EnumInt; }
set { _EnumInt = (int)value; InitializeState(value); }
}
public string Message { get { return _Message; } }
public bool IsError { get { return _IsError; } }
public void InitializeState(CarModeStates? cs)
{
switch (cs)
{
case (CarModeStates.Off):
{
_Message = "Car is off.";
_IsError = false;
break;
}
case (CarModeStates.Idle):
{
_Message = "Car is idling.";
_IsError = false;
break;
}
case (CarModeStates.Drive):
{
_Message = "Car is driving.";
_IsError = false;
break;
}
case (CarModeStates.Accident):
{
_Message = "CRASH!";
_IsError = true;
break;
}
}
}
}
public enum CarModeStates
{
Off,
Idle,
Drive,
Accident,
}
//And from the outside:
class SomeController
{
Car car = new Car();
public string GetStateMessage()
{
car.Mode.State = CarModeStates.Idle;
return car.Mode.Message;
}
}
答案 0 :(得分:3)
您是否尝试过扩展方法?在静态类中,定义:
public static string Message( this CarStates value )
{
switch (value) {
...
}
}
答案 1 :(得分:2)
C#中的常规枚举通常不像您的问题所暗示的那样有问题。只需确保您的switch
语句中有default
个案例,该ArgumentException
案例会引发0
以确保您获得其中一个有效值。您必须小心使用文字值enum
(可以隐式转换为任何枚举类型),但除此之外,C#中的switch
确实在API级别提供了实质性的类型安全性。
C#enums比Java使用的完全封装的枚举更好地执行 。还有一些需要注意的其他细节(例如超出范围的值),但它们在实践中很少引起问题。
Java风格的枚举类很容易在C#中创建。 编辑:除了您不能在这样的枚举的C#版本上使用sealed
语句之外。
private
。enum Color { RED, GREEN, BLUE }
。爪哇:
private class Color {
public static readonly Color RED = new Color();
public static readonly Color GREEN = new Color();
public static readonly Color BLUE = new Color();
private Color() { }
}
C#:
Enum<T>
如果您真的想模仿Java,可以通过为此表单的枚举创建Ordinal
抽象基类来保持Values
属性,并创建静态{{1}如Color
类中的以下属性:
public Color[] Values { get { return new[] { RED, GREEN, BLUE }; } }
答案 2 :(得分:1)
如果您想只使用Enum
值,那么您可以创建自己的属性以提供额外的元数据。
以下示例适用于,但我个人不会以这种方式对我的域进行建模。
// sample test app
class Program
{
static void Main(string[] args)
{
var carState = CarModeStates.Accident;
// the call to get the meta data could and probably should be stored in a local variable
Console.WriteLine(carState.GetMetaData().Message);
Console.WriteLine(carState.GetMetaData().IsError);
Console.WriteLine(carState.GetMetaData().IsUsingPetrol);
Console.Read();
}
}
扩展枚举示例
// enum with meta data
public enum CarModeStates
{
[CarStatus("Car is off."), IsError(false), IsUsingPetrol(false)]
Off,
[CarStatus("Car is idling."), IsError(false), IsUsingPetrol(true)]
Idle,
[CarStatus("Car is driving."), IsError(false), IsUsingPetrol(true)]
Drive,
[CarStatus("CRASH!"), IsError(true), IsUsingPetrol(false)]
Accident
}
用于装饰枚举的自定义属性
public interface IAttribute<out T>
{
T Description { get; }
}
[AttributeUsage(AttributeTargets.Field)]
public class CarStatusAttribute : Attribute, IAttribute<string>
{
private readonly string _value;
public CarStatusAttribute(string value)
{
_value = value;
}
public string Description
{
get { return _value; }
}
}
[AttributeUsage(AttributeTargets.Field)]
public class IsErrorAttribute : Attribute, IAttribute<bool>
{
private readonly bool _value;
public IsErrorAttribute(bool value)
{
_value = value;
}
public bool Description
{
get { return _value; }
}
}
[AttributeUsage(AttributeTargets.Field)]
public class IsUsingPetrolAttribute : Attribute, IAttribute<bool>
{
private readonly bool _value;
public IsUsingPetrolAttribute(bool value)
{
_value = value;
}
public bool Description
{
get { return _value; }
}
}
获取有关枚举的元数据的扩展方法。
public static class CarModeStatesExtensions
{
public static CarModeStateModel GetMetaData(this CarModeStates value)
{
var model = new CarModeStateModel
{
Message = value.GetDescriptionFromEnumValue<string>(typeof (CarStatusAttribute)),
IsError = value.GetDescriptionFromEnumValue<bool>(typeof(IsErrorAttribute)),
IsUsingPetrol = value.GetDescriptionFromEnumValue<bool>(typeof (IsUsingPetrolAttribute))
};
return model;
}
}
public class CarModeStateModel
{
public string Message { get; set; }
public bool IsError { get; set; }
public bool IsUsingPetrol { get; set; }
}
public static class EnumExtensions
{
public static T GetDescriptionFromEnumValue<T>(this CarModeStates value, Type attributeType)
{
var attribute = value.GetType()
.GetField(value.ToString())
.GetCustomAttributes(attributeType, false).SingleOrDefault();
if (attribute == null)
{
return default(T);
}
return ((IAttribute<T>)attribute).Description;
}
}
答案 3 :(得分:1)
也许你需要一个像这样的“工厂”:
public class CarState
{
private string message;
private bool error;
public CarState(string message, bool error)
{
this.message = message;
this.error = error;
}
public string Message
{
get { return this.message; }
}
public bool Error
{
get { return this.error; }
}
}
public static class CarStateFactory
{
public enum CarStateId { Off, Idle, Driving, Accident }
public static CarState GetCarState(CarStateId carStateId)
{
switch(carStateId)
{
case (CarStateId.Off):
{ return new CarState("Car is off", false); }
//add more cases
default:
return null;
}
}
}
通过这个,您可以通过以下方式设置您的汽车状态:
car.State = CarStateFactory.GetCarState(CarStateFactory.ID.Off); //ID.Idle, ID.Driving, ID.Accident
和强>
您可以使用car.State.Message
。
编辑: CarStateFactory的静态getter
public static CarState Idle
{
get
{
return new CarState("Car is off", false);
}
}
答案 4 :(得分:0)
与字典结合使用的扩展方法可能是解决方案而不是switch语句。
public static class CarExtensionMethods
{
public static string Message(this CarStates value)
{
return carStateDictionary[value];
}
private static readonly Dictionary<CarStates, string> carStateDictionary;
static CarExtensionMethods()
{
carStateDictionary = new Dictionary<CarStates, string>();
carStateDictionary.Add(CarStates.Off, "Car is off.");
carStateDictionary.Add(CarStates.Idle, "Car is idling.");
carStateDictionary.Add(CarStates.Drive, "Car is driving.");
carStateDictionary.Add(CarStates.Accident, "CRASH!");
}
}
用法很简单:
CarStates state = CarState.Idle;
Console.WriteLine(state.Message()); //writes "Car is idling."
另外,作为旁注,通常enum
名称在具有[Flags]
属性时应该只有复数。关键是要表明他们可以拥有多个州。枚举的更具风格的名称是CarState
,因为它不能只有一个状态。
答案 5 :(得分:0)
我知道这已经很老了但是对于更多的访问者来说,可能会使用一个状态管理器,而不是使用枚举来表示每个状态?
摘要
/// <summary>
/// Defines the expected members of a state
/// </summary>
internal interface ICarState
{
/// <summary>
/// Gets or sets the message.
/// </summary>
/// <value>
/// The message.
/// </value>
string Message { get; }
}
基础状态
/// <summary>
/// The class that all car states should inherit from.
/// </summary>
internal abstract class CarBaseState : ICarState
{
#region ICarState Members
/// <summary>
/// Gets or sets the message.
/// </summary>
/// <value>
/// The message.
/// </value>
/// </exception>
public abstract string Message { get; }
#endregion
}
实施
/// <summary>
/// Represents the state when the car is off
/// </summary>
internal class OffState : CarBaseState
{
/// <summary>
/// Gets or sets the message.
/// </summary>
/// <value>
/// The message.
/// </value>
/// </exception>
public override string Message { get { return "Off"; } }
}
/// <summary>
/// Represents the state when the car is idling
/// </summary>
internal class IdleState : CarBaseState
{
/// <summary>
/// Gets or sets the message.
/// </summary>
/// <value>
/// The message.
/// </value>
/// </exception>
public override string Message { get { return "Idling"; } }
}
管理器
internal class CarStateManager
{
#region Fields
Dictionary<string, ICarState> _stateStore = null;
#endregion
#region Properties
/// <summary>
/// Gets (or privately sets) the state of the current.
/// </summary>
/// <value>
/// The state of the current.
/// </value>
internal ICarState CurrentState { get; private set; }
#endregion
#region Constructors and Initialisation
/// <summary>
/// Initializes a new instance of the <see cref="StateManager"/> class.
/// </summary>
public CarStateManager()
{
_stateStore = new Dictionary<string, ICarState>();
}
#endregion
#region Methods
/// <summary>
/// Adds a state.
/// </summary>
/// <param name="stateId">The state identifier.</param>
/// <param name="state">The state.</param>
public void AddState(string stateId, ICarState state)
{
// Add the state to the collection
_stateStore.Add(stateId, state);
}
/// <summary>
/// Changes the state.
/// </summary>
/// <param name="stateId">The state identifier.</param>
public void ChangeState(string stateId)
{
// Set thr current state
CurrentState = _stateStore[stateId];
}
#endregion
}
程序
class Program
{
internal class StateKeys
{
public const string Off = "Off";
public const string Idle = "Idle";
}
static void Main(string[] args)
{
// Instantiate the state manager
CarStateManager stateManager = new CarStateManager();
// Add the states
stateManager.AddState(StateKeys.Off, new OffState());
stateManager.AddState(StateKeys.Idle, new IdleState());
// Change the state and display the message
stateManager.ChangeState(StateKeys.Off);
Console.WriteLine(stateManager.CurrentState.Message);
// Change the state and display the message
stateManager.ChangeState(StateKeys.Idle);
Console.WriteLine(stateManager.CurrentState.Message);
Console.ReadLine();
}
}
输出:
Off
Idling
HTH!