2009-02-20 18 views
36

.net में गणना विवरण को स्थानांतरित करने का सबसे अच्छा तरीका क्या है?enum विवरण विशेषताएँ

(enum वर्णन उदाहरण के लिए Adding descriptions to enumeration constants देखें)

आदर्श रूप में मैं कुछ कैसे एप्लिकेशन के अन्य क्षेत्रों स्थानीयकृत हैं साथ संसाधनप्रबंधक और संसाधन फ़ाइलों का उपयोग करता है तो यह में फिट बैठता है चाहते हैं।

उत्तर

25

यह है कि मैं क्या के साथ जा रहा समाप्त हो गया है, मैं एक कस्टम जोड़ने में मूल्य नहीं देखा था है वर्ग का श्रेय एक धारण करने के लिए संसाधन कुंजी और फिर संसाधन फ़ाइलों में देख रहे हैं - संसाधनों के रूप में enums टाइपनाम + मान का उपयोग क्यों न करें?

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

एक एनम एक गणक नहीं है, है ना? यह एक समेकित प्रकार है, लेकिन एक गणक कुछ अलग है जो मुझे विश्वास है ... – Svish

+4

सी # 3.5 का उपयोग करके आप उस विधि को एक विस्तार विधि बना सकते हैं ताकि आप SomeEnum.Large.EnumDescription() का उपयोग कर सकें; –

+2

किसी अन्य मुद्दे की खोज करते समय बस इस प्रश्न पर ठोकर खाई। मैं केवल याद दिलाता हूं कि प्रकार और सदस्य नामों का उपयोग करके आपके आवेदन को खराब करना मुश्किल हो जाता है (आपको प्रक्रिया से समझदार घोषणा को बाहर करना होगा)। –

8

एक आसान समाधान है: संसाधन कुंजी पास करने के लिए स्थानीयकृत डिस्क्रिप्शन विशेषता का उपयोग करें।

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

    } 
+0

मुझे यकीन है कि क्या यह आपके resourceKey रूप enums पूर्ण प्रकार का नाम (namespace.enumname.value) का उपयोग कर खत्म हो जाती है नहीं कर रहा हूँ।ऐसा लगता है कि संसाधन प्रबंधक पर जाकर एक अतिरिक्त अनावश्यक कदम (स्थानीयकरण योग्य डिस्क्रिप्शन एट्रिब्यूट प्राप्त करने के प्रतिबिंब का उपयोग करके) - मुझे क्या याद आ रही है? – Ryan

+0

मुझे लगता है कि हमें एक गलतफहमी है। मैं enum मान विवरण को स्थानीयकृत करने के लिए अपनी विशेषता का उपयोग करता हूं। मुझे लगता है कि आप enums को स्थानीयकरण के बारे में बात कर रहे हैं लेकिन उनके मूल्य नहीं। – Valentin

+0

आप विवरण विशेषता के साथ enum मान को सजाने और संसाधन कुंजी पास नहीं कर सकते हैं। – Valentin

0

इस सवाल में मेरी मेज उदाहरण देखें:

Localisation/I18n of database data in LINQ to SQL

स्थिति प्रकार तालिका नक्शे मूल्यों गणन करने के लिए। वास्तविक लाभ यह है कि आप अपनी रिपोर्ट में और अपने आवेदनों में स्थानीयकरण कर सकते हैं, और तृतीय पक्षों के साथ एकीकरण के लिए बाहरी आईडी निर्दिष्ट कर सकते हैं जो आपके आंतरिक मूल्य आदि नहीं चाहते हैं। यह एनम विवरण को इसके मूल्य से decouples।

+0

डीबी केंद्रित ऐप्स के लिए अच्छी विधि, लेकिन वास्तव में मेरी ज़रूरतों के लिए ओवरकिल। – Ryan

0

आपके पास एकाधिक सिस्टम नहीं हो सकते हैं। कॉम्पोनेंट मॉडेल। डिस्क्रिप्शनएट्रिब्यूट लागू (ताकि विकल्प बाहर हो)।

तो संकेत का एक स्तर जोड़ें, विवरण संसाधन संसाधन रखता है, और फिर संसाधनों में स्थानीयकरण समर्थन का उपयोग करें। स्पष्ट रूप से enum के उपयोगकर्ताओं को ऐसा करने के लिए अपने सहायक विधि को कॉल करने की आवश्यकता होगी।

+0

वैलेंटाइन Vasiliev प्रस्ताव है लेकिन एक सहायक विधि का उपयोग करने की आवश्यकता के बिना - एक ही टिप्पणी भी लागू होता है। – Ryan

3

एक बार मैंने इसे एक बार किया था, उसी नामस्थान में एक enum के रूप में एक विस्तार विधि जोड़ने के लिए, जो एक स्ट्रिंग लौटा दी। मेरे मामले में यह सिर्फ कड़ी मेहनत की गई थी, लेकिन उन्हें संसाधन फ़ाइल से प्राप्त करने में कोई समस्या नहीं होगी।

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 ...; 
     } 
    } 
नहीं

हो सकता है कि एक extremly चिकनी या फैंसी समाधान है, लेकिन यह काम करता है =)

+0

+ 1 एक विस्तार विधि का उपयोग करने के लिए ... हालांकि मैं एनम के पूर्ण योग्य प्रकार के नाम को संसाधन कुंजी के रूप में उपयोग करना पसंद करूंगा (Ryans उत्तर देखें) –

+0

@ SDX2000: हाँ, यह स्ट्रिंग प्राप्त करने का एक बहुत अच्छा वैकल्पिक तरीका हो सकता है । – Svish

23

मेरे समाधान, देशी decription विशेषता का उपयोग:

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; 
    } 
} 

Enum घोषणा

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

फिर फोन MyEnumInstance.GetLocalizedDescription()

+0

को बाइंडिंगफ्लैग की आवश्यकता है। नॉनपब्लिक और बेस तक पहुंचने की आवश्यकता है। NameResourceType.set के भीतर डिस्क्रिप्शन। झंडे enum समर्थन के लिए मेरा जवाब देखें। – kerem

+0

यह मेरे लिए फिर अन्य समाधान के लिए अधिक पुन: प्रयोज्य लगता है। धन्यवाद – Peter

+0

मुझे यह काम करने के लिए 'टाइप रिसोर्स टाइप' को 'टाइपऑफ (रिसोर्स)' में बदलना पड़ा। धन्यवाद! – pizycki

1

फ़्लैग एनम्स के लिए समर्थन जोड़ने के लिए निम्नलिखित के साथ @ नैरिक की विधि को बदलें।

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(); 
} 

और विशेषता में NameResourceType बदल देते हैं:

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

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