c# हर संभव संयोजन की घोषणा किए बिना Enum(झंडे विशेषता के साथ) पर स्विच करें?




enums switch-statement (7)

सबसे आसान तरीका है कि आप केवल एक ORed , अपने मामले में आप निम्न कार्य कर सकते हैं:

[Flags()]public enum CheckType
{
    Form = 1,   
    QueryString = 2,
    TempData = 4,
    FormQueryString = Form | QueryString,
    QueryStringTempData = QueryString | TempData,
    All = FormQueryString | TempData
}

एक बार जब आपके पास enum सेटअप होता है तो अपना switch स्टेटमेंट करने में आसानी होती है

जैसे, अगर मैंने निम्नलिखित निर्धारित किया है:

var chkType = CheckType.Form | CheckType.QueryString;

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

switch(chkType){
 case CheckType.Form:
   // Have Form
 break;
 case CheckType.QueryString:
   // Have QueryString
 break;
 case CheckType.TempData:
  // Have TempData
 break;
 case CheckType.FormQueryString:
  // Have both Form and QueryString
 break;
 case CheckType.QueryStringTempData:
  // Have both QueryString and TempData
 break;
 case CheckType.All:
  // All bit options are set
 break;
}

बहुत क्लीनर और आपको HasFlag साथ एक स्टेटमेंट का उपयोग करने की आवश्यकता नहीं है। आप अपनी इच्छानुसार कोई भी संयोजन बना सकते हैं और फिर स्विच स्टेटमेंट को पढ़ना आसान बना सकते हैं।

मैं आपकी enums को तोड़ने की सलाह enums , यह देखने की कोशिश करूंगा कि क्या आप अलग-अलग चीजों को एक ही enum में नहीं मिला रहे हैं। आप मामलों की संख्या को कम करने के लिए कई enums सेटअप कर सकते हैं।

मैं एक एनुम पर कैसे स्विच कर सकता हूं जिसमें झंडे विशेषता सेट है (या बिट संचालन के लिए अधिक सटीक उपयोग किया जाता है)?

मैं सभी मामलों को स्विच में सक्षम होना चाहता हूं जो घोषित मूल्यों से मेल खाते हैं।

समस्या यह है कि अगर मेरे पास निम्न एनम है

[Flags()]public enum CheckType
{
    Form = 1,   
    QueryString = 2,
    TempData = 4,
}

और मैं इस तरह से एक स्विच का उपयोग करना चाहता हूं

switch(theCheckType)
{
   case CheckType.Form:
       DoSomething(/*Some type of collection is passed */);
       break;

   case CheckType.QueryString:
       DoSomethingElse(/*Some other type of collection is passed */);
       break;

   case CheckType.TempData
       DoWhatever(/*Some different type of collection is passed */);
       break;
}

यदि "theCheckType" दोनों CheckType.Form पर सेट है CheckType.TempData मैं चाहता हूं कि यह दोनों मामले में हिट हो। स्पष्ट रूप से यह ब्रेक के कारण मेरे उदाहरण में दोनों नहीं मारा, लेकिन इसके अलावा यह भी विफल रहता है क्योंकि CheckType.Form CheckType.Form के बराबर नहीं है | CheckType.TempData

एकमात्र समाधान तब जैसा कि मैं देख सकता हूं कि एनम मूल्यों के हर संभव संयोजन के लिए एक मामला बनाना है?

कुछ इस तरह

    case CheckType.Form | CheckType.TempData:
        DoSomething(/*Some type of collection is passed */);
        DoWhatever(/*Some different type of collection is passed */);
        break;

    case CheckType.Form | CheckType.TempData | CheckType.QueryString:
        DoSomething(/*Some type of collection is passed */);
        DoSomethingElse(/*Some other type of collection is passed */);
        break;

... and so on...

लेकिन यह वास्तव में बहुत वांछित नहीं है (क्योंकि यह जल्दी से बहुत बड़ा हो जाएगा)

अभी मेरे पास 3 हैं अगर प्रत्येक के बजाय सही स्थिति

कुछ इस तरह

if ((_CheckType & CheckType.Form) != 0)
{
    DoSomething(/*Some type of collection is passed */);
}

if ((_CheckType & CheckType.TempData) != 0)
{
    DoWhatever(/*Some type of collection is passed */);
}

....

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

क्या इस समस्या को हल करने के लिए कुछ जादुई उपाय है?

मैंने घोषित मूल्यों के माध्यम से लूप की संभावना के बारे में सोचा है और फिर स्विच का उपयोग किया है, तो यह केवल घोषित किए गए प्रत्येक मान के लिए स्विच को हिट करेगा, लेकिन मुझे नहीं पता कि यह कैसे काम करेगा और अगर यह प्रदर्शन ठीक है, तो यह एक अच्छा विचार है ( अगर की तुलना में बहुत अधिक है)?

घोषित किए गए सभी एनम वैल्यू के माध्यम से लूप करने का एक आसान तरीका है?

मैं केवल ToString () और "," और फिर विभाजन के माध्यम से बंटवारे का उपयोग करके आ सकता हूं और हर एक स्ट्रिंग को पार्स कर सकता हूं।

अद्यतन करें:

मैं देख रहा हूँ कि मैंने एक अच्छा पर्याप्त काम नहीं किया है। मेरा उदाहरण सरल है (मेरे परिदृश्य को सरल बनाने की कोशिश की गई है)।

मैं यह देखने के लिए Asp.net MVC में ActionMethodSelectorAttribute के लिए इसका उपयोग करता हूं कि क्या कोई विधि url / रूट को हल करते समय उपलब्ध होनी चाहिए।

मैं इसे विधि पर कुछ इस तरह घोषित करके करता हूं

[ActionSelectorKeyCondition(CheckType.Form | CheckType.TempData, "SomeKey")]
public ActionResult Index()
{
    return View();
} 

इसका मतलब यह होगा कि यह जाँचना चाहिए कि क्या फॉर्म या टेंपडाटा के पास उपलब्ध विधि के लिए निर्दिष्ट कुंजी है।

विधियाँ यह कह रही होंगी (doSomething (), doSomethingElse () और doWhatever () मेरे पिछले उदाहरण में) वास्तव में रिटर्न वैल्यू के रूप में बूल होंगे और उन्हें एक पैरामीटर (अलग-अलग संग्रह) के साथ बुलाया जाएगा जो एक इंटरफ़ेस साझा नहीं करता है जो कि हो सकता है इस्तेमाल किया - नीचे दिए गए लिंक में मेरा उदाहरण कोड देखें)।

उम्मीद करने के लिए कि मैं जो कर रहा हूं उसका एक बेहतर विचार दे सकता हूं कि मैंने वास्तव में पास्टबिन पर क्या कर रहा हूं, इसका एक सरल उदाहरण चिपकाया है - यह यहां पाया जा सकता है http://pastebin.com/m478cc2b8


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

संपादित करें: हम निश्चित रूप से इस कोड को LINQ और कुछ सहायक कार्यों के उपयोग के माध्यम से अधिक कॉम्पैक्ट बना सकते हैं, लेकिन मुझे लगता है कि कम परिष्कृत रूप में समझना आसान है। यह ऐसा मामला हो सकता है जहां स्थिरता लालित्य को रौंदती है।

यहाँ एक उदाहरण है:

[Flags()]public enum CheckType
{
  Form = 1,       
  QueryString = 2,
  TempData = 4,
}

void PerformActions( CheckType c )
{
  // array of bits set in the parameter {c}
  bool[] actionMask = { false, false, false };
  // array of delegates to the corresponding actions we can invoke...
  Action availableActions = { DoSomething, DoSomethingElse, DoAnotherThing };

  // disassemble the flags into a array of booleans
  for( int i = 0; i < actionMask.Length; i++ )
    actionMask[i] = (c & (1 << i)) != 0;

  // for each set flag, dispatch the corresponding action method
  for( int actionIndex = 0; actionIndex < actionMask.Length; actionIndex++ )
  {
      if( actionMask[actionIndex])
          availableActions[actionIndex](); // invoke the corresponding action
  }
}

वैकल्पिक रूप से, यदि आप जिस क्रम में मूल्यांकन करते हैं वह कोई मायने नहीं रखता है, तो यहां सरल, स्पष्ट समाधान है जो बस काम करता है। यदि ऑर्डर मायने रखता है, तो बिट्स-शिफ्टिंग ऑपरेशंस को उस सरणी से बदलें, जिसमें आप उन्हें मूल्यांकन करना चाहते हैं।

int flagMask = 1 << 31; // start with high-order bit...
while( flagMask != 0 )   // loop terminates once all flags have been compared
{
  // switch on only a single bit...
  switch( theCheckType & flagMask )
  {
   case CheckType.Form:
     DoSomething(/*Some type of collection is passed */);
     break;

   case CheckType.QueryString:
     DoSomethingElse(/*Some other type of collection is passed */);
     break;

   case CheckType.TempData
     DoWhatever(/*Some different type of collection is passed */);
     break;
  }

  flagMask >>= 1;  // bit-shift the flag value one bit to the right
}

आपके संपादन और आपके वास्तविक जीवन के कोड के आधार पर, मैं शायद कुछ इस तरह देखने के लिए IsValidForRequest विधि को अपडेट IsValidForRequest :

public sealed override bool IsValidForRequest
    (ControllerContext cc, MethodInfo mi)
{
    _ControllerContext = cc;

    var map = new Dictionary<CheckType, Func<bool>>
        {
            { CheckType.Form, () => CheckForm(cc.HttpContext.Request.Form) },
            { CheckType.Parameter,
                () => CheckParameter(cc.HttpContext.Request.Params) },
            { CheckType.TempData, () => CheckTempData(cc.Controller.TempData) },
            { CheckType.RouteData, () => CheckRouteData(cc.RouteData.Values) }
        };

    foreach (var item in map)
    {
        if ((item.Key & _CheckType) == item.Key)
        {
            if (item.Value())
            {
                return true;
            }
        }
    }
    return false;
}

C # 7 में संभव होना चाहिए

switch (t1)
    {
        case var t when t.HasFlag(TST.M1):
            {
                break;
            }
        case var t when t.HasFlag(TST.M2):
            {
                break;
            }

एक Dictionary<CheckType,Action> जो आप भरेंगे

dict.Add(CheckType.Form, DoSomething);
dict.Add(CheckType.TempDate, DoSomethingElse);
...

आपके मूल्य का अपघटन

flags = Enum.GetValues(typeof(CheckType)).Where(e => (value & (CheckType)e) == (CheckType)e).Cast<CheckType>();

और फिर

foreach (var flag in flags)
{
   if (dict.ContainsKey(flag)) dict[flag]();
}

(कोड अप्राप्त)


C # 7 के साथ अब आप कुछ इस तरह लिख सकते हैं:

public void Run(CheckType checkType)
{
    switch (checkType)
    {
        case var type when CheckType.Form == (type & CheckType.Form):
            DoSomething(/*Some type of collection is passed */);
            break;

        case var type when CheckType.QueryString == (type & CheckType.QueryString):
            DoSomethingElse(/*Some other type of collection is passed */);
            break;

        case var type when CheckType.TempData == (type & CheckType.TempData):
            DoWhatever(/*Some different type of collection is passed */);
            break;
    }
}

बस HasFlag उपयोग HasFlag

if(theCheckType.HasFlag(CheckType.Form)) DoSomething(...);
if(theCheckType.HasFlag(CheckType.QueryString)) DoSomethingElse(...);
if(theCheckType.HasFlag(CheckType.TempData)) DoWhatever(...);




bit