सी # में तार के साथ संलग्न करना


361

मुझे पता है कि निम्नलिखित संभव नहीं है क्योंकि एन्यूमरेशन का प्रकार एक इंट होना है

enum GroupTypes
{
    TheGroup = "OEM",
    TheOtherGroup = "CMB"
}

अपने डेटाबेस से मुझे इनफोर्समेंट कोड ( OEMऔर CMBएस) के साथ एक फील्ड मिलता है । मैं इस क्षेत्र को एक enumया कुछ और समझने योग्य बनाना चाहता हूं । क्योंकि यदि लक्ष्य पठनीयता है, तो समाधान को हल किया जाना चाहिए।

मेरे पास अन्य विकल्प क्या हैं?



12
मुझे यकीन नहीं है कि अधिकांश उत्तर "कास्ट स्ट्रिंग" का उपयोग क्यों नहीं करते हैं और इसके बजाय वे कस्टम कक्षाएं बना रहे हैं।
CTS_AE

1
आप तार का उपयोग करने में सक्षम नहीं हो सकते हैं, लेकिन आप बस ठीक उपयोग कर सकते हैं। यह एक विकल्प है यदि आप एकल-अक्षर मान का उपयोग कर सकते हैं।
टी। सर

1
वास्तव में उलझन में है कि CTS_AE द्वारा प्रस्तावित समाधान शीर्ष तीन उत्तरों में भी क्यों नहीं है।
सिनजई

@ सिनजाई संबंधित मूल्यों का स्पष्ट समूहन एक अगोचर प्रदर्शन हानि के दंड से आगे निकल जाएगा, विशेष रूप से एक एपीआई या पुन: प्रयोज्य घटक में।
व्यक्ति

जवाबों:


402

मैं तरीकों के बजाय एक वर्ग में गुणों का उपयोग करना पसंद करता हूं , क्योंकि वे अधिक एनुम-जैसे दिखते हैं।

यहाँ एक लकड़हारा के लिए एक उदाहरण है:

public class LogCategory
{
    private LogCategory(string value) { Value = value; }

    public string Value { get; set; }

    public static LogCategory Trace   { get { return new LogCategory("Trace"); } }
    public static LogCategory Debug   { get { return new LogCategory("Debug"); } }
    public static LogCategory Info    { get { return new LogCategory("Info"); } }
    public static LogCategory Warning { get { return new LogCategory("Warning"); } }
    public static LogCategory Error   { get { return new LogCategory("Error"); } }
}

एक पैरामीटर के रूप में टाइप-सेफ स्ट्रिंग वैल्यू में पास :

public static void Write(string message, LogCategory logCategory)
{
    var log = new LogEntry { Message = message };
    Logger.Write(log, logCategory.Value);
}

उपयोग:

Logger.Write("This is almost like an enum.", LogCategory.Info);

4
केवल नीचे की ओर मैं यह कह सकता हूं कि यह थोड़ा धीमा होगा, लेकिन यह ज्यादातर मामलों में उपेक्षित होगा। और यह संपादक में सटीक व्यवहार नहीं होगा। ईजी: इस पर स्विच करना प्रत्येक संभावना के लिए एक मामले में स्वचालित रूप से नहीं भरेगा। उन मामूली बिंदुओं के अलावा, मुझे लगता है कि यह संभवतः एक सरल समाधान है।
बोरिस ने 7

3
और एक स्विच के रूप में डिक्शनरी <LogCategory, Action / Func> का उपयोग करना आसान है। :)
अर्निस लैप्स 16

4
@ArnisL। यह कुंजी के रूप में काम करने के लिए पर्याप्त नहीं है, आपको इक्वाल्स () और गेटहैशकोड () को ओवरराइड करने की आवश्यकता है, और आप मूल्य संपत्ति सेटर को निजी बनाना चाहते हैं। फिर भी, यह एक पहेली नहीं है।
डेव वान डेन आईंडी

21
अपने स्वयं के उपयोग के लिए, मैंने इस अवधारणा पर विस्तार किया, ToStringलौटने की विधि को ओवरराइड किया Value। और फिर एक तार से निहित कलाकारों को प्रदान किया। public static implicit operator String(LogCategory category) { return Value; }
ज़ेरेफ़ेथ

6
स्विच मामलों में इसका उपयोग करने के बारे में क्या?
डेविड

176

आप एक्सटेंशन मॉडल का उपयोग भी कर सकते हैं:

public enum MyEnum
{
    [Description("String 1")]
    V1= 1,
    [Description("String 2")]
    V2= 2
} 

आपका एक्सटेंशन क्लास

public static class MyEnumExtensions
{
    public static string ToDescriptionString(this MyEnum val)
    {
        DescriptionAttribute[] attributes = (DescriptionAttribute[])val
           .GetType()
           .GetField(val.ToString())
           .GetCustomAttributes(typeof(DescriptionAttribute), false);
        return attributes.Length > 0 ? attributes[0].Description : string.Empty;
    }
} 

उपयोग:

MyEnum myLocal = MyEnum.V1;
print(myLocal.ToDescriptionString());

3
अन्य विस्तार के लिए और स्ट्रिंग से लेकर एनम तक वर्णन के लिए भी stackoverflow.com/questions/4367723/… देखें ।
डेव

14
मैं यह सोचने में मदद नहीं कर सकता कि जब आप चाहते हैं कि हर बार प्रदर्शन के दृष्टिकोण से पाठ को प्रदर्शित करने में दर्द हो रहा है!
Liath

4
@ लिट - द `.ट्रोस्ट्रिंग ()` पहले से ही प्रतिबिंब का उपयोग करता है, इसलिए आप वास्तव में इस दृष्टिकोण के साथ कुछ भी नहीं खो रहे हैं, और पठनीयता प्राप्त कर रहे हैं
जेम्स किंग

1
क्या आप एक्सटेंशन को सामान्य बना सकते हैं ताकि यह सभी Enums पर अपने आप लागू हो जाए?
इरोज़े

3
जेनेरिक बनाने के लिए, public static string ToDescriptionString(this Enum ...स्पष्ट रूप से टाइप किए बिना अर्थात का उपयोग करें MyEnum
लीबंबल

100

स्थिरांक के साथ स्थैतिक वर्ग का उपयोग कैसे करें?

static class GroupTypes
{
  public const string TheGroup = "OEM";
  public const string TheOtherGroup = "CMB";
}

void DoSomething(string groupType)
{
  if(groupType == GroupTypes.TheGroup)
  {
    // Be nice
  }  
  else if (groupType == GroupTypes.TheOtherGroup)
  {
    // Continue to be nice
  }
  else
  {
    // unexpected, throw exception?
  }
}

9
माना। मुझे अधिक जटिल समाधानों के पीछे के उद्देश्य को देखने में परेशानी हो रही है, सिवाय इसके कि परिणामस्वरूप "एनम" पर स्विच करने में सक्षम होना चाहिए।
फर्जीवाड़ा

@fakeleft आप सामान्य प्रकार (टेम्पलेट) के साथ एक स्थिर वर्ग प्रकार का उपयोग नहीं कर सकते हैं, और शायद अन्य सीमाएं, मुझे लगता है यही कारण है कि लोग "अधिक जटिल" समाधान पसंद करते हैं।
eselk

2
हालांकि इसके लिए काम करने के लिए स्थिरांक को आंतरिक या सार्वजनिक होना चाहिए
arviman

46
स्टेटिक प्रकारों को मापदंडों के रूप में उपयोग नहीं किया जा सकता है।
पेड्रो मोरिरा

2
जैसा कि @PedroMoreira बताते हैं, आप GroupTypesएक तर्क प्रकार के रूप में पारित नहीं कर सकते क्योंकि यह एक स्थिर वर्ग है। यही समस्या है कि यहां तक ​​कि मियां का उत्तर भी हल करता है। इस मामले में आपको इसके बजाय void DoSomething(string groupType), जिसका अर्थ है कि कोई भी स्ट्रिंग मानgroupType हो सकता है , यहां तक ​​कि मान भी जो आप उम्मीद नहीं कर रहे हैं, जिसका अर्थ है कि आपको उन अवैध प्रकारों के लिए तैयार रहना होगा और यह तय करना होगा कि उन्हें कैसे संभालना है (जैसे एक अपवाद फेंककर)। यहां तक ​​कि मियां का उत्तर भी हल करता है कि वर्ग द्वारा परिभाषित विकल्पों में मान्य इनपुट की संख्या को सीमित करके । LogCategory
चरण

30

आप गणना में आइटम के लिए विशेषताएँ जोड़ सकते हैं और फिर विशेषताओं से मान प्राप्त करने के लिए प्रतिबिंब का उपयोग कर सकते हैं।

आपको विशेषताओं को लागू करने के लिए "फ़ील्ड" निर्दिष्ट का उपयोग करना होगा, जैसे:

enum GroupTypes
{
    [field:Description("OEM")]
    TheGroup,

    [field:Description("CMB")]
    TheOtherGroup
}

फिर आप enum के प्रकार के स्थिर क्षेत्रों (इस मामले में GroupTypes) पर प्रतिबिंबित करेंगे और DescriptionAttributeउस मूल्य के लिए प्राप्त करें जिसे आप प्रतिबिंब का उपयोग करने के लिए देख रहे थे:

public static DescriptionAttribute GetEnumDescriptionAttribute<T>(
    this T value) where T : struct
{
    // The type of the enum, it will be reused.
    Type type = typeof(T);

    // If T is not an enum, get out.
    if (!type.IsEnum) 
        throw new InvalidOperationException(
            "The type parameter T must be an enum type.");

    // If the value isn't defined throw an exception.
    if (!Enum.IsDefined(type, value))
        throw new InvalidEnumArgumentException(
            "value", Convert.ToInt32(value), type);

    // Get the static field for the value.
    FieldInfo fi = type.GetField(value.ToString(), 
        BindingFlags.Static | BindingFlags.Public);

    // Get the description attribute, if there is one.
    return fi.GetCustomAttributes(typeof(DescriptionAttribute), true).
        Cast<DescriptionAttribute>().SingleOrDefault();
}

मैंने DescriptionAttributeस्वयं को ऊपर लौटने का विकल्प चुना , इस घटना में कि आप यह निर्धारित करने में सक्षम होना चाहते हैं कि विशेषता भी लागू है या नहीं।


हालाँकि मैं इसे और अधिक जटिल स्थितियों के लिए याद
रखूंगा

26

आप इसे बहुत आसानी से वास्तव में कर सकते हैं। निम्नलिखित कोड का उपयोग करें।

enum GroupTypes
{
   OEM,
   CMB
};

फिर जब आप प्रत्येक एनम तत्व का स्ट्रिंग मान प्राप्त करना चाहते हैं तो कोड की निम्न पंक्ति का उपयोग करें।

String oemString = Enum.GetName(typeof(GroupTypes), GroupTypes.OEM);

मैंने अतीत में सफलतापूर्वक इस विधि का उपयोग किया है, और मैंने स्ट्रिंग स्थिरांक रखने के लिए एक स्थिरांक वर्ग का भी उपयोग किया है, दोनों बहुत अच्छी तरह से काम करते हैं, लेकिन मुझे यह पसंद है।


मैं एक ही बात सोच रहा था, लेकिन इस पर कुछ पकड़ होनी चाहिए ... नहीं तो मुझे संदेह होगा कि अधिक लोग यह सुझाव देंगे (हो सकता है कि मैं सिर्फ पागल हूं)।
मथिज्स वेसल्स

मुझे इस बारे में पता है कि केवल यह है कि मेरा मानना ​​है कि यह स्ट्रिंग का पता लगाने के लिए प्रतिबिंब का उपयोग करता है। एक परिणाम के रूप में अगर मैं एक निरंतर स्ट्रिंग का ट्रैक रखने के लिए एक समाधान के बाद हूँ, तो मैं आम तौर पर अपने अधिकांश अतिरिक्त सामानों को संग्रहीत करने के लिए एक वर्ग का उपयोग करूंगा। हालाँकि, अगर मेरे पास ऐसी स्थिति है जहाँ एक Enum सही समाधान है (मेरे Enum तत्वों के बारे में वर्णनात्मक स्ट्रिंग प्राप्त करने की परवाह किए बिना), तो इसके बजाय एक अतिरिक्त स्ट्रिंग को कहीं और तैरने के लिए प्रबंधित करने के लिए मैं बस वर्णित Enum मान का उपयोग करता हूं।
आर्थर C

+1 यह सबसे अच्छा और आसान उत्तर है, और इसे साबित करने के लिए यहां उच्च वोट भी हैं । विस्तार मॉडल का उपयोग करने के लिए एकमात्र समय बेहतर होता है जब आपको पाठ में रिक्त स्थान की आवश्यकता होती है (अधिक विवरण यहां )।
शार्प

14
नहीं, यह सिर्फ एक एनम वैल्यू का नाम प्राप्त कर रहा है, एनम वैल्यू के लिए स्ट्रिंग असाइन नहीं कर रहा है। ओपी का लक्ष्य एनम मूल्य से अलग एक स्ट्रिंग है जैसे: TheGroup = "OEM", TheOtherGroup = "CMB"।
टिम ऑटिन

3
मैं @ टिम की टिप्पणी से सहमत हूं, यह वह नहीं है जो ओपी करने की कोशिश कर रहा है। यदि आप सोच रहे हैं कि इसका उपयोग मामला क्या है, तो ऐसी स्थिति पर विचार करें जहां कोई डिवाइस कमांड के रूप में स्ट्रिंग्स लेता है, लेकिन साथ ही साथ कमांड का "मानव पठनीय" संस्करण भी होना चाहिए। मुझे "UPDATEFW" कमांड के साथ "अपडेट फ़र्मवेयर" जैसी चीज़ को संबद्ध करने की आवश्यकता थी।
येल्टन

20

स्थिर वर्ग में स्थिरांक जोड़ने का प्रयास करें। आप एक प्रकार के साथ समाप्त नहीं होते हैं, लेकिन आपके पास पठनीय, संगठित स्थिरांक होंगे:

public static class GroupTypes {

    public const string TheGroup = "OEM";
    public const string TheOtherGroup = "CMB";

}

3
कोड से वर्णनात्मक नाम पर वापस जाना मुश्किल है। आपको एक मैच की खोज करने के लिए सभी कास्ट फ़ील्ड पर प्रतिबिंब का उपयोग करना होगा।
ऐलेर

1
@andleer मुझे आपकी चिंता समझ में नहीं आती। यह मेरे द्वारा उपयोग किया जाने वाला समाधान है।
वीएसओ

हाँ, यह वास्तव में ठीक वही है जो मैं चाहता था। और यह सबसे संक्षिप्त / सुरुचिपूर्ण समाधान है जो मैं देखता हूं, जैसे कि मैं एक गणना w / int मानों को परिभाषित कर रहा था - लेकिन इसके बजाय स्ट्रिंग मानों के साथ। 100% परिपूर्ण।
चाड

3
इसके साथ समस्या यह है कि यह इस अर्थ में एनम के रूप में काम नहीं करता है कि हमारे पास मूल्यों की सीमित सूची के साथ एक अलग प्रकार नहीं होगा। एक फ़ंक्शन यह उम्मीद करता है कि इनका उपयोग फ़्री-फॉर्म स्ट्रिंग्स के साथ किया जा सकता है जो त्रुटि प्रवण है।
जुआन मार्टिनेज

14

अपने DB के लिए दूसरा एनम बनाएं, जिसमें निम्नलिखित शामिल हैं:

enum DBGroupTypes
{
    OEM = 0,
    CMB = 1
}

अब, आप स्ट्रिंग्स "OEM" और "CMB" से सही DBGroupTypes मान प्राप्त करने के लिए Enum.Parse का उपयोग कर सकते हैं। फिर आप अपने मॉडल में आगे उपयोग करने के लिए इच्छित सही गणना से सही मानों को पहचानने और प्राप्त करने के लिए उन लोगों को परिवर्तित कर सकते हैं।


यह प्रक्रिया में एक अतिरिक्त कदम प्रतीत होता है, एक वर्ग क्यों नहीं जो सब कुछ संभालता है?
सी। रॉस

11
विशेषताओं और प्रतिबिंब का उपयोग करने का विरोध किया?
डेव वान डेन आइंड

13

एक वर्ग का उपयोग करें।

संपादित करें: बेहतर उदाहरण

class StarshipType
{
    private string _Name;
    private static List<StarshipType> _StarshipTypes = new List<StarshipType>();

    public static readonly StarshipType Ultralight = new StarshipType("Ultralight");
    public static readonly StarshipType Light = new StarshipType("Light");
    public static readonly StarshipType Mediumweight = new StarshipType("Mediumweight");
    public static readonly StarshipType Heavy = new StarshipType("Heavy");
    public static readonly StarshipType Superheavy = new StarshipType("Superheavy");

    public string Name
    {
        get { return _Name; }
        private set { _Name = value; }
    }

    public static IList<StarshipType> StarshipTypes
    {
        get { return _StarshipTypes; }
    }

    private StarshipType(string name, int systemRatio)
    {
        Name = name;
        _StarshipTypes.Add(this);
    }

    public static StarshipType Parse(string toParse)
    {
        foreach (StarshipType s in StarshipTypes)
        {
            if (toParse == s.Name)
                return s;
        }
        throw new FormatException("Could not parse string.");
    }
}

1
कोड से वर्णनात्मक नाम पर वापस जाना मुश्किल है। आपको एक मैच की खोज करने के लिए सभी कास्ट फ़ील्ड पर प्रतिबिंब का उपयोग करना होगा।
andleer

1
में तुम्हारी बात समझ रहा हूँ। मैं एक संस्करण अपलोड करूंगा जो कि बाद में काम करता है, लेकिन मैं मानता हूं कि यह बहुत भारी है।
सी। रॉस

मेरा संस्करण सी। रॉस के समाधान stackoverflow.com/a/48441114/3862615
रोमन एम

7

समस्या से निपटने के लिए एक और तरीका है, एक एनम और स्ट्रिंग्स की एक सरणी है जो स्ट्रिंग्स की सूची के साथ एनम मानों को मैप करेगा:

public enum GroupTypes
{
    TheGroup  = 0,
    TheOtherGroup 
}

string[] GroupTypesStr = {
    "OEM",
    "CMB"
};

आप इसे इस तरह से उपयोग कर सकते हैं:

Log.Write(GroupTypesStr[(int)GroupTypes.TheOtherGroup]);

यह CMB का संकेत देगा

पेशेवरों:

  1. आसान और साफ कोड।
  2. उच्च प्रदर्शन (विशेषकर उन दृष्टिकोणों की तुलना में जो कक्षाओं का उपयोग करते हैं)

कान्स:

  1. इसे संपादित करते समय सूची को गड़बड़ाने की संभावना है, लेकिन यह छोटी सूची के लिए ठीक होगा।

6

यहाँ विस्तार विधि है जिसे मैंने स्ट्रिंग के रूप में एनम मान प्राप्त करने के लिए उपयोग किया है। यहां सबसे पहले एनम है।

public enum DatabaseEnvironment
{
    [Description("AzamSharpBlogDevDatabase")]
    Development = 1, 
    [Description("AzamSharpBlogQADatabase")]
    QualityAssurance = 2, 
    [Description("AzamSharpBlogTestDatabase")] 
    Test = 3
}

विवरण विशेषता System.ComponentModel से आई है।

और यहाँ मेरी विस्तार विधि है:

public static string GetValueAsString(this DatabaseEnvironment environment) 
{
    // get the field 
    var field = environment.GetType().GetField(environment.ToString());
    var customAttributes = field.GetCustomAttributes(typeof (DescriptionAttribute), false);

    if(customAttributes.Length > 0)
    {
        return (customAttributes[0] as DescriptionAttribute).Description;  
    }
    else
    {
        return environment.ToString(); 
    }
}

अब, आप निम्न कोड का उपयोग करके एनम को स्ट्रिंग मान के रूप में एक्सेस कर सकते हैं:

[TestFixture]
public class when_getting_value_of_enum
{
    [Test]
    public void should_get_the_value_as_string()
    {
        Assert.AreEqual("AzamSharpBlogTestDatabase",DatabaseEnvironment.Test.GetValueAsString());  
    }
}

5

क्या आपने डिक्शनरी का उपयोग करके लुकअप टेबल पर विचार किया है?

enum GroupTypes
{
    TheGroup,
    TheOtherGroup
}

Dictionary<string, GroupTypes> GroupTypeLookup = new Dictionary<string, GroupTypes>();
// initialize lookup table:
GroupTypeLookup.Add("OEM", TheGroup);
GroupTypeLookup.Add("CMB", TheOtherGroup);

जब आप इसे पढ़ते हैं तो आप एक स्ट्रिंग देखने के लिए GroupTypeLookup.TryGetValue () का उपयोग कर सकते हैं।


किसी दिए गए मूल्य के लिए आपको आसानी से चाबी कैसे मिलती है?
इगलासियस

सवाल दूसरे रास्ते से जाने को नहीं कहा। लेकिन यह एक और शब्दकोश बनाने के लिए काफी सरल होगा जो दूसरे तरीके से जाता है। वह है, शब्दकोश <GroupTypes, string>।
जिम मेंथेल

4
public class DataType
{
    private readonly string value;
    private static readonly Dictionary<string, DataType> predefinedValues;

    public static readonly DataType Json = new DataType("json");
    public static readonly DataType Xml = new DataType("xml");
    public static readonly DataType Text = new DataType("text");
    public static readonly DataType Html = new DataType("html");
    public static readonly DataType Binary = new DataType("binary");

    static DataType()
    {
        predefinedValues = new Dictionary<string, DataType>();
        predefinedValues.Add(Json.Value, Json);
        predefinedValues.Add(Xml.Value, Xml);
        predefinedValues.Add(Text.Value, Text);
        predefinedValues.Add(Html.Value, Html);
        predefinedValues.Add(Binary.Value, Binary);
    }

    private DataType(string value)
    {
        this.value = value;
    }

    public static DataType Parse(string value)
    {
        var exception = new FormatException($"Invalid value for type {nameof(DataType)}");
        if (string.IsNullOrEmpty(value))
            throw exception;

        string key = value.ToLower();
        if (!predefinedValues.ContainsKey(key))
            throw exception;

        return predefinedValues[key];
    }

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

3

C # एन्यूमरेटेड स्ट्रिंग्स का समर्थन नहीं करता है, लेकिन अधिकांश स्थितियों के लिए आप वांछित प्रभाव प्राप्त करने के लिए एक सूची या शब्दकोश का उपयोग कर सकते हैं।

उदाहरण के लिए पास / असफल परिणाम प्रिंट करें:

List<string> PassFail = new List<string> { "FAIL", "PASS" };
bool result = true;
Console.WriteLine("Test1: " + PassFail[result.GetHashCode()]);

2

मैं इसे पूरी तरह से एक एनम से बचने के लिए एक कक्षा में बनाऊंगा। और फिर एक प्रकार का मेहँदी के उपयोग से आप ऑब्जेक्ट बना सकते हैं जब आप इसे db से लेते हैं।

अर्थात:

public class Group
{
    public string Value{ get; set; }
    public Group( string value ){ Value = value; } 
    public static Group TheGroup() { return new Group("OEM"); }
    public static Group OtherGroup() { return new Group("CMB"); }

}

2

मैं सिर्फ एक शब्दकोश बनाऊंगा और कुंजी के रूप में कोड का उपयोग करूंगा।

संपादित करें: रिवर्स लुकअप (कुंजी खोजने) के बारे में टिप्पणी को संबोधित करने के लिए, यह बहुत ही कुशल नहीं होगा। यदि यह आवश्यक है, तो मैं इसे संभालने के लिए एक नया वर्ग लिखूंगा।


क्या आप किसी दिए गए मूल्य के लिए आसानी से एक कुंजी ले सकते हैं?
इगलासियस

C.Ross के लिए - मुझे यकीन नहीं है कि आपका क्या मतलब है। आप db से मानों को पढ़ सकते हैं और शब्दकोश को गतिशील रूप से आबाद कर सकते हैं।
झेल

2

मेरा पहला सवाल - क्या आपके पास डेटाबेस तक ही पहुँच है? यह डेटाबेस में सामान्य रूप से होना चाहिए, आदर्श रूप से, अन्यथा, किसी भी समाधान में त्रुटि होने का खतरा है। मेरे अनुभव में, "ओईएम" और "सीएमबी" से भरे डेटा फ़ील्ड में "ओईएम" और अन्य 'क्रैप डेटा' जैसी चीजें होती हैं, जो समय के साथ मिश्रित हो जाती हैं। यदि आप इसे सामान्य कर सकते हैं, तो आप कुंजी का उपयोग कर सकते हैं। आपके Enum के रूप में तत्वों से युक्त तालिका में, और आप बहुत क्लीनर संरचना के साथ काम कर रहे हैं।

यदि यह उपलब्ध नहीं है, तो मैं आपका Enum बनाऊंगा, और आपके लिए Enum में अपनी स्ट्रिंग को पार्स करने के लिए एक वर्ग बनाऊंगा। यह कम से कम आपको Enum.Parse / Reflection / etc का उपयोग करके किसी भी प्रकार के वर्कअराउंड करने की तुलना में गैर-मानक प्रविष्टियों को संभालने और त्रुटियों को संभालने के लिए बहुत अधिक लचीलेपन में कुछ लचीलापन देगा। एक शब्दकोश काम करेगा, लेकिन अगर आपके पास कभी भी समस्याएँ हैं, आदि को तोड़ सकता है।

मैं एक वर्ग लिखने की सलाह दूंगा ताकि आप कर सकें:

// I renamed this to GroupType, since it sounds like each element has a single type...
GroupType theType = GroupTypeParser.GetGroupType(theDBString);

यह DB को बदले बिना आपकी अधिकांश पठनीयता को सुरक्षित रखता है।


2

अगर मैं सही तरीके से समझूं, तो आपको स्ट्रिंग से एनम तक रूपांतरण की आवश्यकता है:

enum GroupTypes {
    Unknown = 0,
    OEM = 1,
    CMB = 2
}
static GroupTypes StrToEnum(string str){
    GroupTypes g = GroupTypes.Unknown;
    try {
        object o = Enum.Parse(typeof(GroupTypes), str, true);
        g = (GroupTypes)(o ?? 0);
    } catch {
    }
    return g;
}
// then use it like this
GroupTypes g1 = StrToEnum("OEM");
GroupTypes g2 = StrToEnum("bad value");

यदि आप चाहें तो एनम प्रकार के लिए आप जेनरिक के साथ इसे और अधिक फैंसी बना सकते हैं।


2

VS 2015 में, आप nameof का उपयोग कर सकते हैं

public class LogCategory
{
    public static string Trace;
    public static string Debug;
    public static string Info;
    public static string Warning;
    public static string Error;
}

उपयोग:

Logger.Write("This is almost like an enum.", nameof(LogCategory.Info));

2

ग्लेन्युलर एक्सटेंशन विधि के लिए एक छोटा सा ट्वीक, ताकि आप अन्य चीजों पर एक्सटेंशन का उपयोग सिर्फ ENUM की तुलना में कर सकें;

using System;
using System.ComponentModel;
namespace Extensions {
    public static class T_Extensions {
        /// <summary>
        /// Gets the Description Attribute Value
        /// </summary>
        /// <typeparam name="T">Entity Type</typeparam>
        /// <param name="val">Variable</param>
        /// <returns>The value of the Description Attribute or an Empty String</returns>
        public static string Description<T>(this T t) {
            DescriptionAttribute[] attributes = (DescriptionAttribute[])t.GetType().GetField(t.ToString()).GetCustomAttributes(typeof(DescriptionAttribute), false);
            return attributes.Length > 0 ? attributes[0].Description : string.Empty;
        }
    }
}

या Linq का उपयोग करना

using System;
using System.ComponentModel;
using System.Linq;

namespace Extensions {


public static class T_Extensions {
        public static string Description<T>(this T t) =>
            ((DescriptionAttribute[])t
            ?.GetType()
            ?.GetField(t?.ToString())
            ?.GetCustomAttributes(typeof(DescriptionAttribute), false))
            ?.Select(a => a?.Description)
            ?.FirstOrDefault() 
            ?? string.Empty;  
    }
}

2

@ इवेन मिएन के उत्तर के बाद मैंने थोड़ा आगे बढ़ने और इसे सामान्य बनाने की कोशिश की है, मुझे लगभग ऐसा ही लगता है लेकिन एक मामला अभी भी विरोध कर रहा है और मैं शायद अपने कोड को थोड़ा सरल कर सकता हूं।
मैं इसे यहाँ पोस्ट करता हूँ अगर कोई देखता है कि मैं कैसे सुधार कर सकता हूं और विशेष रूप से यह काम करता है क्योंकि मैं इसे एक स्ट्रिंग से असाइन नहीं कर सकता

तो अब तक मेरे पास निम्नलिखित परिणाम हैं:

        Console.WriteLine(TestEnum.Test1);//displays "TEST1"

        bool test = "TEST1" == TestEnum.Test1; //true

        var test2 = TestEnum.Test1; //is TestEnum and has value

        string test3 = TestEnum.Test1; //test3 = "TEST1"

        var test4 = TestEnum.Test1 == TestEnum.Test2; //false
         EnumType<TestEnum> test5 = "TEST1"; //works fine

        //TestEnum test5 = "string"; DOESN'T compile .... :(:(

जहां जादूगर होता है:

public abstract  class EnumType<T>  where T : EnumType<T>   
{

    public  string Value { get; set; }

    protected EnumType(string value)
    {
        Value = value;
    }


    public static implicit operator EnumType<T>(string s)
    {
        if (All.Any(dt => dt.Value == s))
        {
            Type t = typeof(T);

            ConstructorInfo ci = t.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic,null, new Type[] { typeof(string) }, null);

            return (T)ci.Invoke(new object[] {s});
        }
        else
        {
            return null;
        }
    }

    public static implicit operator string(EnumType<T> dt)
    {
        return dt?.Value;
    }


    public static bool operator ==(EnumType<T> ct1, EnumType<T> ct2)
    {
        return (string)ct1 == (string)ct2;
    }

    public static bool operator !=(EnumType<T> ct1, EnumType<T> ct2)
    {
        return !(ct1 == ct2);
    }


    public override bool Equals(object obj)
    {
        try
        {
            return (string)obj == Value;
        }
        catch
        {
            return false;
        }
    }

    public override int GetHashCode()
    {
        return Value.GetHashCode();
    }

    public static IEnumerable<T> All
     => typeof(T).GetProperties()
       .Where(p => p.PropertyType == typeof(T))
       .Select(x => (T)x.GetValue(null, null));



}

मुझे केवल अपनी दुश्मनी के लिए यह घोषित करना होगा:

public class TestEnum : EnumType<TestEnum> 
{

    private TestEnum(string value) : base(value)
    {}

    public static TestEnum Test1 { get { return new TestEnum("TEST1"); } }
    public static TestEnum Test2 { get { return new TestEnum("TEST2"); } }
}

इस महान नौकरी के लिए धन्यवाद, मैं लंबे समय से इस तरह के दृष्टिकोण की तलाश में था। मुझे लगता है कि आपको इसके लिए 1000 अंक मिलने चाहिए
user3492977

ओह, इस टिप्पणी के लिए धन्यवाद, और मुझे यह याद दिलाने के लिए धन्यवाद, मैंने दो साल तक सी # का उपयोग नहीं किया था जब मैंने इस बिट कोड को लिखा था, मुझे जल्द ही इसे वापस प्राप्त करना चाहिए!
लोमिथ्रानी

@ user3492977 मैं अंत में इसे वापस ले आया और इसे पूरी तरह से कार्यशील बना दिया, मुझे अभी भी संदेह है कि अगर यह एक महान विचार या एक बेकार चीज है: D stackoverflow.com/questions/62043138/…
Lomithodi

2

नई .Net कोर 3.0 / C # 8.0 (यदि आपका कार्य वातावरण आपको अपनी परियोजना को अपग्रेड करने की अनुमति देता है) एक शॉर्ट-हैंड स्विच स्टेटमेंट है जो कुछ हद तक एनुम-ईश लगता है। दिन के अंत में यह वही पुराना बोरिंग स्विच स्टेटमेंट है जिसका उपयोग हम वर्षों से कर रहे हैं।

यहां केवल वास्तविक अंतर यह है कि स्विच स्टेटमेंट को एक नया सूट मिला।

public static RGBColor FromRainbow(Rainbow colorBand) =>
colorBand switch
{
    Rainbow.Red    => new RGBColor(0xFF, 0x00, 0x00),
    Rainbow.Orange => new RGBColor(0xFF, 0x7F, 0x00),
    Rainbow.Yellow => new RGBColor(0xFF, 0xFF, 0x00),
    Rainbow.Green  => new RGBColor(0x00, 0xFF, 0x00),
    Rainbow.Blue   => new RGBColor(0x00, 0x00, 0xFF),
    Rainbow.Indigo => new RGBColor(0x4B, 0x00, 0x82),
    Rainbow.Violet => new RGBColor(0x94, 0x00, 0xD3),
    _              => throw new ArgumentException(message: "invalid enum value", paramName: nameof(colorBand)),
};

आप देखेंगे कि जिस कोड को मैंने यहां से कॉपी किया था , वह वास्तव में एक एनम का उपयोग परम के रूप में कर रहा है।

यह बिल्कुल वैसा नहीं है जैसा आप चाहते हैं (और मुझ पर भरोसा करें, मुझे कुछ ऐसा ही चाहिए था जो ओपी लंबे समय से अनुरोध कर रहा है), लेकिन मुझे वास्तव में ऐसा महसूस हो रहा है कि यह एमएस की कुछ जैतून शाखा है। JMO।

आशा है कि यह किसी की मदद करता है!


2

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

    struct ViewTypes
    {
        public const string View1 = "Whatever string you like";
        public const string View2 = "another string";
    }

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

   switch( some_string_variable )
   {
      case ViewTypes.View1: /* do something */ break;
      case ViewTypes.View2: /* do something else */ break;
   }

1

मैंने @Even (के माध्यम से class Xऔर public static Xसदस्यों) द्वारा सुझाए गए कुछ शब्दों को भी लागू किया , बस बाद में पता चलता है कि इन दिनों, .net 4.5 से शुरू होकर, वहाँ सही ToString() तरीका है।

अब मैं सब कुछ वापस enums पर लागू कर रहा हूँ।


1

यह एक जोरदार टाइप पैरामीटर के रूप में या एक स्ट्रिंग के रूप में उपयोग करने का एक तरीका है :

public class ClassLikeEnum
{
    public string Value
    {
        get;
        private set;
    }

    ClassLikeEnum(string value) 
    {
        Value = value;
    }

    public static implicit operator string(ClassLikeEnum c)
    {
        return c.Value;
    }

    public static readonly ClassLikeEnum C1 = new ClassLikeEnum("RandomString1");
    public static readonly ClassLikeEnum C2 = new ClassLikeEnum("RandomString2");
}

1

आप दो enums का उपयोग कर सकते हैं। एक डेटाबेस के लिए और दूसरा पठनीयता के लिए।

आपको केवल यह सुनिश्चित करने की आवश्यकता है कि वे सिंक में रहें, जो एक छोटी सी लागत की तरह लगता है। आपको मान सेट करने की आवश्यकता नहीं है, बस स्थितियां समान सेट करें, लेकिन मान सेट करने से यह स्पष्ट होता है कि दो एनम संबंधित हैं और त्रुटियों को एंम सदस्यों को पुन: व्यवस्थित करने से रोकता है। और एक टिप्पणी से रखरखाव चालक दल को पता चलता है कि ये संबंधित हैं और इन्हें सिंक में रखा जाना चाहिए।

// keep in sync with GroupTypes
public enum GroupTypeCodes
{
    OEM,
    CMB
}

// keep in sync with GroupTypesCodes
public enum GroupTypes
{
    TheGroup = GroupTypeCodes.OEM,
    TheOtherGroup = GroupTypeCodes.CMB
}

इसका उपयोग करने के लिए आपको पहले कोड में बदलना होगा:

GroupTypes myGroupType = GroupTypes.TheGroup;
string valueToSaveIntoDatabase = ((GroupTypeCodes)myGroupType).ToString();

फिर यदि आप इसे और भी सुविधाजनक बनाना चाहते हैं, तो आप एक एक्सटेंशन फंक्शन जोड़ सकते हैं जो केवल इस प्रकार के एनम के लिए काम करता है:

public static string ToString(this GroupTypes source)
{
    return ((GroupTypeCodes)source).ToString();
}

और तुम तो बस कर सकते हो:

GroupTypes myGroupType = GroupTypes.TheGroup;
string valueToSaveIntoDatabase = myGroupType.ToString();

यह एक बुरा अभ्यास है: एक आश्रित के साथ एक enumमूल्य में बदलाव एक दूसरे को असमान रूप से गड़बड़ कर सकता है।
लोरेन्ज लो सॉयर

1

मैं मूल रूप से @ArthurC द्वारा परावर्तन उत्तर की तलाश में था

बस उसके जवाब को थोड़ा विस्तार देने के लिए, आप एक सामान्य कार्य करके इसे और बेहतर बना सकते हैं:

    // If you want for a specific Enum
    private static string EnumStringValue(GroupTypes e)
    {
        return EnumStringValue<GroupTypes>(e);
    }

    // Generic
    private static string EnumStringValue<T>(T enumInstance)
    {
        return Enum.GetName(typeof(T), enumInstance);
    } 

फिर आपके पास जो कुछ भी है उसे आप केवल लपेट सकते हैं

EnumStringValue(GroupTypes.TheGroup) // if you incorporate the top part

या

EnumStringValue<GroupTypes>(GroupTypes.TheGroup) // if you just use the generic

1

@EvenMien से लिया गया और कुछ टिप्पणियों में जोड़ा गया। (मेरे अपने उपयोग के मामले के लिए भी)

public struct AgentAction
{
    private AgentAction(string value) { Value = value; }

    public string Value { get; private set; }

    public override string ToString()
    {
        return this.Value;
    }

    public static AgentAction Login = new AgentAction("Logout");
    public static AgentAction Logout = new AgentAction("Logout");

    public static implicit operator string(AgentAction action) { return action.ToString(); }
}

1

इस वर्ग को जोड़ना

public class DatabasePreference {
    public DatabasePreference([CallerMemberName] string preferenceName = "") {
        PreferenceName = preferenceName;
    }
    public string PreferenceName;
}

यह कार्य CallerMemberNameकोडिंग को कम करने के लिए उपयोग कर रहा है

का उपयोग करते हुए:

//Declare names
public static DatabasePreference ScannerDefaultFlashLight = new DatabasePreference();
public static DatabasePreference ScannerQrCodes = new DatabasePreference();
public static DatabasePreference Scanner1dCodes = new DatabasePreference();

झसे आज़माओ:

Console.WriteLine(ScannerDefaultFlashLight.PreferenceName);
Console.WriteLine(ScannerDefaultFlashLight.Scanner1dCodes);

उत्पादन:

ScannerDefaultFlashLight
Scanner1dCodes

0

अन्य रायों के आधार पर, यह वही है जो मैं लेकर आया हूं। यह दृष्टिकोण टाइप करने से बचता है। जहाँ आप लगातार मूल्य प्राप्त करना चाहते हैं।

मेरे पास इस तरह के सभी स्ट्रिंग एनम के लिए एक बेस क्लास है:

using System;
using Newtonsoft.Json;

[JsonConverter(typeof(ConstantConverter))]
public class StringEnum: IConvertible
{
    public string Value { get; set; }

    protected StringEnum(string value)
    {
        Value = value;
    }

    public static implicit operator string(StringEnum c)
    {
        return c.Value;
    }
    public string ToString(IFormatProvider provider)
    {
        return Value;
    }

    public TypeCode GetTypeCode()
    {
        throw new NotImplementedException();
    }

    public bool ToBoolean(IFormatProvider provider)
    {
        throw new NotImplementedException();
    }
    //The same for all the rest of IConvertible methods
}

JsonConverter इस तरह है:

using System;
using Newtonsoft.Json;

class ConstantConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return true;
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        if (value == null)
        {
            serializer.Serialize(writer, null);
        }
        else
        {
            serializer.Serialize(writer, value.ToString());
        }
    }
}

और एक वास्तविक स्ट्रिंग एनम कुछ इस तरह होगी:

public sealed class Colors : StringEnum
{
    public static Colors Red { get { return new Catalog("Red"); } }
    public static Colors Yellow { get { return new Catalog("Yellow"); } }
    public static Colors White { get { return new Catalog("White"); } }

    private Colors(string value) : base(value) { }
}

और इसके साथ, आप बस रंग का उपयोग कर सकते हैं। मूल्य संपत्ति का उपयोग किए बिना भी json को क्रमबद्ध करें


0

मुझे स्ट्रिंग में स्टोर करने की तरह मजबूत कुछ भी नहीं चाहिए था। मुझे बस MyEnum.BillEveryWeek"बिल हर हफ्ते" या MyEnum.UseLegacySystem"लीगेसी सिस्टम का उपयोग " जैसे कुछ मोड़ने की ज़रूरत थी - मूल रूप से अपने ऊंट-केसिंग द्वारा एन्युकम को निचले-मामले के शब्दों में विभाजित करें।

public static string UnCamelCase(this Enum input, string delimiter = " ", bool preserveCasing = false)
{
    var characters = input.ToString().Select((x, i) =>
    {

       if (i > 0 && char.IsUpper(x))
       {
           return delimiter + x.ToString(CultureInfo.InvariantCulture);
       }
       return x.ToString(CultureInfo.InvariantCulture);

    });

    var result = preserveCasing
       ? string.Concat(characters)
       : string.Concat(characters).ToLower();

    var lastComma = result.LastIndexOf(", ", StringComparison.Ordinal);

    if (lastComma > -1)
    {
       result = result.Remove(lastComma, 2).Insert(lastComma, " and ");
    }

    return result;
}

MyEnum.UseLegacySystem.UnCamelCase() आउटपुट "विरासत प्रणाली का उपयोग करें"

यदि आपके पास कई झंडे हैं, तो यह सादे अंग्रेजी में बदल जाएगा (अंतिम अल्पविराम के स्थान पर "और" को छोड़कर)।

var myCustomerBehaviour = MyEnum.BillEveryWeek | MyEnum.UseLegacySystem | MyEnum.ChargeTaxes;

Console.WriteLine(myCustomerBehaviour.UnCamelCase());
//outputs "bill every week, use legacy system and charge taxes"
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.