【问题标题】:Switchable Unique Identifier in C#C#中的可切换唯一标识符
【发布时间】:2009-09-02 05:38:34
【问题描述】:

我正在实现一个系统来在我正在编写的程序的不同部分之间发送消息。有一些通用的消息类型以及一些特定于程序每个部分的消息类型。我想避免从每种类型的基本消息类派生所固有的层次结构腐烂,所以我将这种类型封装在 int 或 ushort 中。然后,我使用“消息”命名空间和带有一堆常量的静态类来集中不同类型。但是,我遇到了必须为每个不同部分维护唯一编号列表的问题:

namespace Messages
{
    public static class Generic
    {
        public const Int32 Unknown = 0;
        public const Int32 Initialize = 1;
        ...
        public const Int32 Destroy = 10;
    }
}

然后在别处

namespace Messages
{
    public static class Graphics
    {
        public const Int32 Unknown = 0;
        public const Int32 AddGraphic = 11; // <-- ?
    }
}

拥有任意 11 个似乎很困难,尤其是如果我有其中的几个,维护和更新以确保没有冲突似乎很痛苦。是否有一个简单的解决方案来确保对此的每个引用都是唯一的?我尝试使用静态只读,将它们从静态构造函数中的 Unique.ID() 函数初始化,但如果这样做,我将无法 switch() 传递的消息类型,因为它说“需要一个常量类型”每种情况。

【问题讨论】:

  • 只有对象有什么问题? public static readonly object AddGraphic = new object(),每个都变得唯一(至少在运行时内)?
  • 我无法根据只读值进行切换。无论如何,我正在重新考虑我的设计。

标签: c# constants uniqueidentifier switch-statement


【解决方案1】:

你不使用枚举有什么原因吗?

public enum MessageTypes
{
    Unknown,
    Initialize,
    ...
}

-- 编辑:

详细说明我的评论,考虑

enum MessageType
{
    Update,
    Delete,
    Destroy
}

MessageType t = ...;

switch(t){
   case MessageType.Update:
       DoUpdate();
   }
}

对比:

interface IActionable
{
   void Do ();
}


public abstract class ActionableBase : IActionable
{
   // some other things

   public abstract void Do ();
}


public class UpdateAction : ActionableBase
{
   public override void Do ()
   {
       // Update Code
   }
}

...

IActionable a = ...;
a.Do();

【讨论】:

  • 枚举不允许我“分片”不同消息类型的声明。 switch(message.Type) { case Messages.Generic.Initialize:break;案例 Messages.Graphics.AddGraphic:break; }
  • (呃,上面的格式很奇怪,但我相信你明白了。)
  • 我真的认为你最好重新考虑你的设计,一般来说。在 C# 中,出于消息识别的目的,您真的不应该有任何 int 常量。对于此类事情,您通常应该使用enum,或者某种形式的继承/操作系统。
  • @Damian 整数(或枚举)永远不是解决无法管理的子类数量的适当解决方案。
  • 首先,OOPS 的概念旨在减少 switch 和 if 类语句。您可以使用遗传学和良好的层次结构重新设计,而不是强制转换和切换语句。精心设计的虚拟和重写方法更快且易于维护。
【解决方案2】:

您可以为每个班级使用一个数字范围。为类定义一个基数,并将 0、1、2 等添加到该基数。

【讨论】:

    【解决方案3】:

    如果你想让它们保持数字,一种方法是将它们分成不同的大小:

    namespace Messages
    {
        public static class Generic
        { 
            // these messages are 3-figure numbers
            public const Int32 Unknown = 0;
            public const Int32 Initialize = 101;
            ...
            public const Int32 Destroy = 110;
        }
    
        public static class Graphics
        {
            // these messages are 4-figure numbers
            public const Int32 Unknown = 0;
            public const Int32 AddGraphic = 1001; // <-- ?
            // and so on...
        }
    
    }
    

    那么你只需要确保你对每种类型的消息都保持在界限内。

    【讨论】:

      【解决方案4】:

      这不是自动的,但维护起来可能比到处复制值更容易:

          public enum Generic
          {
              Unknown = 0,
              Initialize = 1,
              Destroy = 10
          }
      
          public enum Graphics
          {
              AddGraphic = Generic.Destroy + 1
          }
      

      因此,您可以让所有特定枚举都以之前枚举集中的值开始,然后像这样构建它们。

      在您的实际对象中,您可以将它们存储为 int,然后将任何枚举值转换为适当的 int。

      不过,在这种情况下,继承似乎是不可避免的,因为您的数据模型中存在自然层次结构。

      【讨论】:

      • 为什么 AddGraphic 不只是通用枚举中的另一个选项?
      • Taylor:我希望分散消息类型,以便不同的系统定义自己的消息类型。
      • @Taylor 这样他就可以将 Generic.Value 或 Graphics.Value 传递给同一个方法,并且不会有重叠的值(例如 Generic.Unknown 和 Graphics.AddGraphic 都是 0)
      • 我仍然不明白为什么它不是一个枚举,或者可能打开系统类型,然后是单个系统枚举。这样您就不必担心它们对于所有系统都是独一无二的。
      • @Taylor L 我不确定他的具体情况,但根据我的经验,如果您可以将相关数据/值与使用它的代码一起放置,它会使代码库更易于管理。减少文件之间的频繁切换和滚动浏览可能彼此几乎没有关系的常量字符串/枚举的长列表。我确实倾向于同意单独的枚举 + 类的层次结构可能是一种更好的方法,但他想保持它们之间的某种关系。
      【解决方案5】:

      我建议您查找“命令”和“消息”之间的区别,这可能会帮助您得出结论,即在消息中使用幻数\枚举是一个坏主意。

      理想情况下,您希望创建由侦听器观察和执行的“命令”...

      HTH

      奥莉

      【讨论】:

        【解决方案6】:

        如果您真的非常想这样做,您可以创建一个通用的私有枚举来保存所有可能的值。

        然后,您可以通过单独的类将这些值公开为只读属性,将枚举公开为 Int32 - 例如

        namespace Messages
        {
            private enum AllMessageTypes
            {
                Update,
                Delete,
                Destroy,
                AddGraphic 
            }
        
            public static class Generic
            {
                public Int32 Update 
                {
                    get { return (Int32)AllMessageTypes.Update; }
                }
                ...
            }
        
            public static class Graphics
            {
                public Int32 AddGraphic 
                {
                    get { return (Int32)AllMessageTypes.AddGraphic ; }
                }
            }
        }
        

        但是 - 我建议您重新设计您的解决方案。这似乎是自找麻烦(我相信人们会评论)

        【讨论】:

        • 是的。我想我将通过 && 一起创建 ID,一个“SystemID”和一个“CommandID”(00010000 && 0001)。也就是说,如果我没有找到我喜欢的重新设计的解决方案。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-11-19
        • 2022-11-16
        • 2011-08-25
        • 2010-11-28
        • 1970-01-01
        • 1970-01-01
        • 2011-08-05
        相关资源
        最近更新 更多