एनाम मूल्यों के लिए कस्टम स्ट्रिंग प्रारूपण के साथ मेरे पास एक एनम बाउंड कॉम्बोबॉक्स कैसे है?


135

Enum ToString पोस्ट में DescriptionAttribute, इस तरह से कस्टम विशेषता का उपयोग करने के लिए एक विधि का वर्णन किया गया है :

Enum HowNice {
  [Description("Really Nice")]
  ReallyNice,
  [Description("Kinda Nice")]
  SortOfNice,
  [Description("Not Nice At All")]
  NotNice
}

और फिर, आप एक फ़ंक्शन कहते हैं GetDescription, जैसे सिंटैक्स का उपयोग करके:

GetDescription<HowNice>(NotNice); // Returns "Not Nice At All"

लेकिन यह वास्तव में मेरी मदद नहीं करता है, जब मैं बस एक एनबूम के मूल्यों के साथ एक कॉम्बो बॉक्स को आबाद करना चाहता हूं, क्योंकि मैं कॉम्बो बॉक्स को कॉल करने के लिए मजबूर नहीं कर सकताGetDescription

मुझे क्या चाहिए निम्नलिखित आवश्यकताएँ हैं:

  • रीडिंग (HowNice)myComboBox.selectedItemचयनित मान को एनम मान के रूप में लौटाएगा।
  • उपयोगकर्ता को उपयोगकर्ता के अनुकूल डिस्प्ले स्ट्रिंग्स को देखना चाहिए, न कि केवल एन्यूमरेशन मानों का नाम। इसलिए " NotNice" देखने के बजाय , उपयोगकर्ता " Not Nice At All" को देखेगा ।
  • उम्मीद है, समाधान के लिए मौजूदा गणना के लिए न्यूनतम कोड परिवर्तन की आवश्यकता होगी।

जाहिर है, मैं प्रत्येक एनुम के लिए एक नया वर्ग लागू कर सकता हूं जिसे मैं बनाता हूं, और इसके ओवरराइड करता हूं ToString(), लेकिन यह कि प्रत्येक एनम के लिए बहुत काम है, और मैं इससे बचता हूं।

कोई विचार?

बिल्ली, मैं भी एक इनाम के रूप में एक आलिंगन में फेंक देंगे :-)


1
jjnguy सही है कि जावा एनम इस अच्छी तरह से हल करता है ( javahowto.blogspot.com/2006/10/… ), लेकिन यह संदिग्ध प्रासंगिकता है।
मैथ्यू फ्लैशेन

8
जावा एनम एक मजाक है। शायद वे 2020 में गुण जोड़ लेंगे: /
चाड अनुदान

एक लाइटर के लिए (लेकिन यकीनन कम मजबूत) समाधान मेरे धागे को देखते हैं ।
20

जवाबों:


42

आप एक TypeConverter लिख सकते हैं जो आपके संसाधनों में उन्हें देखने के लिए निर्दिष्ट विशेषताओं को पढ़ता है। इस प्रकार आपको बिना किसी परेशानी के प्रदर्शन नामों के लिए बहु-भाषा समर्थन मिलेगा।

TypeConverter के ConvertFrom / ConvertTo तरीकों में देखें, और अपने एनम फ़ील्ड पर विशेषताओं को पढ़ने के लिए प्रतिबिंब का उपयोग करें ।


ठीक है, मैंने कुछ कोड लिखे (इस प्रश्न का उत्तर देखें) - क्या आपको लगता है कि यह पर्याप्त है, क्या मुझे कुछ याद आ रहा है?
शालोम क्रेमर

1
अच्छा है। बेहतर ओवरहाल, लेकिन आपके रन-ऑफ-द-मिल के लिए ओवरकिल हो सकता है, कभी-कभी-कभी-वैश्वीकृत सॉफ्टवेयर के किसी भी तरह का टुकड़ा। (मुझे पता है, यह धारणा बाद में झूठी हो जाएगी; ;-))
peSHIr

85

ComboBoxआपके पास वह सब कुछ है जो आवश्यक है: FormattingEnabledसंपत्ति, जिसे आपको सेट करना चाहिए true, और Formatघटना, जहां आपको वांछित स्वरूपण तर्क रखने की आवश्यकता होगी। इस प्रकार,

myComboBox.FormattingEnabled = true;
myComboBox.Format += delegate(object sender, ListControlConvertEventArgs e)
    {
        e.Value = GetDescription<HowNice>((HowNice)e.Value);
    }

क्या यह केवल डेटाबाउंड कॉम्बोक्स के साथ काम करता है? मुझे अन्यथा आग लगाने के लिए प्रारूप घटना नहीं मिल सकती है।
SomeBetter

यहाँ एकमात्र समस्या यह है कि आपके पास अपने तर्क के साथ छांटी गई सूची नहीं है
गोरिल्लाएप

यह एक बेहतरीन उपाय है। DataGridComboBoxColumnहालांकि मुझे इसके साथ काम करने की आवश्यकता होगी । इसे हल करने का कोई मौका? मैं करने के लिए उपयोग करने के लिए एक रास्ता खोजने के लिए सक्षम नहीं कर रहा हूँ ComboBoxकी DataGridComboBoxColumn
सोको

46

नहीं करें! Enums आदिम हैं और UI ऑब्जेक्ट नहीं हैं - उन्हें UI को .ToString () में डिज़ाइन करने के दृष्टिकोण से काफी खराब किया जाएगा। आप यहाँ गलत समस्या को हल करने की कोशिश कर रहे हैं: असली मुद्दा यह है कि आप Enum.ToString () कॉम्बो बॉक्स में दिखाना नहीं चाहते हैं!

अब यह वास्तव में एक बहुत ही हल करने योग्य समस्या है! आप अपने कॉम्बो बॉक्स आइटम का प्रतिनिधित्व करने के लिए एक यूआई ऑब्जेक्ट बनाते हैं:

sealed class NicenessComboBoxItem
{
    public string Description { get { return ...; } }
    public HowNice Value { get; private set; }

    public NicenessComboBoxItem(HowNice howNice) { Value = howNice; }
}

और फिर इस वर्ग के उदाहरणों को अपने कॉम्बो बॉक्स के आइटम संग्रह में जोड़ें और इन गुणों को सेट करें:

comboBox.ValueMember = "Value";
comboBox.DisplayMember = "Description";

1
मैं तहे दिल से सहमत हूं। न तो आपको UI को ToString () के परिणाम को उजागर करना चाहिए। और, आपको स्थानीयकरण नहीं मिलता है।
atयविन्द स्कार

मुझे पता है कि यह पुराना है, लेकिन यह कैसे अलग है?
nportelli

2
मैं एक ऐसी ही देखा है समाधान जहां इसके बजाय कस्टम वर्ग का उपयोग कर के, वे एक के लिए enum मान मैप Dictionaryऔर इस्तेमाल किया Keyऔर Valueगुण के रूप में DisplayMemberऔर ValueMember
जेफ बी

42

TypeConverter। मुझे लगता है कि यह वही है जिसकी मुझे तलाश थी। सभी जय साइमन स्वेन्सन !

[TypeConverter(typeof(EnumToStringUsingDescription))]
Enum HowNice {
  [Description("Really Nice")]
  ReallyNice,
  [Description("Kinda Nice")]
  SortOfNice,
  [Description("Not Nice At All")]
  NotNice
}

मुझे अपनी वर्तमान एनुम में परिवर्तन करने की आवश्यकता है, इस लाइन को उनके घोषणा से पहले जोड़ दिया गया है।

[TypeConverter(typeof(EnumToStringUsingDescription))]

एक बार जब मैं ऐसा करता हूं, तो कोई भी एनम DescriptionAttributeअपने खेतों का उपयोग करके प्रदर्शित होगी ।

ओह, और TypeConverterइस तरह परिभाषित किया जाएगा:

public class EnumToStringUsingDescription : TypeConverter
{
    public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
    {
        return (sourceType.Equals(typeof(Enum)));
    }

    public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
    {
        return (destinationType.Equals(typeof(String)));
    }

    public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
    {
        return base.ConvertFrom(context, culture, value);
    }

    public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
    {
        if (!destinationType.Equals(typeof(String)))
        {
            throw new ArgumentException("Can only convert to string.", "destinationType");
        }

        if (!value.GetType().BaseType.Equals(typeof(Enum)))
        {
            throw new ArgumentException("Can only convert an instance of enum.", "value");
        }

        string name = value.ToString();
        object[] attrs = 
            value.GetType().GetField(name).GetCustomAttributes(typeof(DescriptionAttribute), false);
        return (attrs.Length > 0) ? ((DescriptionAttribute)attrs[0]).Description : name;
    }
}

यह मुझे मेरे कॉम्बो बॉक्स मामले में मदद करता है, लेकिन जाहिर है कि वास्तव में इससे आगे नहीं बढ़ता है ToString()। मुझे लगता है मैं इस बीच के लिए तय करेंगे ...


3
आप Enum -> स्ट्रिंग को संभाल रहे हैं, लेकिन यदि आपको पूर्ण कार्यान्वयन की आवश्यकता है, तो आपको Enum> InstanceDescriptor और String -> Enum की भी आवश्यकता होगी। लेकिन मुझे लगता है कि यह प्रदर्शित करना इस समय आपकी आवश्यकताओं के लिए पर्याप्त है। ;)
sisve

1
यह समाधान तभी काम करता है जब आपका विवरण स्थिर हो, दुर्भाग्य से।
लेले जूल

वैसे, TypeConverter का उपयोग स्थिर descritions के लिए बाध्य नहीं है, आवरण विशेषताओं के अलावा अन्य स्रोतों से मूल्यों को आबाद कर सकता है।
दिमित्री ताशकिनोव

3
अब कुछ घंटों के लिए मेरे बाल खींच रहे हैं, लेकिन यह अभी भी सरल कंसोल ऐप में भी काम नहीं करता है। मैंने एनम को सजाया [TypeConverter(typeof(EnumToStringUsingDescription))] public enum MyEnum {[Description("Blah")] One}, करने की कोशिश की Console.WriteLine(MyEnum.One)और यह अभी भी "वन" के रूप में सामने आता है। क्या आपको कुछ विशेष जादू की आवश्यकता है जैसे TypeDescriptor.GetConverter(typeof(MyEnum)).ConvertToString(MyEnum.One)(जो ठीक काम करता है)?
दाव

1
@scraimer मैंने आपके कोड समर्थन झंडे का एक संस्करण पोस्ट किया है। आपके लिए सभी अधिकार सुरक्षित ...
Avi टर्नर

32

अपने गणना उदाहरण का उपयोग करना:

using System.ComponentModel;

Enum HowNice
{
    [Description("Really Nice")]
    ReallyNice,
    [Description("Kinda Nice")]
    SortOfNice,
    [Description("Not Nice At All")]
    NotNice
}

एक एक्सटेंशन बनाएं:

public static class EnumExtensions
{
    public static string Description(this Enum value)
    {
        var enumType = value.GetType();
        var field = enumType.GetField(value.ToString());
        var attributes = field.GetCustomAttributes(typeof(DescriptionAttribute),
                                                   false);
        return attributes.Length == 0
            ? value.ToString()
            : ((DescriptionAttribute)attributes[0]).Description;
    }
}

तो आप निम्न जैसे कुछ का उपयोग कर सकते हैं:

HowNice myEnum = HowNice.ReallyNice;
string myDesc = myEnum.Description();

अधिक जानकारी के लिए देखें: http://www.blackwasp.co.uk/EnumDescription.aspx समाधान के लिए क्रेडिट रिचार्ज कैर को जाता है


मैंने निर्दिष्ट साइट पर विवरणों का पालन किया और इसे निम्नानुसार उपयोग किया, मेरे लिए सीधा 'स्ट्रिंग myDesc = HowNice.ReallyNice.Description ();' myDesc वास्तव में अच्छा उत्पादन करेगा
आनंद

8

आप एक सामान्य संरचना बना सकते हैं जिसका उपयोग आप अपने सभी एनमों के लिए कर सकते हैं जिनके पास विवरण हैं। वर्ग से और उसके साथ निहित रूपांतरणों के साथ, आपके चर अभी भी Toumring विधि को छोड़कर Enum की तरह काम करते हैं:

public struct Described<T> where T : struct {

    private T _value;

    public Described(T value) {
        _value = value;
    }

    public override string ToString() {
        string text = _value.ToString();
        object[] attr =
            typeof(T).GetField(text)
            .GetCustomAttributes(typeof(DescriptionAttribute), false);
        if (attr.Length == 1) {
            text = ((DescriptionAttribute)attr[0]).Description;
        }
        return text;
    }

    public static implicit operator Described<T>(T value) {
        return new Described<T>(value);
    }

    public static implicit operator T(Described<T> value) {
        return value._value;
    }

}

उपयोग उदाहरण:

Described<HowNice> nice = HowNice.ReallyNice;

Console.WriteLine(nice == HowNice.ReallyNice); // writes "True"
Console.WriteLine(nice); // writes "Really Nice"

5

मुझे नहीं लगता कि आप इसे केवल एक अलग प्रकार के लिए बाध्य किए बिना कर सकते हैं - कम से कम, आसानी से नहीं। आम तौर पर, भले ही आप नियंत्रित नहीं कर सकते ToString(), आप TypeConverterकस्टम स्वरूपण करने के लिए एक का उपयोग कर सकते हैं - लेकिन IIRC दSystem.ComponentModel सामान इस बात का सम्मान नहीं करता है।

आप string[]विवरण, या अनिवार्य रूप से एक कुंजी / मूल्य जोड़ी की तरह कुछ करने के लिए बाध्य कर सकते हैं ? (desription / मूल्य) - कुछ इस तरह:

class EnumWrapper<T> where T : struct
{
    private readonly T value;
    public T Value { get { return value; } }
    public EnumWrapper(T value) { this.value = value; }
    public string Description { get { return GetDescription<T>(value); } }
    public override string ToString() { return Description; }

    public static EnumWrapper<T>[] GetValues()
    {
        T[] vals = (T[])Enum.GetValues(typeof(T));
        return Array.ConvertAll(vals, v => new EnumWrapper<T>(v));
    }
}

और फिर बांधते हैं EnumWrapper<HowNice>.GetValues()


1
वर्तमान संदर्भ में 'गेटडेस्क्रिप्शन' नाम मौजूद नहीं है। im .net 4.0 का उपयोग करके
मुहम्मद अदील जाहिद

: जो लिंक पोस्ट से आता है - @MuhammadAdeelZahid प्रश्न के शुरू में करीब से देखो stackoverflow.com/questions/479410/enum-tostring
मार्क Gravell

क्षमा करें, लेकिन प्रश्न से कोई सुराग नहीं मिल सकता है। आपका तरीका संकलन नहीं है और त्रुटि दिखाता है।
मुहम्मद अदील जाहिद

हाय मार्क, मैंने आपके विचार की कोशिश की। यह काम कर रहा है, लेकिन खुद के बजाय, theComboBox.SelectItemइसका प्रकार है। मुझे लगता है कि स्क्रेमर चाहता है । EnumWrapper<T>TReading (HowNice)myComboBox.selectedItem will return the selected value as the enum value.
पीटर ली

5

ऐसा करने का सबसे अच्छा तरीका एक वर्ग बनाना है।

class EnumWithToString {
    private string description;
    internal EnumWithToString(string desc){
        description = desc;
    }
    public override string ToString(){
        return description;
    }
}

class HowNice : EnumWithToString {

    private HowNice(string desc) : base(desc){}

    public static readonly HowNice ReallyNice = new HowNice("Really Nice");
    public static readonly HowNice KindaNice = new HowNice("Kinda Nice");
    public static readonly HowNice NotVeryNice = new HowNice("Really Mean!");
}

मेरा मानना ​​है कि यह करने का सबसे अच्छा तरीका है।

जब कॉम्बोबॉक्स में भरकर सुंदर टोस्ट्रिंग दिखाई जाएगी, और यह तथ्य कि कोई भी आपकी कक्षा के किसी भी अधिक उदाहरण को अनिवार्य रूप से नहीं बना सकता है, तो यह एक एनम बनाता है।

ps कुछ मामूली वाक्यविन्यास सुधार करने की आवश्यकता हो सकती है, मैं C # के साथ सुपर अच्छा नहीं हूं। (जावा पुरुष)


1
यह कॉम्बोक्स समस्या के साथ कैसे मदद करता है?
peSHIr

खैर, अब, जब नई वस्तु को एक कॉम्बोक्स में डाल दिया जाता है, तो इसके टोस्ट्रिंग को ठीक से प्रदर्शित किया जाएगा, और वर्ग अभी भी एक एनम की तरह काम करता है।
jjnguy

1
मेरा भी जवाब होता।
मिकको रेंटेनन

3
और यह देखकर कि मूल पोस्टर कैसे स्पष्ट रूप से एक वर्ग नहीं चाहता था। मुझे नहीं लगता कि एक वर्ग इतना अधिक काम करता है। आप वर्णन को सार कर सकते हैं और ToString सभी एनमों के लिए एक मूल वर्ग को ओवरराइड कर सकते हैं। इसके बाद आपको एक निर्माता private HowNice(String desc) : base(desc) { }और स्थिर क्षेत्रों की आवश्यकता है।
मिको रानतेंन

मैं इससे बचने की उम्मीद कर रहा था, क्योंकि इसका मतलब है कि मेरे द्वारा किए जाने वाले प्रत्येक ज्ञान की अपनी कक्षा की आवश्यकता होगी। ओह।
शालोम क्रेमर

3

यह देखते हुए कि आप प्रत्येक एनम के लिए एक क्लास नहीं बनायेंगे, मैं आपको एनम वैल्यू / डिसप्ले टेक्स्ट का एक शब्दकोष बनाने और उसके बजाय बाध्यकारी बनाने की सलाह दूंगा।

ध्यान दें कि यह मूल पोस्ट में GetDescription विधि विधियों पर निर्भरता है।

public static IDictionary<T, string> GetDescriptions<T>()
    where T : struct
{
    IDictionary<T, string> values = new Dictionary<T, string>();

    Type type = enumerationValue.GetType();
    if (!type.IsEnum)
    {
        throw new ArgumentException("T must be of Enum type", "enumerationValue");
    }

    //Tries to find a DescriptionAttribute for a potential friendly name
    //for the enum
    foreach (T value in Enum.GetValues(typeof(T)))
    {
        string text = value.GetDescription();

        values.Add(value, text);
    }

    return values;
}

अछा सुझाव। लेकिन मैं इसे कॉम्बोक्स के साथ कैसे उपयोग करूंगा? एक बार जब उपयोगकर्ता कॉम्बोक्स से एक आइटम का चयन करता है, तो मुझे कैसे पता चलेगा कि उसने कौन सी वस्तुओं का चयन किया है? विवरण स्ट्रिंग द्वारा खोजें? यह मेरी त्वचा को खुजली करता है ... (विवरण स्ट्रिंग्स के बीच एक स्ट्रिंग "टक्कर" हो सकती है)
शालोम क्रेमर

चयनित आइटम की कुंजी वास्तविक एनम मान होगी। इसके अलावा, वर्णन के तार नहीं टकराए - उपयोगकर्ता अंतर कैसे बताएगा?
रिचर्ड साज़ेले

<cont> यदि आपके पास वर्णन स्ट्रिंग्स हैं जो टकराते हैं, तो आपको एनुम के मूल्यों को सीधे किसी भी तरह से एक कॉम्बोक्स से बांधना नहीं चाहिए।
रिचर्ड शेजले

हम्म् ... अच्छा, क्या आप मुझे उदाहरण कोड दे सकते हैं कि आप कॉम्बोक्स में आइटम कैसे जोड़ेंगे? मैं सोच सकता हूं कि "foreach (वर्णनों में स्ट्रिंग s हैं। निर्णय) {this.combobox.Items.Add (s);}"
Shalom Craimer

1
ComboBox.DataSource = शब्दकोश;
रिचर्ड शेजले

3

सी # में enums के ToString () को ओवरराइड करना संभव नहीं है। हालाँकि, आप एक्सटेंशन विधियों का उपयोग कर सकते हैं;

public static string ToString(this HowNice self, int neverUsed)
{
    switch (self)
    {
        case HowNice.ReallyNice:
            return "Rilly, rilly nice";
            break;
    ...

बेशक आपको विधि के लिए एक स्पष्ट कॉल करना होगा, अर्थात;

HowNice.ReallyNice.ToString(0)

यह एक अच्छा समाधान नहीं है, एक स्विच स्टेटमेंट और सभी के साथ - लेकिन यह काम करना चाहिए और उम्मीद है कि कई पुनर्लेखनों को सफेद कर सकता है ...


ध्यान रखें कि जो नियंत्रण आपके एनम को बांधता है वह इस विस्तार पद्धति को नहीं कहेगा, यह डिफ़ॉल्ट कार्यान्वयन कहलाएगा।
रिचर्ड शेजय

सही। तो यह एक व्यवहार्य विकल्प है यदि आपको कहीं पर एक विवरण की आवश्यकता है, तो यह सामने वाले कॉम्बोक्स समस्या के साथ मदद नहीं करता है।
peSHIr

एक बड़ी समस्या यह है कि यह कभी नहीं बुलाया जाएगा (एक विस्तार विधि के रूप में) - उदाहरण के तरीके जो पहले से मौजूद हैं हमेशा प्राथमिकता लेते हैं।
मार्क Gravell

बेशक मार्क सही है (हमेशा की तरह?)। मेरा .NET अनुभव न्यूनतम है, लेकिन विधि को एक डमी पैरामीटर प्रदान करते हुए ट्रिक करना चाहिए। संपादित उत्तर।
ब्योर्न

2

@Scraimer उत्तर पर अनुसरण करने के बाद, यहाँ enum-to-string प्रकार कनवर्टर का एक संस्करण है, जो झंडे का समर्थन करता है:

    /// <summary>
/// A drop-in converter that returns the strings from 
/// <see cref="System.ComponentModel.DescriptionAttribute"/>
/// of items in an enumaration when they are converted to a string,
/// like in ToString().
/// </summary>
public class EnumToStringUsingDescription : TypeConverter
{
    public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
    {
        return (sourceType.Equals(typeof(Enum)));
    }

    public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
    {
        return (destinationType.Equals(typeof(String)));
    }

    public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
    {
        return base.ConvertFrom(context, culture, value);
    }

    public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
    {
        if (destinationType.Equals(typeof(String)))
        {
            string name = value.ToString();
            Type effectiveType = value.GetType();          

            if (name != null)
            {
                FieldInfo fi = effectiveType.GetField(name);
                if (fi != null)
                {
                    object[] attrs =
                    fi.GetCustomAttributes(typeof(DescriptionAttribute), false);
                    return (attrs.Length > 0) ? ((DescriptionAttribute)attrs[0]).Description : name;
                }

            }
        }

        return base.ConvertTo(context, culture, value, destinationType);
    }

    /// <summary>
    /// Coverts an Enums to string by it's description. falls back to ToString.
    /// </summary>
    /// <param name="value">The value.</param>
    /// <returns></returns>
    public string EnumToString(Enum value)
    {
        //getting the actual values
        List<Enum> values = EnumToStringUsingDescription.GetFlaggedValues(value);
        //values.ToString();
        //Will hold results for each value
        List<string> results = new List<string>();
        //getting the representing strings
        foreach (Enum currValue in values)
        {
            string currresult = this.ConvertTo(null, null, currValue, typeof(String)).ToString();;
            results.Add(currresult);
        }

        return String.Join("\n",results);

    }

    /// <summary>
    /// All of the values of enumeration that are represented by specified value.
    /// If it is not a flag, the value will be the only value retured
    /// </summary>
    /// <param name="value">The value.</param>
    /// <returns></returns>
    private static List<Enum> GetFlaggedValues(Enum value)
    {
        //checking if this string is a flaged Enum
        Type enumType = value.GetType();
        object[] attributes = enumType.GetCustomAttributes(true);
        bool hasFlags = false;
        foreach (object currAttibute in attributes)
        {
            if (enumType.GetCustomAttributes(true)[0] is System.FlagsAttribute)
            {
                hasFlags = true;
                break;
            }
        }
        //If it is a flag, add all fllaged values
        List<Enum> values = new List<Enum>();
        if (hasFlags)
        {
            Array allValues = Enum.GetValues(enumType);
            foreach (Enum currValue in allValues)
            {
                if (value.HasFlag(currValue))
                {
                    values.Add(currValue);
                }
            }



        }
        else//if not just add current value
        {
            values.Add(value);
        }
        return values;
    }

}

और इसका उपयोग करने के लिए एक विस्तार विधि:

    /// <summary>
    /// Converts an Enum to string by it's description. falls back to ToString
    /// </summary>
    /// <param name="enumVal">The enum val.</param>
    /// <returns></returns>
    public static string ToStringByDescription(this Enum enumVal)
    {
        EnumToStringUsingDescription inter = new EnumToStringUsingDescription();
        string str = inter.EnumToString(enumVal);
        return str;
    }

1

मैं किसी भी प्रकार के उपयोग के लिए एक सामान्य वर्ग लिखूंगा। मैंने अतीत में ऐसा कुछ इस्तेमाल किया है:

public class ComboBoxItem<T>
{
    /// The text to display.
    private string text = "";
    /// The associated tag.
    private T tag = default(T);

    public string Text
    {
        get
        {
            return text;
        }
    }

    public T Tag
    {
        get
        {
            return tag;
        }
    }

    public override string ToString()
    {
        return text;
    }

    // Add various constructors here to fit your needs
}

इस के शीर्ष पर, आप एक स्थिर "फ़ैक्टरी विधि" जोड़ सकते हैं, जिसमें कॉम्बोबॉक्स आइटमों की एक सूची तैयार की जाती है, जो एक एनम प्रकार दिया जाता है (बहुत ही समान गेटडेस्केल्स विधि जो आपके पास है)। यह आपको प्रत्येक एनुम प्रकार के अनुसार एक इकाई को लागू करने से बचाएगा, और "गेटडेसेप्स" सहायक विधि के लिए एक अच्छा / तार्किक स्थान प्रदान करेगा (व्यक्तिगत रूप से मैं इसे FromEnum (T obj) कहूंगा ...)


1

एक संग्रह बनाएं जिसमें आपकी आवश्यकता हो (जैसे कि साधारण वस्तुएं जिसमें एक Valueसंपत्ति होती है, जिसमें HowNiceएनम मूल्य और एक Descriptionसंपत्ति होती हैGetDescription<HowNice>(Value) और DataBind कि संग्रह करने के लिए कॉम्बो।

इस तरह बिट:

Combo.DataSource = new EnumeratedValueCollection<HowNice>();
Combo.ValueMember = "Value";
Combo.DisplayMember = "Description";

जब आपके पास इस तरह एक संग्रह वर्ग होता है:

using System;
using System.Linq;
using System.Collections.Generic;
using System.Collections.ObjectModel;

namespace Whatever.Tickles.Your.Fancy
{
    public class EnumeratedValueCollection<T> : ReadOnlyCollection<EnumeratedValue<T>>
    {
        public EnumeratedValueCollection()
            : base(ListConstructor()) { }
        public EnumeratedValueCollection(Func<T, bool> selection)
            : base(ListConstructor(selection)) { }
        public EnumeratedValueCollection(Func<T, string> format)
            : base(ListConstructor(format)) { }
        public EnumeratedValueCollection(Func<T, bool> selection, Func<T, string> format)
            : base(ListConstructor(selection, format)) { }
        internal EnumeratedValueCollection(IList<EnumeratedValue<T>> data)
            : base(data) { }

        internal static List<EnumeratedValue<T>> ListConstructor()
        {
            return ListConstructor(null, null);
        }

        internal static List<EnumeratedValue<T>> ListConstructor(Func<T, string> format)
        {
            return ListConstructor(null, format);
        }

        internal static List<EnumeratedValue<T>> ListConstructor(Func<T, bool> selection)
        {
            return ListConstructor(selection, null);
        }

        internal static List<EnumeratedValue<T>> ListConstructor(Func<T, bool> selection, Func<T, string> format)
        {
            if (null == selection) selection = (x => true);
            if (null == format) format = (x => GetDescription<T>(x));
            var result = new List<EnumeratedValue<T>>();
            foreach (T value in System.Enum.GetValues(typeof(T)))
            {
                if (selection(value))
                {
                    string description = format(value);
                    result.Add(new EnumeratedValue<T>(value, description));
                }
            }
            return result;
        }

        public bool Contains(T value)
        {
            return (Items.FirstOrDefault(item => item.Value.Equals(value)) != null);
        }

        public EnumeratedValue<T> this[T value]
        {
            get
            {
                return Items.First(item => item.Value.Equals(value));
            }
        }

        public string Describe(T value)
        {
            return this[value].Description;
        }
    }

    [System.Diagnostics.DebuggerDisplay("{Value} ({Description})")]
    public class EnumeratedValue<T>
    {
        private T value;
        private string description;
        internal EnumeratedValue(T value, string description) {
            this.value = value;
            this.description = description;
        }
        public T Value { get { return this.value; } }
        public string Description { get { return this.description; } }
    }

}

जैसा कि आप देख सकते हैं, लैम्बडा के साथ यह संग्रह आसानी से अनुकूलन योग्य है, अपने एन्यूमरेटर और / या आपके द्वारा उल्लिखित फ़ंक्शन stringका उपयोग करने के बजाय कस्टम स्वरूपण को लागू करने के लिए GetDescription<T>(x)


बहुत बढ़िया, लेकिन मैं ऐसी चीज़ की तलाश कर रहा हूँ जिसके लिए कोड में भी कम काम करना पड़े।
शालोम क्रेमर

यहां तक ​​कि अगर आप अपने सभी enumerators के लिए इस तरह के सामान के लिए एक ही सामान्य संग्रह का उपयोग कर सकते हैं? मैं निश्चित रूप से प्रत्येक एनम के लिए इस तरह के संग्रह को कस्टम लिखने का सुझाव नहीं दे रहा था।
peSHIr

1

आप Enum.ToString को लक्षित करने के लिए PostSharp का उपयोग कर सकते हैं और अपनी इच्छानुसार एडिशन कोड जोड़ सकते हैं। इसके लिए किसी कोड परिवर्तन की आवश्यकता नहीं है।


1

आपको एक एनम को ReadonlyCollection में बदलना है और संग्रह को कॉम्बोक्स (या उस मामले के लिए किसी भी कुंजी-मूल्य जोड़ी सक्षम नियंत्रण) से बांधना है

सबसे पहले आपको सूची के आइटम को शामिल करने के लिए एक वर्ग की आवश्यकता है। चूँकि आप सभी की आवश्यकता इंट / स्ट्रिंग जोड़ी है जो मैं एक इंटरफ़ेस और बेस क्लास कॉम्बो का उपयोग करने का सुझाव देता हूं ताकि आप किसी भी ऑब्जेक्ट में कार्यक्षमता को लागू कर सकें जो आप चाहते हैं:

public interface IValueDescritionItem
{
    int Value { get; set;}
    string Description { get; set;}
}

public class MyItem : IValueDescritionItem
{
    HowNice _howNice;
    string _description;

    public MyItem()
    {

    }

    public MyItem(HowNice howNice, string howNice_descr)
    {
        _howNice = howNice;
        _description = howNice_descr;
    }

    public HowNice Niceness { get { return _howNice; } }
    public String NicenessDescription { get { return _description; } }


    #region IValueDescritionItem Members

    int IValueDescritionItem.Value
    {
        get { return (int)_howNice; }
        set { _howNice = (HowNice)value; }
    }

    string IValueDescritionItem.Description
    {
        get { return _description; }
        set { _description = value; }
    }

    #endregion
}

यहाँ इंटरफ़ेस और एक नमूना वर्ग है जो इसे लागू करता है। यह इंगित करता है कि वर्ग की कुंजी दृढ़ता से Enum के लिए टाइप की गई है, और यह है कि IValueDescritionItem भविष्यवाणियां स्पष्ट रूप से कार्यान्वित की जाती हैं (इसलिए वर्ग में जो भी गुण हैं और आप उन लोगों को चुन सकते हैं जो कार्यान्वयन को लागू कर सकते हैं। कुंजी / मूल्य जोड़ी।

अब EnumToReadOnlyCollection वर्ग:

public class EnumToReadOnlyCollection<T,TEnum> : ReadOnlyCollection<T> where T: IValueDescritionItem,new() where TEnum : struct
{
    Type _type;

    public EnumToReadOnlyCollection() : base(new List<T>())
    {
        _type = typeof(TEnum);
        if (_type.IsEnum)
        {
            FieldInfo[] fields = _type.GetFields();

            foreach (FieldInfo enum_item in fields)
            {
                if (!enum_item.IsSpecialName)
                {
                    T item = new T();
                    item.Value = (int)enum_item.GetValue(null);
                    item.Description = ((ItemDescription)enum_item.GetCustomAttributes(false)[0]).Description;
                    //above line should be replaced with proper code that gets the description attribute
                    Items.Add(item);
                }
            }
        }
        else
            throw new Exception("Only enum types are supported.");
    }

    public T this[TEnum key]
    {
        get 
        {
            return Items[Convert.ToInt32(key)];
        }
    }

}

तो आप अपने कोड में सभी की जरूरत है:

private EnumToReadOnlyCollection<MyItem, HowNice> enumcol;
enumcol = new EnumToReadOnlyCollection<MyItem, HowNice>();
comboBox1.ValueMember = "Niceness";
comboBox1.DisplayMember = "NicenessDescription";
comboBox1.DataSource = enumcol;

याद रखें कि आपका संग्रह MyItem के साथ टाइप किया गया है, इसलिए कॉम्बोबॉक्स मान को एक उचित मान वापस करना चाहिए यदि आप उपयुक्त प्रॉपर को बाँधते हैं।

मैंने T को इस [Enum t] संपत्ति को एक साधारण कॉम्बो की तुलना में अधिक उपयोगी बनाने के लिए जोड़ा, उदाहरण के लिए textBox1.Text = enumcol [HowNice.ReallyNice] ।NicenessDescription;

आप निश्चित रूप से MyItem को कुंजी / मान वर्ग में बदलने के लिए चुन सकते हैं, जिसका उपयोग केवल इस प्यूमरोज के लिए किया जाता है, जो पूरी तरह से EnumToReadlyCollection के प्रकार तर्क में MyItem को छोड़ देता है, लेकिन तब आप कुंजी के लिए इंट के लिए जाने के लिए मजबूर हो जाएंगे (जिसका अर्थ है combobox1.electedValue मिलना int वापस आएगा और एनम प्रकार नहीं)। यदि आप MyItem और इतने पर और आगे की जगह के लिए KeyValueItem क्लास बनाते हैं, तो आप इसके आसपास काम करते हैं ...


1

इस पुराने सूत्र को पाने के लिए क्षमा करें।

मैं एनम को स्थानीय बनाने के लिए निम्न तरीके से जाऊंगा, क्योंकि यह उपयोगकर्ता के लिए सार्थक और स्थानीयकृत मान प्रदर्शित कर सकता है, न कि केवल वर्णन, इस उदाहरण में एक ड्रॉपडाउन टेक्स्ट फ़ील्ड के माध्यम से।

सबसे पहले, मैं एक वैश्विक विधि फ़ाइल से स्थानीयकृत तार प्राप्त करने के लिए OwToStringByCulture नामक एक सरल विधि बनाता हूं, इस उदाहरण में यह App_GlobalResources फ़ोल्डर में BiBongNet.resx है। इस संसाधन फ़ाइल के अंदर, सुनिश्चित करें कि आपके पास एनम (रियलीनेस, सॉर्टऑनइस, नोटनिस) के मान के समान ही हैं। इस पद्धति में, मैं पैरामीटर में गुजरता हूं: resourceClassName जो आमतौर पर संसाधन फ़ाइल का नाम है।

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

फिर DropDownList1 नामक ड्रॉपडाउनलिस्ट के साथ पृष्ठ में, मैंने ड्रॉपडाउनलिस्ट में एनम को भरने के लिए कोड की केवल एक सरल रेखा के बाद Page_Load में सेट किया।

 BiBongNet.OwFillDataWithEnum<HowNice>(DropDownList1, "BiBongNet");

बस। मुझे लगता है कि इन जैसे कुछ सरल तरीकों के साथ, आप किसी भी एनम के साथ किसी भी सूची नियंत्रण को भर सकते हैं, न केवल वर्णनात्मक मूल्यों के साथ, बल्कि प्रदर्शित करने के लिए स्थानीयकृत पाठ भी। आप इन सभी तरीकों को बेहतर उपयोग के लिए विस्तार विधियों के रूप में बना सकते हैं।

उममीद है कि इससे मदद मिलेगी। साझा करने के लिए साझा करें!

ये तरीके हैं:

public class BiBongNet
{

        enum HowNice
        {
            ReallyNice,
            SortOfNice,
            NotNice
        }

        /// <summary>
        /// This method is for filling a listcontrol,
        /// such as dropdownlist, listbox... 
        /// with an enum as the datasource.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="ctrl"></param>
        /// <param name="resourceClassName"></param>
        public static void OwFillDataWithEnum<T>(ListControl ctrl, string resourceClassName)
        {
            var owType = typeof(T);
            var values = Enum.GetValues(owType);
            for (var i = 0; i < values.Length; i++)
            {
                //Localize this for displaying listcontrol's text field.
                var text = OwToStringByCulture(resourceClassName, Enum.Parse(owType, values.GetValue(i).ToString()).ToString());
                //This is for listcontrol's value field
                var key = (Enum.Parse(owType, values.GetValue(i).ToString()));
                //add values of enum to listcontrol.
                ctrl.Items.Add(new ListItem(text, key.ToString()));
            }
        }

        /// <summary>
        /// Get localized strings.
        /// </summary>
        /// <param name="resourceClassName"></param>
        /// <param name="resourceKey"></param>
        /// <returns></returns>
        public static string OwToStringByCulture(string resourceClassName, string resourceKey)
        {
                return (string)HttpContext.GetGlobalResourceObject(resourceClassName, resourceKey);
        }
}

1
Enum HowNice {
  [Description("Really Nice")]
  ReallyNice,
  [Description("Kinda Nice")]
  SortOfNice,
  [Description("Not Nice At All")]
  NotNice
}

इसे हल करने के लिए आपको एक्सटेंशन विधि और स्ट्रिंग्स का एक सरणी का उपयोग करना चाहिए:

Enum HowNice {
  ReallyNice  = 0,
  SortOfNice  = 1,
  NotNice     = 2
}

internal static class HowNiceIsThis
{
 const String[] strings = { "Really Nice", "Kinda Nice", "Not Nice At All" }

 public static String DecodeToString(this HowNice howNice)
 {
   return strings[(int)howNice];
 }
}

सरल कोड और तेजी से डिकोडिंग।


स्ट्रिंग्स चर स्थिर होना चाहिए और ऐसा घोषित किया जाना चाहिए: स्टेटिक स्ट्रिंग [] स्ट्रिंग्स = नया [] {...}
सेरेजियो

इसके साथ एकमात्र समस्या यह है कि आपको प्रत्येक गणना के लिए एक फ़ंक्शन की आवश्यकता होगी, और विवरण स्वयं गणना के अलावा होगा ...
एवी टर्नर

1

मैंने इस दृष्टिकोण की कोशिश की और यह मेरे लिए काम कर गया।

मैंने enums के लिए एक आवरण वर्ग बनाया और निहित ऑपरेटर को अधिभारित किया, ताकि मैं इसे enum चर को असाइन कर सकूं (मेरे मामले में मुझे किसी वस्तु को किसी ComboBoxमूल्य पर बाँधना था )।

आप एनम मूल्यों को जिस तरह से आप चाहते हैं, उसे प्रारूपित करने के लिए प्रतिबिंब का उपयोग कर सकते हैं, मेरे मामले में मैं DisplayAttributeएनम मानों (यदि मौजूद है) से बाहर निकालता हूं ।

उम्मीद है की यह मदद करेगा।

public sealed class EnumItem<T>
{
    T value;

    public override string ToString()
    {
        return Display;
    }

    public string Display { get; private set; }
    public T Value { get; set; }

    public EnumItem(T val)
    {
        value = val;
        Type en = val.GetType();
        MemberInfo res = en.GetMember(val.ToString())?.FirstOrDefault();
        DisplayAttribute display = res.GetCustomAttribute<DisplayAttribute>();
        Display = display != null ? String.Format(display.Name, val) : val.ToString();
    }

    public static implicit operator T(EnumItem<T> val)
    {
        return val.Value;
    }

    public static implicit operator EnumItem<T>(T val)
    {
        return new EnumItem<T>(val);
    }
}

संपादित करें:

शायद ज़रुरत पड़े, मैं प्राप्त करने के लिए निम्न फ़ंक्शन का उपयोग करें enumकि मैं के लिए उपयोग मूल्यों DataSourceकीComboBox

public static class Utils
{
    public static IEnumerable<EnumItem<T>> GetEnumValues<T>()
    {
        List<EnumItem<T>> result = new List<EnumItem<T>>();
        foreach (T item in Enum.GetValues(typeof(T)))
        {
            result.Add(item);
        }
        return result;
    }
}

0

जब आपके पास GetDescriptionविधि हो जाए (इसे वैश्विक स्थैतिक होना आवश्यक है), आप इसे विस्तार विधि के माध्यम से उपयोग कर सकते हैं:

public static string ToString(this HowNice self)
{
    return GetDescription<HowNice>(self);
}

0
Enum HowNice {   
[StringValue("Really Nice")]   
ReallyNice,   
[StringValue("Kinda Nice")]   
SortOfNice,   
[StringValue("Not Nice At All")]   
NotNice 
}

Status = ReallyNice.GetDescription()

3
Stackoverflow में आपका स्वागत है! हमेशा पोस्ट सटीकता को बेहतर बनाने के लिए एक नमूना कोड के लिए संक्षिप्त विवरण प्रदान करना बेहतर होता है :)
Picrofo सॉफ्टवेयर

-1

आप एनम को परिभाषित कर सकते हैं

Enum HowNice {   
[StringValue("Really Nice")]   
ReallyNice,   
[StringValue("Kinda Nice")]   
SortOfNice,   
[StringValue("Not Nice At All")]   
NotNice 
} 

और फिर उपयोग करें HowNice.GetStringValue()


2
यह संकलन नहीं है (मेरे पास .NET 3.5 है)। IsStringValue´ कहाँ घोषित किया गया है?
विस्मय

1
@ सीज़राइमर का उत्तर एक ही है, सिवाय इसके कि वह फ्रेमवर्क से बाहर एक विशेषता का उपयोग कर रहा है, जबकि आप किसी प्रकार के स्व परिभाषित विशेषता का उपयोग करते हैं।
ओलिवर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.