2013-01-21 7 views
6

W języku C# Jestem trochę zdziwiony, aby zrozumieć Enum.Czy można używać Enum z parami wartości jak słownik

W moim przypadku określon musiałbym sklepu stałą wartość w formacie Nazwa Wartość podobnego>

300 sekund = 5 minut

Obecnie używam tej klasy.

  • Czy można zamiast tego używać Enum, więc klasa Enum będzie wyglądać lubi?
  • Czy mogę przechowywać w wyliczeniu parę wartości?

Czy możesz podać mi próbkę kodu?

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Web; 

namespace MyWebSite.Models 
{ 
    public class Reminders 
    { 
     private sortedDictionary<int, string> remindersValue = new SortedDictionary<int, string>(); 

     // We are settign the default values using the Costructor 
     public Reminders() 
     { 
      remindersValue.Add(0, "None"); 
      remindersValue.Add(300, "5 minutes before"); 
      remindersValue.Add(900, "15 minutes before"); 
     } 

     public SortedDictionary<int, string> GetValues() 
     { 
      return remindersValue; 
     } 

    } 
} 
+1

Jaki jest cel wszystkich klawiszy "0"? Chcesz podać liczbę sekund? – atlaste

+0

Dziękuję Stefan za wskazanie. Dokonałem edycji mojego pytania. – GibboK

+2

Myślę, że powinieneś spojrzeć na klasę [TimeSpan] (http://msdn.microsoft.com/en-us/library/system.timespan.aspx) zamiast używać tych liczb. – Default

Odpowiedz

8

Możesz użyć Tuple<int, int> jako klucza słownika (przynajmniej z .NET> = 4).

Ale ponieważ faktycznie chcesz przechowywać TimeSpan, użyj tego jako klucza.

private static Dictionary<TimeSpan, string> TimeSpanText = new Dictionary<TimeSpan, string>(); 

static Reminders() 
{ 
    TimeSpanText.Add(TimeSpan.Zero, "None"); 
    TimeSpanText.Add(TimeSpan.FromMinutes(5), "5 minutes before"); 
    TimeSpanText.Add(TimeSpan.FromMinutes(15), "15 minutes before"); 
    TimeSpanText.Add(TimeSpan.FromMinutes(30), "30 minutes before"); 
    TimeSpanText.Add(TimeSpan.FromHours(1), "1 hour before"); 
    // .... 
} 

public static string DisplayName(TimeSpan ts) 
{ 
    string text; 
    if (TimeSpanText.TryGetValue(ts, out text)) 
     return text; 
    else 
     throw new ArgumentException("Invalid Timespan", "ts"); 
} 

można uzyskać tłumaczenie w ten sposób:

var quarter = TimeSpan.FromMinutes(15); 
string text = TimeSpanText[ quarter ]; 
+4

TimeSpan.FromSeconds and TimeSpan .FromMinutes itp. Zamiast ctor dostarczyć lepszy opis o tym, co się dzieje imo. – atlaste

+0

Muszę zgodzić się ze Stefanem w tej sprawie. Jednak miałoby to sens jako miła metoda rozszerzenia, np. 'TimeSpan.FromMinutes (15) .DisplayName()' – James

+0

@StefandeBruijn: Tak, chciałem tylko pokazać, jak utworzyć dowolne przedziały czasowe (np. Jedną godzinę + 30 minut) bez konieczności obliczania. Zwróć uwagę, że użyłem metody fabrycznej poniżej. –

2

Jeśli proszą można przechowywać wartość całkowitą przeciwko wyliczenia następnie tak można na przykład

public enum DurationSeconds 
{ 
    None = 0, 
    FiveMinutesBefore = 300, 
    FifteenMinutesBefore = 900, 
    ThirtyMinutesBefore = 1800, 
    OneHourBefore = 3600, 
    TwoHoursBefore = 7200, 
    OneDayBefore = 86400, 
    TwoDaysBefore = 172800 
} 
+3

Nazwy enum nie mogą rozpoczynać się od numeru iirc – atlaste

+0

@StefandeBruijn Mam zaktualizowane do używania ciągi zamiast (używane liczby dla prędkości!). – James

5

Możesz ozdobić swoje wyliczenie atrybutami opisowymi i uzyskać do nich dostęp później poprzez odbicie. Na przykład,

enum ReminderTimes 
{ 
    [Description("None")] 
    None = 0, 

    [Description("5 minutes before")] 
    FiveMinutesBefore = 300, 

    [Description("15 minutes before")] 
    FifteenMinutesBefore = 900 
} 

można dostać się z opisem przez:

public static string GetDescription(this Enum value) 
{    
    FieldInfo field = value.GetType().GetField(value.ToString()); 

    DescriptionAttribute attribute 
      = Attribute.GetCustomAttribute(field, typeof(DescriptionAttribute)) 
       as DescriptionAttribute; 

    return attribute == null ? value.ToString() : attribute.Description; 
} 

Zobacz także: http://www.codeproject.com/Articles/13821/Adding-Descriptions-to-your-Enumerations

+0

Chociaż jest to możliwe, nie widzę sensu dodawania atrybutów, gdy szukasz tylko pary nazwa-wartość (to jest jak dodanie drugiej nazwy). W tym scenariuszu powiedziałbym, że przepracowujesz. – atlaste

+0

@StefandeBruijn Zdecydowanie się zgadzam, a odpowiedź TimSchmeltera jest prawdopodobnie najlepsza. Pytanie brzmiało jednak: "czy mogę użyć enumu", więc ilustrowałem, w jaki sposób. –

+0

Chociaż może nie jest to najlepsza odpowiedź na konkretne pytanie, jest to bardzo przydatny pomysł. Dzięki. – Steven

3

enum jest właściwie nazwany typ całkowitą. Na przykład.

public enum Foo : int 
{ 
    SomeValue = 100, 
} 

co oznacza, że ​​tworzy się wyliczenie Foo z typem "int" i pewną wartością. Osobiście zawsze robię to jasno, aby pokazać, co się dzieje, ale C# niejawnie czyni go typem "int" (int 32-bitowy).

Możesz użyć dowolnej nazwy dla nazw wyliczeniowych i możesz sprawdzić, czy jest to poprawne wyliczenie za pomocą metody Enum.IsDefined (np. Aby sprawdzić, czy 300 jest poprawną nazwą wyliczeniową).

aktualizacja

Ok, faktycznie to nie jest w 100% poprawne, aby być uczciwym. Ta aktualizacja ma na celu pokazanie, co faktycznie dzieje się pod maską. Wyliczenie jest typem wartości z polami, które działają jak nazwy. Na przykład. powyższe wyliczenia jest rzeczywiście:

public struct Foo 
{ 
    private int _value; 
    public static Foo SomeValue { get { return new Foo() { _value = 100 }; } } 
} 

Zauważ, że „int” to typ int (w moim przypadku wyraźnej). Ponieważ jest to typ wartości, ma on taką samą strukturę jak prawdziwa liczba całkowita w pamięci - prawdopodobnie jest to używane przez kompilator podczas przesyłania.

0

W przeciwieństwie do tego, co zwykle robię, dodam kolejną odpowiedź, która jest odpowiedzią IMO na problem.

Zwykle chcesz, aby kompilator wykonał jak najwięcej sprawdzeń, zanim faktycznie używał sprawdzania w czasie wykonywania. Oznacza to, że w tym przypadku przy użyciu Enum dla wartości uzyskiwanie:

// provides a strong type when using values in memory to make sure you don't enter incorrect values 
public enum TimeSpanEnum : int 
{ 
    Minutes30 = 30, 
    Minutes60 = 60, 
} 

public class Reminders 
{ 
    static Reminders() 
    { 
     names.Add(TimeSpanEnum.Minutes30, "30 minutes"); 
     names.Add(TimeSpanEnum.Minutes60, "60 minutes"); 
    } 

    public Reminders(TimeSpanEnum ts) 
    { 
     if (!Enum.IsDefined(typeof(TimeSpanEnum), ts)) 
     { 
      throw new Exception("Incorrect value given for time difference"); 
     } 
    } 

    private TimeSpanEnum value; 
    private static Dictionary<TimeSpanEnum, string> names = new Dictionary<TimeSpanEnum, string>(); 

    public TimeSpan Difference { get { return TimeSpan.FromSeconds((int)value); } } 
    public string Name { get { return names[value]; } } 

} 

Tworząc program tak, język pomaga na kilka sposobów:

  • nie można używać timespans które nie są zdefiniowane
  • inicjuje słownika tylko raz, a dokładnie gdy, np. typ jest skonstruowany
  • Enum.IsDefined sprawia, że ​​na pewno nie używaj niepoprawną wartość int (np nowe Przypomnienia ((TimeSpanEnum 5)) zawiedzie
Powiązane problemy