2011-09-16 10 views
37

Może mi brakować jakiegoś punktu tutaj, jeśli tak jest - włącz tę dyskusję jako część mojego pytania :).Enum z metodami funkcjonalnymi (Combine Class/Enum)

Jest to skrócona próbka działającego kodu o zmienionej nazwie. GetTicks (..) to pojedyncza próbka, która może być dowolną funkcjonalnością (wartość > 0 < 9 powinna zwrócić określoną Enum a.so).

public static class Something 
{ 
    public enum TypeOf : short 
    { 
     Minute = 2, Hour = 3, Day = 4, ........ 
    } 

    public static long GetTicks(Something.TypeOf someEnum) 
    { 
     long ticks = 0; 
     switch (someEnum) 
     { 
      case Something.TypeOf.Minute: 
       ticks = TimeSpan.TicksPerMinute; 
       break; 
      case Something.TypeOf.Hour: 
       ticks = TimeSpan.TicksPerHour; 
       break; 
     .... 
     } 
     return ticks; 
    } 
} 


// This class is called from anywhere in the system. 
public static void SomeMethod(string dodo, object o, Something.TypeOf period) 
{ 
    // With the design above 
    long ticks = Something.GetTicks(period); 

    // Traditional, if there was a simple enum 
    if (period == Something.Day) 
     ticks = TimeSpan.FromDays(1).Ticks; 
    else if (period == Something.Hour) 
     ticks = TimeSpan.FromHours(1).Ticks; 
} 

Chodzi o zbieranie funkcjonalności, która dotyczy enum, jak najbliżej samego enum. Wyliczenie jest funkcją przyczyny. Również znajduję łatwą i naturalną możliwość szukania takiej funkcjonalności w pobliżu enum. Ponadto można go łatwo modyfikować lub rozszerzać.

Wadą, którą mam, jest to, że muszę podać enum bardziej wyraźne Something.TypeOf. Wygląd może nie wyglądać normalnie? i miałoby zastosowanie, gdyby wyliczenie było do użytku wewnętrznego w klasie.

Jak mógłbyś zrobić to ładniej? Próbowałem abstrakcyjne, podstawowe dziedziczenie, częściowe. Żadne z nich nie wydaje się mieć zastosowania.

Odpowiedz

32

C# przymiotniki nie działają dobrze w ten sposób. Jednakże, można zaimplementować własną „stałe zbiór wartości” dość łatwo:

public sealed class Foo 
{ 
    public static readonly Foo FirstValue = new Foo(...); 
    public static readonly Foo SecondValue = new Foo(...); 

    private Foo(...) 
    { 
    } 

    // Add methods here 
} 

Jak to się dzieje, jeden przykład mam tego jest niezwykle podobne do Ciebie - DateTimeFieldType w Noda Time. Czasami możesz nawet chcieć, aby klasa została otwarta, ale zachowaj prywatny konstruktor - który pozwala tworzyć subklasy tylko jako zagnieżdżone klasy. Bardzo przydatny do ograniczania dziedziczenia.

Minusem jest to, że nie można użyć przełącznika :(

+0

W gruncie rzeczy, tak samo imponująco! Podoba mi się twoje podejście i zagłębię się w to później, gdy będę w stanie poświęcić czas na optymalizację i zrozumienie korzyści (jeśli w ogóle);)). – Independent

+0

Tak, podobne do Java. Chociaż zalecam używanie struktury, a nie klasy. I pole "Wartość" do szybkiego porównywania i instrukcji switch. – IllidanS4

+0

@ IllidanS4: Nie widzę żadnego szczególnego zastosowania struktury - a klasa pozwala na różne podklasy implementujące różne zachowania (podobnie jak wyliczenia Java). Dodatkowo, struktura oznaczałaby "domyślną (Foo)" zawsze była "prawdziwą" wartością, która może być bólem w szyi. Chociaż jestem pewien, że są przypadki, w których odpowiednia jest wersja struct, częściej korzystam z klas. –

71

Jeśli nie przeszkadza trochę więcej pisania można zrobić metody rozszerzenie rozszerzenie interfejsu wyliczenia.

np

public enum TimeUnit 
{ 
    Second, 
    Minute, 
    Hour, 
    Day, 
    Year, 
    /* etc */ 
} 
public static class TimeUnitExtensions 
{ 
    public static long InTicks(this TimeUnit myUnit) 
    { 
     switch(myUnit) 
     { 
      case TimeUnit.Second: 
       return TimeSpan.TicksPerSecond; 
      case TimeUnit.Minute: 
       return TimeSpan.TicksPerMinute; 
      /* etc */ 
     } 
    } 
} 

można dodać metody „Instancja” Twoje teksty stałe. jest to trochę bardziej gadatliwy niż najbardziej jak chociaż.

Pamiętaj jednak enum powinny być traktowane głównie jako nazwana wartość.

+0

Jak powiązać "TimeUnitExtensions" z instancją "TimeUnit" i instancją "TimeSpan", dla której chcesz zaznaczyć? Być może brakuje mi jakiegoś kontekstu i bez wątpienia mój brak wiedzy o C# nie pomaga. –

+2

@DavidHarkness, to z powodu "tego" w tej linii: public static long InTicks (This TimeUnit myUnit). "To" kojarzy TimeUnit z rozszerzeniem. – Seva

+0

Podoba mi się odpowiedź Jona, ale jest to również możliwe. +1, nie rozważałem metod rozszerzenia dla tego! – Joel