2012-03-07 7 views
24

Buduję aplikację, która intensywnie korzysta z Enum s dla niestandardowych danych. Zasadniczo obiekt jest przechowywany w bazie danych z około 28 oddzielnymi atrybutami. Każdy atrybut jest dwuliterowym polem, które jest tłumaczone z SQL bezpośrednio na Enum.Czy niestandardowe atrybuty dla materiałów niebezpiecznych są niebezpieczne?

Niestety, muszę przetłumaczyć te wartości na dwie wartości czytelne dla człowieka. Jedna dla legendy na tabeli danych, a druga dla klasy CSS do stylizowania obrazu w interfejsie aplikacji WWW.

Aby to zrobić, skonfigurowałem dwa niestandardowe atrybuty i zastosowałem je w razie potrzeby do Enum. Np

interfejs klienta Atrybut

public interface IAttribute<T> 
{ 
    T Value { get; } 
} 

Przykład klienta Atrybut

public sealed class AbbreviationAttribute: Attribute, IAttribute<string> 
{ 
    private readonly string value; 

    public AbbreviationAttribute(string value) 
    { 
     this.value = value; 
    } 

    public string Value 
    { 
     get { return this.value; } 
    } 
} 

metoda pobiera zwykły atrybut z Enum

public static R GetAttributeValue<T, R>(IConvertible @enum) 
{ 
    R attributeValue = default(R); 

    if (@enum != null) 
    { 
     FieldInfo fi = @enum.GetType().GetField(@enum.ToString()); 

     if (fi != null) 
     { 
      T[] attributes = fi.GetCustomAttributes(typeof(T), false) as T[]; 

      if (attributes != null && attributes.Length > 0) 
      { 
       IAttribute<R> attribute = attributes[0] as IAttribute<R>; 

       if (attribute != null) 
       { 
        attributeValue = attribute.Value; 
       } 
      } 
     } 
    } 

    return attributeValue; 
} 

Przykład Enum Stosując ten wzór

public enum Download 
{ 
    [Abbreviation("check")] 
    [Description("Certified")] 
    C = 1, 

    [Abbreviation("no-formal")] 
    [Description("No formal certification")] 
    NF = 2, 

    [Abbreviation("cert-prob")] 
    [Description("Certified with potential problems")] 
    CP = 3 
} 

Zarówno Abbreviation i Description są niestandardowych cech, które implementują IAttribute<T>. Moje rzeczywiste Enum ma 11 możliwych wartości, i jak już wspomniałem wcześniej jest używany w 28 oddzielnych właściwości w moim niestandardowym obiekcie. Używanie atrybutów niestandardowych wydawało się najlepszym sposobem na odwzorowanie tych informacji w jedną i drugą stronę.

Teraz na pytanie, jest to najlepszy sposób, aby to osiągnąć? Przechowuję wartość Enum ("C", "NF" lub "CP" we fragmencie powyżej) w bazie danych, ale potrzebuję wartości Skrót i Opis w moim kodzie. Ponadto wątpię, aby to był ostateczny zestaw niestandardowych atrybutów, których potrzebuję.

Zanim przejdę do przodu z tym wzorem ... czy to właściwy sposób na robienie rzeczy? Wolę teraz rozwiązać potencjalne problemy związane z tym podejściem niż później.

+2

Mogłem zobaczyć pewne problemy z lokalizacją w stanie, w jakim się znajduje – asawyer

+0

Dobra uwaga. Prawdopodobnie mógłbym zmodyfikować 'IAttribute', aby obsługiwał konfigurację lokalizacji w stylu' gettext'. Bardziej niepokoję się skalowalnością, wydajnością i najlepszymi praktykami, których być może nie jestem świadomy. – EAMann

+0

'GetAttributeValue' nie jest metodą rozszerzenia w przeciwieństwie do poprzedniego tekstu opisu. –

Odpowiedz

13

Jest to ta sama metoda, której używam. Jedną wadą jest serializacja. Wartości atrybutów niestandardowych nie są serializowane.

Lubię sposób niestandardowy atrybut nad metodą bazy danych, ponieważ łączy dane atrybutów prawo do wyliczenia zamiast używać tabeli odnośników lub klasę itd

+1

Drugą wadą jest to, że musisz całkowicie ponownie wdrożyć aplikację, jeśli opis zmienia się o tyle, o ile jest to znak – eouw0o83hf

+1

@ eouw0o83hf: true. złagodzone przez ostatnie opcje wdrażania (aka ClickOnce), ale masz rację. Większość moich aplikacji to web lub rzeczy z długimi okresami między cyklami wdrażania, w których wiele innych rzeczy się zmieni, więc aktualizacja kilku opisów to nic wielkiego. –

1

Czy możesz zmienić bazę danych? Myślę, że najlepszą opcją byłoby zrobienie tabeli (lub tabel) do umieszczenia możliwych wartości enumów i klucza obcego głównych obiektów do niego (zamiast używania kodów znaków - to ułatwia wciąganie i normalizuje twój DB) . Daj tabeli kolumnę Abbreviation i Description, a następnie wciągnij je i odwołaj do nich za pomocą klucza, a następnie umieść je w pamięci podręcznej, jeśli wyszukiwania są powolne.

Jedną z niebezpiecznych cech atrybutu jest to, że jeśli którykolwiek z tych ciągów kiedykolwiek musi się zmienić, jest to kompletne przeniesienie aplikacji. Jeśli tworzysz wartości bazy danych, możesz je zmienić za pomocą prostego UPDATE.

2

pewnie bym zbudować tabeli mieszania i specjalny typ czegoś takiego. Być może odrzuciłeś już ten pomysł z jakiegoś powodu, ale oto, czego bym nie znał w twojej aplikacji.

class SpecialType { 
    // include the fields and all attributes that you need to reference, ToString method for debugging, and any serialization you need 
    public string foo { get; set; } 
    public string bar { get; set; } 
    public ToString() { return "SpecialType with foo '" + foo + "' and bar '" + bar + "'"; } 
} 

Dictionary<int, SpecialType> myDict = new Dictionary<int, SpecialType> { 
    { 1, new SpecialType { foo = "XA1B2", bar = "XC3D4" } }, 
    { 2, new SpecialType { foo = "ZA1B2", bar = "ZC3D4" } }, 
    { 3, new SpecialType { foo = "YA1B2", bar = "YC3D4" } }, 
} 

Wtedy mógłbym łatwo utrzymać ints w moich innych klas, aby zaoszczędzić pamięć, dowiedzieć się, czy dana wartość była ważna przez sprawdzanie istnienia w tonacjach słownika, cały ten jazz. Prawdopodobnie byłoby o wiele łatwiej zrobić wiązanie danych, jeśli ostatecznie wykorzystasz WPF lub odczyt/zapis na dysku.

Powiązane problemy