【问题标题】:Enumerate with return type other than string?用字符串以外的返回类型枚举?
【发布时间】:2010-11-08 23:59:56
【问题描述】:

由于枚举使用整数,我可以使用什么其他结构来让我像枚举一样访问链接到名称的值:

[我知道这是错误的,正在寻找替代方案]

private enum Project
    {
        Cleanup = new Guid("2ED3164-BB48-499B-86C4-A2B1114BF1"),
        Maintenance = new Guid("39D31D4-28EC-4832-827B-A11129EB2"),
        Upgrade = new Guid("892F865-E38D-46D7-809A-49510111C1"),
        Sales = new Guid("A5690E7-1111-4AFB-B44D-1DF3AD66D435"),
        Replacement = new Guid("11E5CBA2-EDDE-4ECA-BDFD-63BDBA725C8C"),
        Modem = new Guid("6F686C73-504B-111-9A0B-850C26FDB25F"),
        Audit = new Guid("30558C7-66D9-4189-9BD9-2B87D11190"),
        Queries = new Guid("9985242-516A-4151-B7DD-851112F562")
    }

编辑 2014-07-20

这是对这个问题的更新答案。使用带有辅助方法的 Attribute 类,定义枚举所需的额外属性。

 public enum MultiValueEnum
    {
        [FooAttribute("alpha", 20d, true)]
        First,
        [FooAttribute("beta", 40.91d, false)]
        Second,
        [FooAttribute("gamma", 1.2d, false)]
        Third,
    }     

  public class FooAttribute : Attribute
            {
                internal FooAttribute(string name, double percentage, bool isGood)
                {
                    this.Name = name;
                    this.Percentage = (decimal)percentage;
                    this.IsGood = isGood;
                }
                public string Name { get; private set; }
                public decimal Percentage { get; private set; }
                public bool IsGood { get; private set; }
            }



  public static TAttribute GetAttribute<TAttribute>(this Enum value)
        where TAttribute : Attribute
        {
            var type = value.GetType();
            var name = Enum.GetName(type, value);
            return type.GetField(name)
                .GetCustomAttributes(false)
                .OfType<TAttribute>()
                .SingleOrDefault();
        }

这让它变得如此简单:

        MultiValueEnum enumVar = MultiValueEnum.First;
        var enumStringValue = enumVar.GetAttribute<FooAttribute>().Name;
        var enumValueDecimal = enumVar.GetAttribute<FooAttribute>().Percentage;
        var enumBool = enumVar.GetAttribute<FooAttribute>().IsGood;

【问题讨论】:

    标签: c# enums


    【解决方案1】:

    否则你可以为你的枚举创建一个自定义属性,它可以保存 Guid。

    以下内容:

    class EnumGuid : Attribute
    {
        public Guid Guid;
    
        public EnumGuid(string guid)
        {
            Guid = new Guid(guid);
        }
    }
    

    然后你会像这样使用它:

    enum Project
    {
        [EnumGuid("2ED3164-BB48-499B-86C4-A2B1114BF1")]
        Cleanup = 1,
        [EnumGuid("39D31D4-28EC-4832-827B-A11129EB2")]
        Maintenance = 2
        // and so forth, notice the integer value isn't supposed to be used, 
        // it's merely there because not assigning any value is a performance overhead.
    }
    

    最后你可以(我总是这样做)创建一个扩展来轻松获取 guid:

    static Guid GetEnumGuid(this Enum e)
    {
        Type type = e.GetType();
    
        MemberInfo[] memInfo = type.GetMember(e.ToString());
    
        if (memInfo != null && memInfo.Length > 0)
        {
            object[] attrs = memInfo[0].GetCustomAttributes(typeof(EnumGuid),false);
            if (attrs != null && attrs.Length > 0)
                return ((EnumGuid)attrs[0]).Guid;
        }
    
        throw new ArgumentException("Enum " + e.ToString() + " has no EnumGuid defined!");
    }
    

    所以最终你所要做的就是:

    Guid guid = Project.Cleanup.GetEnumGuid();
    

    我使用这种方法将描述附加到枚举,通常是包含空格的较长字符串,因此不能用作名称。

    【讨论】:

    • 这个解决方案不会为我构建。但是,如果您将 EnumGuid 上的构造函数更改为采用字符串,然后从该字符串创建 guid,它会。公共类 EnumGuid : 属性 { public Guid Guid { get;私人套装; } public EnumGuid(String s) { this.Guid = Guid.Parse(s) ; } }
    • 是的,看来您必须为枚举构造函数使用原始类型,请参阅:stackoverflow.com/questions/25859094/…。但是,正如@Druaka 所说,在构造函数中将字符串转换为 Guid,一切都很好。
    【解决方案2】:

    我见过 SubSonic 使用这种方法(结构)来存储列和表名。

    internal struct Project
    {
       public static Guid  Cleanup = new Guid("2ED3164-BB48-499B-86C4-A2B1114BF1");
       public static Guid  Maintenance = new Guid("39D31D4-28EC-4832-827B-A129EB2");
       public static Guid  Upgrade = new Guid("892F865-E38D-46D7-809A-49510111C1");
       public static Guid  Sales = new Guid("A5690E7-1111-4AFB-B44D-1DF3AD66D435");
       public static Guid  Replacement = new Guid("11E5CBA2-EDDE-4ECA-BD63-B725C8C");
       public static Guid  Modem = new Guid("6F686C73-504B-111-9A0B-850C26FDB25F");
       public static Guid  Audit = new Guid("30558C7-66D9-4189-9BD9-2B87D11190");
       public static Guid  Queries = new Guid("9985242-516A-4151-B7DD-851112F562");
    }
    

    编辑:- 感谢您评论代码中的缺陷。首先,如果 Guid 字符串不是无效的,它将编译。至于不创建实例来访问变量是的,它们需要是 public static

    【讨论】:

    • 无法访问结构中的私有字段,也无法像在结构中那样初始化字段。
    • 你不应该创建这个结构的实例,因为它只是一个容器
    • 它不会因为超过 1 个原因编译。
    • 使它成为一个静态类。这和 Brushes.Black 等是一样的。
    【解决方案3】:

    我可能会在这个上走字典路线。基本上有一个查找表:

    public class GuidMapper
    {
        private Dictionary<GuidTypes, Guid> mGuidMap = new Dictionary<GuidTypes, Guid>();
        public enum GuidTypes: int
        {
            Cleanup,
            Maintenance,
            Upgrade,
            Sales,
            Replacement,
            Modem,
            Audit,
            Queries
        }
    
        public GuidMapper()
        {
            mGuidMap.Add(GuidTypes.Cleanup, new Guid("2ED31640-BB48-499B-86C4-A2B1114BF100"));
            mGuidMap.Add(GuidTypes.Maintenance, new Guid("39D31D40-28EC-4832-827B-A11129EB2000"));
            mGuidMap.Add(GuidTypes.Upgrade, new Guid("892F8650-E38D-46D7-809A-49510111C100"));
            mGuidMap.Add(GuidTypes.Sales, new Guid("A5690E70-1111-4AFB-B44D-1DF3AD66D435"));
            mGuidMap.Add(GuidTypes.Replacement, new Guid("11E5CBA2-EDDE-4ECA-BDFD-63BDBA725C8C"));
            mGuidMap.Add(GuidTypes.Modem, new Guid("6F686C73-504B-1110-9A0B-850C26FDB25F"));
            mGuidMap.Add(GuidTypes.Audit, new Guid("30558C70-66D9-4189-9BD9-2B87D1119000"));
            mGuidMap.Add(GuidTypes.Queries, new Guid("99852420-516A-4151-B7DD-851112F56200"));
        }
    
        public Guid GetGuid(GuidTypes guidType)
        {
            if (mGuidMap.ContainsKey(guidType))
            {
                return mGuidMap[guidType];
            }
            return Guid.Empty;
        }
    }
    

    【讨论】:

      【解决方案4】:

      如果您需要适当的enum 类语义和类型安全,那么您可以使用这样的模式。

      (如果您需要转换运算符、GetUnderlyingTypeToString 等附加功能,您可以进一步充实它。如果您想将该模式重新用于具有不同基础类型的多个 enum 类类,那么您可以将任何通用代码移动到通用的抽象基类中。)

      Project x = Project.Cleanup;
      Project y = Project.Cleanup;
      Project z = Project.Maintenance;
      
      Console.WriteLine(x == y);     // True
      Console.WriteLine(x == z);     // False
      Console.WriteLine(x.Value);    // 47801daa-7437-4bfe-a240-9f7c583018a4
      
      // this line will cause a compiler error
      Console.WriteLine(x == new Guid("47801daa-7437-4bfe-a240-9f7c583018a4"));
      
      // ...
      
      public class Project
      {
          private Project(Guid v) { Value = v; }
          public Guid Value { get; private set; }
      
          public static readonly Project Cleanup =
              new Project(new Guid("47801daa-7437-4bfe-a240-9f7c583018a4"));
      
          public static readonly Project Maintenence =
              new Project(new Guid("2548a7f3-7bf4-4533-a6c1-dcbcfcdc26a5"));
      
          public static readonly Project Upgrade =
              new Project(new Guid("ed3c3e73-8e6a-4c09-84ae-7f0876d194aa"));
      }
      

      【讨论】:

        【解决方案5】:

        当遇到此类问题时,我使用带有 const 的结构作为公共成员:

        public struct FileExtensions
        {
            public const string ProcessingExtension = ".lck";
            public const string ProcessedExtension = ".xml";
            public const string FailedExtension = ".failed";
            public const string CsvExtension = ".csv";
        }
        

        【讨论】:

        • 一个类会更有意义,因为您可以从中派生并扩展常量。
        • 我不会从一个唯一目的是包含常量值的类派生,因为多态性没有多大意义。相反,我会不断将相关的常量添加到同一个类中,或者为新的常量集创建新的常量。
        • @enrico:有一些好处,比如父字段在范围内。
        • 使用 public const Guid Cleanup = new Guid("2E43264-BB48-432B-86C4-A2B1114BF1");在 oublic 结构中,我得到构建错误:“结构中不能有字段初始化器。”和“System.Guid 不能声明为 const”
        • 为什么人们会因此而倾向于使用 struct?
        【解决方案6】:

        您可以创建一个只包含常量值的静态类。 例如:

        internal static class Project
        {
            public static readonly Guid Cleanup = new Guid("2ED3164-BB48-499B-86C4-A2B1114BF1");
            public static readonly Guid Maintenance = new Guid("39D31D4-28EC-4832-827B-A11129EB2");
            public static readonly Guid Upgrade = new Guid("892F865-E38D-46D7-809A-49510111C1");
        }
        

        这样,类只是充当容器,不能从中创建对象。

        在 VB 中,这将是一个模块:

        Friend Module Project
            Public Shared ReadOnly Cleanup As Guid = New Guid("2ED3164-BB48-499B-86C4-A2B1114BF1")
            Public Shared ReadOnly Maintenance As Guid = New Guid("39D31D4-28EC-4832-827B-A11129EB2")
            Public Shared ReadOnly Upgrade As Guid = New Guid("892F865-E38D-46D7-809A-49510111C1")
        End Module
        

        【讨论】:

        • 我们继续。静态类不能有实例成员!
        【解决方案7】:

        枚举类型可以only supportintegral types(char除外)作为其值。但是,您可以使用 Dictionary 之类的东西来查找名称和值。

        Dictionary<Guid> lookup = new Dictionary<Guid>();
        lookup["Cleanup"] = new Guid("2ED3164-BB48-499B-86C4-A2B1114BF1");
        lookup["Maintenance"] = new Guid("39D31D4-28EC-4832-827B-A11129EB2");
        lookup["Upgrade"] = new Guid("892F865-E38D-46D7-809A-49510111C1");
        // etc...
        

        另一种选择是在静态类中包含一系列只读值。

        public static class Guids
        {
          public static readonly Guid Cleanup = new Guid("2ED3164-BB48-499B-86C4-A2B1114BF1");
          public static readonly Guid Maintenance = new Guid("39D31D4-28EC-4832-827B-A11129EB2");
          public static readonly Guid Upgrade = new Guid("892F865-E38D-46D7-809A-49510111C1");
        }
        

        【讨论】:

        • 我们又来了。静态类不能有实例成员!
        猜你喜欢
        • 1970-01-01
        • 2014-07-23
        • 2018-11-24
        • 1970-01-01
        • 2022-06-11
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多