2016-12-16 4 views
0

Я хочу создать объект, подобный перечислению, но с дополнительным «свойством».Как создать перечисление C# с более чем одним свойством

Например я мог бы день недели перечисления:

enum Day {Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday }; 

Теперь, скажем, у меня есть еще одно свойство, я хочу, чтобы хранить на каждый день. Что-то, что никогда не меняется. Ради аргумента, скажем, у нас есть ставка оплаты, которая никогда не меняется и составляет 1,5 в субботу, 2 в воскресенье и 1 в противном случае.

Невозможно сделать это с перечислением. Я думал о создании «вспомогательного» статического класса, который просто вернул бы это второе свойство, но это кажется неуклюжим.

static class Rate 
{ 
    static float GetRate(Day d) 
    { 
     switch (d) 
     { 
      case Day.Saturday: 
       return 1.5f; 
      case Day.Sunday: 
       return 2f; 
      default: 
       return 1f; 

     } 
    } 
} 

Вместо перечисления с вспомогательным классом я мог бы использовать ReadOnlyCollection, но это кажется сложным и тяжелый вес за то, что мне нужно.

Каков наилучший путь?

+0

насчет KeyValue пары? или словарь? – ViVi

+3

Ваш код выглядит хорошо для меня. – TaW

+0

@ViVi они не постоянны/доступны только для чтения – under

ответ

3

значение C# перечислений простого одиночное-значение в отличии от на других языках, где они могут быть сложными типами (например, кортежи).

Если значение перечисления представляет собой «ключ» для неизменных данных, вы можете взломать его, используя метод расширения с switch блоком - похожий на ваш, например, но синтаксически чище при использовании:

enum Day {Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday }; 

public static class DayExtensions 
{ 
    public static Single GetRate(this Day d) 
    { 
     switch(d) 
     { 
      case Day.Saturday: 
       return 1.5f; 
      case Day.Sunday: 
       return 2f; 
      default: 
       return 1f; 
     } 
    } 
} 

Использования :

Day d = Day.Monday; 
Single rate = d.GetRate(); 
+0

Это на самом деле очень распространенный способ расширения функций enum. Вы сохраняете класс расширения в том же файле исходного кода, что и перечисление, поскольку они логически являются частью одного и того же типа. –

1

Может быть что-то вроде:

public struct Day 
{ 
    public Day(int key, float rate) 
    { 
     _key = key; 
     _rate = rate; 
    } 
    private readonly int _key; 
    private readonly float _rate; 
    public int Key => _key; 
    public float Rate => _rate; 

    public static readonly Day 
     Monday = new Day(0, 1f), 
     Tuesday = new Day(0, 1f), ...; 

    public static implicit operator int(Day day) => day.Key; 
} 

Then Day.Monday.Rate работ и int day = Day.Monday работ.

+0

Почему одновременно отображаются как частные поля, так и публичные свойства? – Dai

+0

@Dai не стесняйтесь настраивать локально, чтобы удовлетворить и т.д. :) –

+0

@Dai У вас не может быть свойство 'readonly'. Ключевое слово 'readonly' гарантирует, что значение поля не может быть изменено вне конструктора. – Maarten

2

Что вы можете сделать, это добавить пользовательский атрибут для значений перечислений следующим образом:

enum Day { 
    [MyAttr(Rate=1.5f)] 
    Sunday, 
    [MyAttr(Rate=2)] 
    Monday 
} 

public class MyAttr : Attribute { 
    public float Rate {get;set;} 
} 

Затем чтение атрибута, как это:

public float GetRate(Day day) { 
    MemberInfo memberInfo = typeof(Day).GetMember(day.ToString()).FirstOrDefault(); 

    if (memberInfo != null) { 
     MyAttr attribute = (MyAttr)memberInfo 
      .GetCustomAttributes(typeof(MyAttr), false) 
      .FirstOrDefault(); 
     return attribute.Rate; 
    } 

    return 0; 
} 
1

Вы можете использовать закрытый класс с предопределенными статическими экземплярами. Дополнительное свойство (или свойства) можно читать либо как свойство, либо посредством неявного преобразования.

public sealed class Day 
{ 
    private Day(float rate) 
    { 
     m_Rate = rate; 
    } 

    private readonly float m_Rate; 
    public float Rate { get { return m_Rate; } } 

    public static readonly Day Saturday = new Day(1.5f); 
    public static readonly Day Sunday = new Day(2f); 
    public static readonly Day Monday = new Day(1f); 
    public static readonly Day Tuesday = new Day(1f); 
    public static readonly Day Wednesday = new Day(1f); 
    public static readonly Day Thursday = new Day(1f); 
    public static readonly Day Friday = new Day(1f); 

    public static implicit operator float(Day day) 
    { 
     return day.m_Rate; 
    } 
} 

Использование:

var day = Day.Sunday; 
var rate = day.Rate;  // Use property 
float rate2 = day;  // Use implicit conversion 
Смежные вопросы