Вопрос по c#, enums – Перечислить с типом возврата, отличным от строки?

25

Поскольку в перечислении используются целые числа, какую другую структуру я могу использовать, чтобы предоставить enum-подобный доступ к значению, связанному с именем:

[Я знаю, что это неправильно, ищу альтернативу]

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;

Ваш Ответ

7   ответов
5

вероятно, пошел по маршруту словаря на этом. Иметь таблицу поиска в основном:

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;
    }
}
24

речисления, который может содержать 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: Attribute {public Guid Guid {get; приватный набор; } public EnumGuid (String s) {this.Guid = Guid.Parse (s); }}
Да, похоже, вы должны использовать примитивные типы для конструкторов enum, смотрите:stackoverflow.com/questions/25859094/…, Однако, как утверждает @Druaka, конвертируйте строку в Guid внутри конструктора, и все хорошо.
0

который просто содержит постоянные значения. Например:

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
Guid не может быть постоянным ....
Вы правы, я поменял их на поля только для чтения
Здесь мы идем до сих пор. Статические классы не могут иметь членов экземпляра!
Верно еще раз :-)
0

только поддержка интегральные типы (кроме символа) в качестве значения. Однако вы можете использовать что-то вроде словаря для поиска имени в значении.

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");
}
Хороший вопрос, спасибо. обновленный
Это снова мы. Статические классы не могут иметь членов экземпляра!
11

используемый 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 причине.
Не может получить доступ к закрытым полям в структурах, а также не может инициализировать поля, как вы делаете в структуре.
Вы не должны иметь возможности создавать экземпляры этой структуры, поскольку она действует только как контейнер
Сделайте это статическим классом. Это то же самое, что и кисти. Черный и так далее.
Они должны быть статичными, чтобы ваш пример работал.
0

я использовал структуры с conts в качестве публичных членов:

public struct FileExtensions
{
    public const string ProcessingExtension = ".lck";
    public const string ProcessedExtension = ".xml";
    public const string FailedExtension = ".failed";
    public const string CsvExtension = ".csv";
}
Почему люди тяготеют к структуре для этого?
@enrico: есть несколько преимуществ, таких как родительские поля в области видимости.
с использованием общедоступной очистки Guid = новая Guid ("2E43264-BB48-432B-86C4-A2B1114BF1"); в Oblic Struc я получаю ошибку сборки: "не может быть инициализаторов полей в структурах". и & quot; System.Guid не может быть объявлен как const & quot; callisto
Класс будет иметь больше смысла, учитывая, что вы можете извлечь из него и расширить константы.
Я бы не был производным от класса, единственная цель которого состоит в том, чтобы содержать постоянные значения, поскольку полиморфизм не имел бы большого смысла. Вместо этого я продолжал бы добавлять связанные константы в тот же класс или создавать новые для новых наборов констант.
2

enumКак семантика и безопасность типов, вы можете использовать такой шаблон.

(Вы можете конкретизировать это дальше, если вам нужны дополнительные функции, такие как операторы преобразования,GetUnderlyingType, ToString и т.д. Если вы хотите повторно использовать шаблон для нескольких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 Val,ue { 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"));
}

Похожие вопросы