如何让enum存储每个条目的额外信息

时间:2014-02-26 22:19:07

标签: c# oop enums

我有一组包含相关信息的项目。这些项目由我,程序员定义,用户不需要更改它们,它们永远不需要根据配置进行更改,并且它们可能更改的唯一时间是我的应用程序的未来版本。我事先知道应该有多少这些项目,以及它们的确切数据。

一个enum,是一个很好的编程结构,让我可以预定义我的应用程序中可用的一组键,并将它们分组为逻辑类型。

我现在需要的是一个构造,让我可以预定义一组附加了额外信息的键。

示例:

这是标准枚举:

public enum PossibleKeys
{
    Key1,
    Key2,
    Key3
}

这是我需要的枚举:

public enum PossibleItems
{
    Item1
    {
        Name = "My first item",
        Description = "The first of my possible items."
    },
    Item2
    {
        Name = "My second item",
        Description = "The second of my possible items."
    },
    Item3
    {
        Name = "My third item",
        Description = "The third of my possible items."
    }
}

我知道这种枚举不存在。我要问的是:在C#中,如何硬编码一组预定义的项目,其数据是在代码中设置的?最好的方法是什么?

编辑:我不一定想要一个使用枚举的解决方案,只是一个允许我有这种行为的解决方案,即了解我的应用程序中的所有可能项目,以及每个项目都有的信息。

编辑2:能够在运行时获取所有现有项目对我来说很重要。因此,需要能够查询所有项目并迭代它们。就像我能用枚举一样。

8 个答案:

答案 0 :(得分:4)

试试这个

public enum PossibleKeys{
    [Description("key 1 desc")]
    Key1,
    [Description("key 2 desc")]
    Key2,
    [Description("key 3 desc")]
    Key3
}

答案 1 :(得分:2)

C#在这方面不是很好 - 枚举往往只是那个,而不是其他的东西。你可以接近以下内容,但我很快就推荐一个带有私有构造函数的类和只读它自己的实例。

class Program
{
    static void Main(string[] args)
    {
        State fullState = State.Full;

        Console.WriteLine(fullState.Description());
        Console.WriteLine(State.HalfFull.Description());

        Console.ReadLine();
    }
}

public enum State
{
    Empty,
    Full,
    HalfFull
}

public static class StateExtensions
{
    private static Dictionary<State, string> descriptions = new Dictionary<State, string>();

    static StateExtensions()
    {
        descriptions.Add(State.Empty, "It's just empty");
        descriptions.Add(State.Full, "It's so full");
        descriptions.Add(State.HalfFull, "It's got something in it");
    }

    public static string Description(this State state)
    {
        return descriptions[state];
    }
}

或者基于非枚举的approched可能类似于

class MusicalNote
{
    public int Index { get; private set; }
    public string Name { get; private set; }

    private MusicalNote(int index, string name)
    {
        Index = index;
        Name = name;
    }

    public static readonly MusicalNote A = new MusicalNote(1, "A");
    public static readonly MusicalNote ASharp = new MusicalNote(2, "A#");
}

答案 2 :(得分:2)

如果纯粹是为了描述,您可以使用其他一些答案中所述的内置DescriptionAttribute。但是,如果需要属性无法提供的功能,则可以使用某种元数据对象创建查找。

这样的事情:

public enum PossibleKeys
{
    Key1,
    Key2,
    Key3
}

public class KeyMetadata
{
    public PossibleKeys Id { get; set; }
    public string Description { get; set; }
    public SomeOtherClass SomethingAttributesCantHandle { get; set; }
}

private static readonly IReadOnlyDictionary<PossibleKeys, KeyMetadata> KeyMetadataLookup;

static EnumContainerClass()
{
    Dictionary<PossibleKeys, KeyMetadata> metadata = new Dictionary<PossibleKeys, KeyMetadata>();
    metadata.Add(PossibleKeys.Key1, new KeyMetadata { Id = PossibleKeys.Key1, Description = "First Item" });
    metadata.Add(PossibleKeys.Key2, new KeyMetadata { Id = PossibleKeys.Key2, Description = "Second Item" });
    metadata.Add(PossibleKeys.Key3, new KeyMetadata { Id = PossibleKeys.Key3, Description = "Third Item" });
    KeyMetadataLookup = new ReadOnlyDictionary<PossibleKeys, KeyMetadata>(metadata);
}

然后检索:

KeyMetadataLookup[PossibleKeys.Key1].Description

请注意,如果某些属性无法处理,我只会使用此功能。如果它是所有原始类型,您也可以简单地创建自己的自定义属性。你不仅仅局限于内置的。

您自己的自定义属性最终会像:

[System.AttributeUsage(System.AttributeTargets.Enum)]
public class CustomDataAttribute : System.Attribute
{
    public string Name { get; set; }

    public string Description { get; set; }
}

然后在使用中:

public enum PossibleItems
{
    [CustomData(Name = "My first item", Description = "The first of my possible items.")]
    Item1,

    [CustomData(Name = "My second item", Description = "The second of my possible items.")]
    Item2,

    [CustomData(Name = "My third item", Description = "The third  of my possible items.")]
    Item3
}

答案 3 :(得分:1)

当我需要与枚举值相关联的描述时,我通过在每个枚举值上放置DescriptionAttribute然后使用扩展方法来获取对该数据的访问权来执行此操作。这是一个完整的LINQPad示例。

// Make sure to add a using for System.ComponentModel

void Main()
{
    Test.First.GetDescription().Dump();
    Test.Second.GetDescription().Dump();
}

public enum Test
{
    [Description("My first enum value's description.")]
    First = 1,
    [Description("My second enum value's description.")]
    Second = 2
}

public static class EnumExtensions
{
    public static string GetDescription(this Enum value)
    {
        DescriptionAttribute[] descriptionAttributes = (DescriptionAttribute[])value.GetType().GetField(value.ToString()).GetCustomAttributes(typeof(DescriptionAttribute), false);
        return (descriptionAttributes != null && descriptionAttributes.Length > 0 ? descriptionAttributes[0].Description : null);
    }
}

此输出

  

我的第一个枚举值的描述​​。

     

我的第二个枚举值的描述​​。

答案 4 :(得分:1)

public class PossibleItems
{
    public class Item1
    {
        public static readonly string Name = "My first item";
        public static readonly string  Description = "The first of my possible items.";
    }

    public class Item2
    {
        public static readonly string  Name = "My second item";
        public static readonly string  Description = "The second of my possible items.";
    }

    public class Item3
    {
        public static readonly string  Name = "My third item";
        public static readonly string  Description = "The third of my possible items.";
    }
}

使用PossibleItems.Item1.Name;

进行访问

答案 5 :(得分:1)

另一种替代方法是使用 Java样式枚举

public class PossibleItems
{
    public string Name { private set; get; }
    public string Description { private set; get; }

    public static PossibleItems Item1 = new PossibleItems() { Name = "My first item", Description = "The first of my possible items" };
    public static PossibleItems Item2 = new PossibleItems() { Name = "My second  item", Description = "The second  of my possible items" };

    private PossibleItems()
    {

    }

    public override int GetHashCode()
    {
        return (Name + ";" + Description).GetHashCode();
    }

    public override bool Equals(object obj)
    {
        if(!(obj is PossibleItems)) return false;
        var other = obj as PossibleItems;
        return other.Name == Name && other.Description == Description;
    }
}

bool eq  = PossibleItems.Item1 == PossibleItems.Item1;
Console.WriteLine(PossibleItems.Item1.Name);

答案 6 :(得分:0)

我同意你应该使用某种类。但是如果你真的想使用Enums,你也可以添加一个扩展方法。

public static PossibleItem GetPossibleItem(this PossibleKey key){
    switch (key){
       case Key1:
       return WhateverItem;
       ...
}

然后你可以调用Key1.GetPossibleItem();

答案 7 :(得分:0)

 static class PossibleItems
    {
        public class Item
        {
            public readonly string Name;
            public readonly string Description;

            public Item(string name, string desc)
            {
                this.Name = name;
                this.Description = desc;
            }
        }

        public static List<Item> Get()
        {
            List<Item> list = new List<Item>();
            list.Add(new Item("name1", "desc1"));
            list.Add(new Item("name2", "desc2"));
            return list;
        }
    }

然后以迭代的方式进行访问

foreach ( PossibleItem.Item item in PossibleItems.Get())
{
    MessageBox.Show(item.Name + ": " + item.Description);
}

如果您想要一个具有特定名称的项目,您甚至可以将此代码添加到PossibleItems类

        public static Item GetItemWithName(PossibleNames name)
        {
            switch (name)
            {
                case PossibleNames.Name1:
                    return new Item("Name1", "Desc1");

                case PossibleNames.Name2:
                    return new Item("Name2", "Desc2");
            }
            return null;
        }

        public enum PossibleNames
        {
            Name1,
            Name2
        }

P.S。我在智能手机上输入了额外的积分