我正在创建一个服务器库,其中数据包关联由枚举完成。
public enum ServerOperationCode : byte
{
LoginResponse = 0x00,
SelectionResponse = 0x01,
BlahBlahResponse = 0x02
}
public enum ClientOperationCode : byte
{
LoginRequest = 0x00,
SelectionRequest = 0x01,
BlahBlahRequest = 0x02
}
当您在自己的项目中工作时,它可以正常工作 - 您可以比较返回的枚举成员(即if (packet.OperationCode == ClientOperationCode.LoginRequest)
)。但是,由于这是一个类库,用户必须定义自己的枚举。
因此,我有两个枚举添加为“抽象” - ServerOperationCode和ClientOperationCode。我知道在C#中实现抽象枚举是不可能的。我该怎么做?
答案 0 :(得分:13)
当我需要这样做时,我喜欢在我的类上使用静态实例。它允许您拥有一些默认值,但也可以通过常规的继承和接口实现方式进行扩展:
public abstract class OperationCode
{
public byte Code { get; private set; }
public OperationCode(byte code)
{
Code = code;
}
}
public class ServerOperationCode : OperationCode
{
public static ServerOperationCode LoginResponse = new ServerOperationCode(0x00);
public static ServerOperationCode SelectionResponse = new ServerOperationCode(0x01);
public static ServerOperationCode BlahBlahResponse = new ServerOperationCode(0x02);
public ServerOperationCode(byte code) : base(code) { }
}
public class ClientOperationCode : OperationCode
{
public static ClientOperationCode LoginRequest = new ClientOperationCode(0x00);
public static ClientOperationCode SelectionRequest = new ClientOperationCode(0x01);
public static ClientOperationCode BlahBlahRequest = new ClientOperationCode(0x02);
public ClientOperationCode(byte code) : base(code) { }
}
假设packet.OperationCode
返回一个字节,您可能必须为字节实现==运算符。将此代码放入您的抽象OperationCode类中。
public static bool operator ==(OperationCode a, OperationCode b)
{
return a.Code == b.Code;
}
public static bool operator !=(OperationCode a, OperationCode b)
{
return !(a == b);
}
这将允许您进行与您显示的相同的检查:
if (packet.OperationCode == ClientOperationCode.LoginRequest)
答案 1 :(得分:5)
为什么每个人都认为Enums不能被抽象出来?
类System.Enum IS 枚举的抽象。
您可以将任何枚举值分配给枚举,然后将其强制转换回原始枚举或使用名称或值。
例如:
这段代码片段来自我的一个控件库中使用的动态属性集合。我允许通过枚举值创建和访问属性,使其更快,更少人为错误
/// <summary>
/// creates a new trigger property.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="value"></param>
/// <param name="name"></param>
/// <returns></returns>
protected virtual TriggerProperty<T> Create<T>(T value, Enum name)
{
var pt = new TriggerProperty<T>(value, OnPropertyChanged, Enum.GetName(name.GetType(), name));
_properties[name.GetHashCode()] = pt;
return pt;
}
我使用Enum.GetName(Type, object)
获取枚举值的名称(为属性提供名称),出于速度和一致性的原因,我使用GetHashCode()
返回枚举成员的整数值(int的哈希码总是只是int值)
这是被调用方法的一个例子:
public enum Props
{
A, B, C, Color, Type, Region, Centre, Angle
}
public SpecularProperties()
:base("SpecularProperties", null)
{
Create<double>(1, Props.A);
Create<double>(1, Props.B);
Create<double>(1, Props.C);
Create<Color>(Color.Gray, Props.Color);
Create<GradientType>(GradientType.Linear, Props.Type);
Create<RectangleF>(RectangleF.Empty, Props.Region);
Create<PointF>(PointF.Empty, Props.Centre);
Create<float>(0f, Props.Angle);
}
答案 2 :(得分:0)
如果您想要一个可以由库的客户扩展的枚举,请查看我的CodeProject主题Symbols as extensible enums上的文章。
请注意,在我的库中,Symbol会自动为“枚举值”选择ID号,因为它设计用于单个程序内而不是用于在网络上交换值。但是,也许可以根据自己的喜好更改Symbol.cs,以便客户端可以为符号分配常量值。
答案 3 :(得分:0)
为LoginResponse,SelectionResponse等创建枚举,但不指定值。
让ServerOperationCode和ClientOperationCode实现一个函数,给定整数字节码,从Enum返回适当的值。
示例:
public enum OperationCode
{
LoginResponse,
SelectionResponse,
BlahBlahResponse
}
public interface IOperationCodeTranslator {
public OperationCode GetOperationCode(byte inputcode);
}
public class ServerOperationCode : IOperationCodeTranslator
{
public OperationCode GetOperationCode(byte inputcode) {
switch(inputcode) {
case 0x00: return OperationCode.LoginResponse;
[...]
}
}
警告:由于接口无法定义静态函数,因此如果所述函数是实例函数,ServerOperationCode和ClientOperationCode将只能实现公共接口。如果他们不需要实现公共接口,GetOperationCode可以是静态函数。
(为任何C#snafus道歉,这不是我的第一语言......)
答案 4 :(得分:0)
如果您的客户端和服务器应用程序之间共享了一个数据库,那么查找表可能有所帮助;表结构只包含一个整数值(ID)和一个字符串(名称),该表可以由应用程序的任何一方(客户端或服务器)填写,并由另一方读取。您可以将这些表(在您的代码中)缓存在字典中以便快速查找。
您也可以在app.config文件中实现相同的功能;强制您的库的用户在您的库可以轻松访问的app.config文件中设置这些值。
答案 5 :(得分:0)
我曾经写过一个类似场景的消息切换库,我决定使用泛型来传递用户定义的枚举。这个问题的主要问题是你不能将你的泛型约束到枚举类型,但只能说T:struct。有人可能会使用其他一些原始类型来实例化你的类型(尽管使用整数仍然可以起作用,前提是它们都是唯一的值。如果它们不是,字典将抛出异常。你可以使用反射添加一些额外的检查。确保你通过枚举。
public abstract class DefaultMessageHandler<T> : IMessageHandler<T> where T : struct {
public delegate void MessageHandlerDelegate(IMessage<T> message, IConnection connnection);
private readonly IDictionary<T, MessageHandlerDelegate> messageHandlerDictionary =
new Dictionary<T, MessageHandlerDelegate>();
protected void RegisterMessageHandler(T messageType, MessageHandlerDelegate handler) {
if (this.messageHandlerDictionary.ContainsKey(messageType))
return;
else this.messageHandlerDictionary.Add(messageType, handler);
}
protected void UnregisterMessageHandler(T messageType) {
if (this.messageHandlerDictionary.ContainsKey(messageType))
this.messageHandlerDictionary.Remove(messageType);
}
protected virtual void HandleUnregisteredMessage(IMessage<T> message, IConnection connection) {
}
void IMessageHandler<T>.HandleMessage(IMessage<T> message, IConnection connection) {
if (this.messageHandlerDictionary.ContainsKey(message.MessageType))
this.messageHandlerDictionary[message.MessageType].Invoke(message, connection);
else HandleUnregisteredMessage(message, connection);
}
}
根据您的示例场景,您只需将其子类化为此类。
public sealed class ServerOperationHandler : DefaultMessageHandler<ServerOperationCode> {
public ServerOperationHandler() {
this.RegisterMessageHandler(ServerOperationCode.LoginResponse, this.HandleLoginResponse);
this.RegisterMessageHandler(ServerOperationCode.SelectionResponse, this.HandleSelectionResponse);
}
private void HandleLoginResponse(IMessage<ServerOperationCode> message, IConnection connection) {
//TODO
}
private void HandleSelectionResponse(IMessage<ServerOperationCode> message, IConnection connection) {
//TODO
}
}
答案 6 :(得分:0)
如何使用静态Dictionary和虚方法来检索继承类中的静态字典?
就像您的案例的跟随:
public abstract class Operation
{
protected abstract Dictionary<string, int> getCodeTable();
public int returnOpCode(string request){ return getCodeTable()[request]; }
}
public class ServerOperation : Operation
{
Dictionary<string, int> serverOpCodeTable = new Dictionary<string, int>()
{
{"LoginResponse", 0x00,},
{"SelectionResponse", 0x01},
{"BlahBlahResponse", 0x02}
};
protected override Dictionary<string, int> getCodeTable()
{
return serverOpCodeTable;
}
}
public class ClientOperation : Operation
{
Dictionary<string, int> cilentOpCodeTable = new Dictionary<string, int>()
{
{"LoginResponse", 0x00,},
{"SelectionResponse", 0x01},
{"BlahBlahResponse", 0x02}
};
protected override Dictionary<string, int> getCodeTable()
{
return cilentOpCodeTable;
}
}