2009-02-20 13 views

Odpowiedz

25

To właśnie z skończyło się, nie widzę wartość w dodawaniu niestandardowego klasę atrybutu posiadać klucz zasobów, a następnie wyszukiwanie w plikach zasobów - dlaczego nie użyć po prostu enums nazwa_tabela + wartość jako klucza zasobów?

using System; 
using System.Resources; 
using System.Reflection; 

public class MyClass 
{ 
    enum SomeEnum {Small,Large}; 

    private ResourceManager _resources = new ResourceManager("MyClass.myResources", 
          System.Reflection.Assembly.GetExecutingAssembly());  

    public string EnumDescription(Enum enumerator) 
    {  
    string rk = String.Format("{0}.{1}",enumerator.GetType(),enumerator); 
    string localizedDescription = _resources.GetString(rk); 

    if (localizedDescription == null) 
     { 
     // A localized string was not found so you can either just return 
     // the enums value - most likely readable and a good fallback. 
     return enumerator.ToString(); 

     // Or you can return the full resourceKey which will be helpful when 
     // editing the resource files(e.g. MyClass+SomeEnum.Small) 
     // return resourceKey; 
     } 
    else 
     return localizedDescription; 
    } 


    void SomeRoutine() 
    { 
    // Looks in resource file for a string matching the key 
    // "MyClass+SomeEnum.Large" 
    string s1 = EnumDescription(SomeEnum.Large);  
    } 
} 
+4

Enum nie jest modułem wyliczającym, prawda? Jest to typ wyliczeniowy, ale moduł wyliczający jest czymś zupełnie innym, jak sądzę ... – Svish

+4

Używając C# 3.5 można uczynić tę metodę metodą rozszerzenia, aby można było następnie użyć SomeEnum.Large.EnumDescription(); –

+2

Natknąłem się na to pytanie, szukając innego problemu. Przypominam tylko, że używanie nazwy typu i nazwiska utrudnia utrudnianie aplikacji (należy wykluczyć sensowną deklarację z procesu). –

8

Istnieje proste rozwiązanie: użyj atrybutu LocalizedDescription, aby przekazać klucz zasobów.

[Serializable] 
    public class LocalizableDescriptionAttribute:DescriptionAttribute 
    { 
     public LocalizableDescriptionAttribute(string resourceKey) 
      :base(Resources.ResourceManager.GetString(resourceKey)) 
     { } 

    } 
+0

Nie jestem pewien, co to dostaje się nad wykorzystaniem teksty stałe pełna nazwa typu (namespace.enumname.value) jak resourceKey.Wydaje się, że jest to dodatkowy niepotrzebny krok (za pomocą refleksji, aby uzyskać LocalizableDescriptionAttribute) po prostu przejściem do menedżera zasobów - czego mi brakuje? – Ryan

+0

Myślę, że mamy nieporozumienie. Używam mojego atrybutu do lokalizowania opisu wartości wyliczeniowych. Sądzę, że mówisz o lokalizowaniu wyrażeń, ale nie o ich wartościach. – Valentin

+0

Nie można ozdobić wartości wyliczeniowej za pomocą atrybutu Opis i przekazać klucza zasobu. – Valentin

0

Zobacz mój przykład stół w tej kwestii: Mapy typu

Localisation/I18n of database data in LINQ to SQL

Stan tabeli na wyliczenie wartości. Prawdziwa korzyść polega na tym, że możesz zlokalizować swoje raporty i aplikacje, a także określić zewnętrzne identyfikatory do integracji z osobami trzecimi, które nie chcą wartości wewnętrznych itp. Oddziela opis enum od jego wartości.

+0

Dobra metoda dla aplikacji bazujących na db, ale naprawdę przesada dla moich potrzeb. – Ryan

0

Nie można zastosować wielu opcji System.ComponentModel.DescriptionAttribute (aby opcja była wyłączona).

Dodaj więc poziom pośredni, opis zawiera nazwę zasobu, a następnie użyj wsparcia lokalizacji w zasobach. Najwyraźniej użytkownicy enum będą musieli wywołać metodę pomocnika, aby to zrobić.

+0

Tak właśnie proponuje Valentin Vasiliev, ale bez potrzeby stosowania metody pomocniczej - ten sam komentarz dotyczy również. – Ryan

3

Jednym ze sposobów, które zrobiłem raz, było dodanie metody rozszerzania w tej samej przestrzeni nazw co wyliczenie, które zwróciło ciąg znaków. W moim przypadku było to po prostu na stałe, ale nie byłoby problemu z ich pobraniem z pliku zasobów.

public static string Describe(this SomeEnum e) 
    { 
     switch(e) 
     { 
      SomeEnum.A: 
       return "Some text from resourcefile"; 
      SomeEnum.B: 
       return "Some other text from resourcefile"; 
      ...: 
       return ...; 
     } 
    } 
nie

Może wyjątkowo gładka lub fantazyjne rozwiązanie, ale działa =)

+0

+ 1 za używanie metody rozszerzenia ... chociaż wolałbym używać pełnej nazwy typu enum jako klucza zasobu (zobacz odpowiedź Ryansa) –

+0

@ SDX2000: Tak, to mógłby być bardzo miły alternatywny sposób na uzyskanie ciągów znaków . – Svish

23

Moje rozwiązanie, wykorzystując natywne atrybut OPIS: Deklaracja

public class LocalizedEnumAttribute : DescriptionAttribute 
{ 
    private PropertyInfo _nameProperty; 
    private Type _resourceType; 

    public LocalizedEnumAttribute(string displayNameKey) 
     : base(displayNameKey) 
    { 

    } 

    public Type NameResourceType 
    { 
     get 
     { 
      return _resourceType; 
     } 
     set 
     { 
      _resourceType = value; 

      _nameProperty = _resourceType.GetProperty(this.Description, BindingFlags.Static | BindingFlags.Public); 
     } 
    } 

    public override string Description 
    { 
     get 
     { 
      //check if nameProperty is null and return original display name value 
      if (_nameProperty == null) 
      { 
       return base.Description; 
      } 

      return (string)_nameProperty.GetValue(_nameProperty.DeclaringType, null); 
     } 
    } 
} 

public static class EnumExtender 
{ 
    public static string GetLocalizedDescription(this Enum @enum) 
    { 
     if (@enum == null) 
      return null; 

     string description = @enum.ToString(); 

     FieldInfo fieldInfo = @enum.GetType().GetField(description); 
     DescriptionAttribute[] attributes = (DescriptionAttribute[])fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false); 

     if (attributes.Any()) 
      return attributes[0].Description; 

     return description; 
    } 
} 

wyliczenia

public enum MyEnum 
{ 
    [LocalizedEnum("ResourceName", NameResourceType = typeof(ResourceType))] 
    Test = 0 
} 

Następnie zadzwonić MyEnumInstance.GetLocalizedDescription()

+0

Wymaga BindingFlags.NonPublic i potrzebuje dostępu do bazy. Opis w NameResourceType.set. Zobacz moją odpowiedź na wsparcie enum flagi. – kerem

+0

Wydaje mi się, że jest to bardziej możliwe do ponownego wykorzystania niż inne rozwiązanie. Dzięki – Peter

+0

Musiałem zmienić 'NameResourceType' na' typeof (Resource) ', aby to działało. Dzięki! – pizycki

1

Zamień metodę @ nairik na następującą, aby dodać obsługę znaczników flagi.

public static string GetLocalizedDescription(this Enum @enum) 
{ 
    if (@enum == null) 
     return null; 

    StringBuilder sbRet = new StringBuilder(); 

    string description = @enum.ToString(); 

    var fields = description.Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries); 

    foreach (var field in fields) 
    { 
     FieldInfo fieldInfo = @enum.GetType().GetField(field); 
     DescriptionAttribute[] attributes = (DescriptionAttribute[])fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false); 

     if (attributes.Any()) 
      sbRet.AppendFormat("{0}, ", attributes[0].Description); 
     else 
      sbRet.AppendFormat("{0}, ", field); 
    } 

    if (sbRet.Length > 2) 
     sbRet.Remove(sbRet.Length - 2, 2); 

    return sbRet.ToString(); 
} 

i zastąpić NameResourceType w atrybucie:

public Type NameResourceType 
{ 
    get 
    { 
     return _resourceType; 
    } 
    set 
    { 
     _resourceType = value; 

     _nameProperty = _resourceType.GetProperty(base.Description, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); 
    } 
} 
Powiązane problemy