2012-03-26 12 views
5

का विस्तार इससे पहले कि आप की आलोचना और C# specification की §8.7.2 मुझे इशारा करते हुए शुरू करते हैं, ध्यान से पढ़ें :)स्विच बयान - सी #/आईडीई क्षमता

हम सभी जानते हैं कि कैसे स्विच सी # में की तरह दिखता है। ठीक है तो "बुरा" बार विधि

static int barCounter = 0; 
public static int Bar() 
{ 
    return ++barCounter; 
} 

इस वर्ग में कहीं न कहीं साथ वर्ग MainWindow पर विचार हम इस

Action switchCode =() => 
{ 
    switch (Bar()) 
    { 
     case 1: 
      Console.WriteLine("First"); 
      break; 
     case 2: 
      Console.WriteLine("Second"); 
      break; 
    } 
}; 

switchCode(); 

switchCode(); 

कंसोल विंडो में की तरह कोड है हम देखेंगे

First 
Second 

सी # में अभिव्यक्तियों का उपयोग करके हम वही कर सकते हैं - एक ही कोड लिखना

var switchValue = Expression.Call(typeof(MainWindow).GetMethod("Bar")); 

var WriteLine = typeof(Console).GetMethod("WriteLine", new Type[] { typeof(String) }); 

var @switch = Expression.Switch(switchValue, 
    Expression.SwitchCase(
     Expression.Call(WriteLine, Expression.Constant("First")), 
     Expression.Constant(1) 
     ), 
    Expression.SwitchCase(
     Expression.Call(WriteLine, Expression.Constant("Second")), 
     Expression.Constant(2) 
     ) 
    ); 

Action switchCode = Expression.Lambda<Action>(@switch).Compile(); 

switchCode(); 

switchCode(); 

हम देख सकता है DebugView में इस अभिव्यक्ति

.Switch (.Call WpfApplication1.MainWindow.Bar()) { 
.Case (1): 
     .Call System.Console.WriteLine("First") 
.Case (2): 
     .Call System.Console.WriteLine("Second") 
} 

Ehmm, क्या हुआ अगर हम Expression.Call बजाय Expression.Constant का उपयोग करें "के पीछे कोड"?

public static bool foo1() { return false; } 

public static bool foo2() { return true; } 

// ..... 

var foo1 = Ex.Call(typeof(MainWindow).GetMethod("foo1")); 
var foo2 = Ex.Call(typeof(MainWindow).GetMethod("foo2")); 
var switchValue = Ex.Call(typeof(MainWindow).GetMethod("Bar")); 

var WriteLine = typeof(Console).GetMethod("WriteLine", new Type[] { typeof(String) }); 

var @switch = Ex.Switch(Ex.Constant(true), 
    Ex.SwitchCase(
     Ex.Call(WriteLine, Ex.Constant("First")), 
     foo1 
     ), 
    Ex.SwitchCase(
     Ex.Call(WriteLine, Ex.Constant("OK!")), 
     Ex.Equal(switchValue, Ex.Constant(2)) 
     ), 
    Ex.SwitchCase(
     Ex.Call(WriteLine, Ex.Constant("Second")), 
     foo2 
     ) 
    ); 

Action switchCode = Ex.Lambda<Action>(@switch).Compile(); 

switchCode(); 

switchCode(); 

कंसोल खिड़की से पता चलता है, हम

Second 
OK! 

और अपेक्षा के अनुरूप DebugView

.Switch (True) { 
.Case (.Call WpfApplication1.MainWindow.foo1()): 
     .Call System.Console.WriteLine("First") 
.Case (.Call WpfApplication1.MainWindow.Bar() == 2): 
     .Call System.Console.WriteLine("OK!") 
.Case (.Call WpfApplication1.MainWindow.foo2()): 
     .Call System.Console.WriteLine("Second") 
} 

तो यह मामला बयान :)

में गैर निरंतर अभिव्यक्ति उपयोग करना संभव है ठीक है, मुझे पता है कि यह छोटा 'गन्दा' कोड है। लेकिन यहां मेरा प्रश्न आता है (अंत में: पी):
क्या ऐसा करने के लिए आईडीई/विजुअलस्टूडियो/कंपाइलर की कार्यक्षमता बढ़ाने का कोई तरीका है, लेकिन अधिक सुरुचिपूर्ण कोड के साथ?
कुछ इस

switch (true) 
{ 
    case foo1(): 
     Console.WriteLine("First"); 
     break; 
    case Bar() == 2: 
     Console.WriteLine("OK!"); 
     break; 
    case foo2(): 
     Console.WriteLine("Second"); 
     break; 
} 

की तरह मैं यह जानता हूँ कुछ विस्तार किया जाएगा और कोड एक ही (नहीं एक ही प्रदर्शन) नहीं होगा। लेकिन मुझे आश्चर्य है कि क्या ऑन-द-फ्लाई पर "चेंज" कोड भी संभव है - जैसे अज्ञात फ़ंक्शन या उपज वापसी नेस्टेड क्लास में बदल जाती है।

मुझे आशा है कि कोई उपरोक्त पाठ से गुजरता है और कुछ सुराग छोड़ देता है।

+4

ऐसी समस्या को हल करने के लिए बहुत सारे प्रयासों की तरह लगता है जो अस्तित्व में नहीं है। स्विच लगातार लुकअप समय की पेशकश कर सकते हैं। परिदृश्यों में यह एक बड़ी बात है जहां आपके पास बड़ी संख्या में संभावित मूल्य हैं। बस 'if/else if' की श्रृंखला का उपयोग करें और वास्तविक समस्याओं को हल करने के लिए आगे बढ़ें (या ऐसी भाषा का उपयोग करें जो बोर्ड में प्रदर्शन पर अभिव्यक्ति का पक्ष लेती है)। –

+0

@EdS। आपको लगता है कि मुझे if/else if के बारे में पता नहीं है? यह "चुनौती" है कि यह कैसे करें, समस्या नहीं है "मैं बुलियन-कंडीशन-स्टेटमेंट का समूह कैसे उपयोग कर सकता हूं"। असल में मैंने PHP और जावास्क्रिप्ट का उपयोग किया, बहुत कुछ ऊपर जैसा है। यदि आप कुछ वास्तविक समस्या चाहते हैं: http://stackoverflow.com/q/9536087/1245315 – Carnifex

+1

नहीं, मुझे लगता है कि आप अपना समय बर्बाद कर रहे हैं और वास्तविक समस्याओं को हल करने के लिए इसका उपयोग नहीं कर रहे हैं। हां, ऐसी भाषाएं हैं जो आप प्रस्तावित कर सकते हैं, वे निरंतर समय की तलाश भी नहीं कर सकते हैं। इस जीवन में आपके पास केवल सीमित समय है, मेरी सलाह है कि इस तरह की चीजों पर इसे न खोएं, जिसका किसी के लिए कोई प्रशंसनीय लाभ नहीं है। एक प्रोग्रामिंग भाषा सिर्फ एक उपकरण है, न कि खुद के लिए एक लक्ष्य। आपके अन्य प्रश्न के लिए ... कोई धन्यवाद नहीं, यूआई क्विर्क मुझे रूचि नहीं देते हैं, यही कारण है कि मैं जीवित रहने के लिए यूआई का निर्माण नहीं करता :) –

उत्तर

1

नहीं, यह संभव नहीं है, और न ही मुझे पता है। यह पहले से ही चमत्कार है कि आप stringswitch कथन (अपरिवर्तनीय व्यवहार के साथ संदर्भ प्रकार) के अंदर उपयोग कर सकते हैं। इस तरह के मामलों के लिए बस if, if/else, if/elseif संयोजनों का उपयोग करें।

+2

जबकि मैं पूरी तरह से आपके उत्तर से सहमत हूं, मुझे नहीं पता कि यह स्विच के अंदर तारों का उपयोग करने का चमत्कार क्यों है, क्योंकि आप वास्तव में उपयोग कर रहे हैं एक संकलन-समय निरंतर (शाब्दिक स्ट्रिंग मान) है। –

+0

उदाहरण के लिए 'सी ++' में आप 'स्विच' कथन में एक स्ट्रिंग का उपयोग नहीं कर सकते हैं। 'टाइप' की धारणा, 'स्पष्ट तुलना क्षमता' कुछ ऐसा है जो 'सी #' "में आता है"। यही है, मेरा मुद्दा सिर्फ उस भलाई को ध्यान में रखना था जो 'नेट' हमें लाता है। – Tigran

1

वर्तमान में ऐसे एक्सटेंशन नहीं हैं जो इस तरह की चीजें करते हैं। हालांकि यह उनका कहना है कि एमएस एसक्यूएल वास्तव में क्या आप के लिए

SELECT 
    Column1, Column2, 
    CASE 
    WHEN SomeCondition THEN Column3 
    WHEN SomeOtherCondition THEN Column4 
    END AS CustomColumn 
FROM ... 

इस के साथ समस्या यह देख रहे हैं समझ पूर्वता हो जाता है के लिए अनुमति देता लायक है; क्या होता है जब दोनों स्थितियां सच होती हैं?एसक्यूएल में केस कथन सत्य के पहले कथन से मान देता है, और अन्य मामलों को अनदेखा करता है, लेकिन वह व्यवहार शायद नहीं हो सकता है जो आप चाहते थे।

सी # की ताकत यह है कि कोड स्विच करना असंभव है कि दोनों मामले 1 और केस 2 एक ही समय में सच हो सकते हैं, इसलिए आपको केवल एक सही उत्तर की गारंटी है।

+0

+1 यह इंगित करने के लिए कि दो केस लेबल्स में एक ही मूल्य नहीं हो सकता –

0

जैसा कि हम सभी जानते हैं "स्विच" if पर समान कार्यक्षमता का खुलासा करता है। हम में से अधिकांश (स्वयं को शामिल करते हैं) इसे सिंटैक्स चीनी के रूप में देखते हैं - एक निश्चित switch पर मामलों का एक समूह पढ़ना आसान है, तो अगर//।/Else। लेकिन तथ्य यह है कि स्विच कोई वाक्यविन्यास चीनी नहीं है।

आपको क्या पता होना चाहिए कि switch (यह आईएल या मशीन कोड हो) के लिए उत्पन्न कोड अनुक्रमिक ifs के लिए उत्पन्न कोड के समान नहीं है। स्विच में एक अच्छा अनुकूलन है, जैसा कि @ एडी एस पहले से ही इंगित करता है, इसे लगातार समय में चलाने में सक्षम बनाता है।

+3

स्विच * निरंतर समय * कभी * * में चला सकते हैं। स्विच पूरी तरह से ** गारंटी ** ** निरंतर समय में चलाने के लिए नहीं हैं, और व्यवहार में वे अक्सर नहीं करते हैं। ऐसे कई कारक हैं जो लॉगरिदमिक या रैखिक समय में स्विच चलाने का कारण बन सकते हैं। –

+0

@EricLippert, मैं एक स्विच स्टेटमेंट द्वारा उत्पन्न आईएल को देख रहा था और पाया कि मेरे दिमाग में अनुकूलन वास्तव में नहीं हैं - मैंने आश्चर्यचकित होना शुरू किया कि ओपी क्या पूछ रहा था - यह समझ में आया। क्या मैं इस मामले के बारे में ब्लॉग पोस्ट सुझा सकता हूं? :) –

2

सामान्य रूप से, माइक्रोसॉफ्ट सी # कंपाइलर में कोई विस्तार बिंदु नहीं है, जहां तक ​​मुझे पता है (और यहां तक ​​कि रोज़लिन भी इसे बदलने की योजना नहीं बना रहा है)। लेकिन कुछ भी आपको अपने स्वयं के सी # कंपाइलर को लिखने से रोक नहीं रहा है, या अधिक वास्तविकता से, ओपन सोर्स Mono C# compiler को संशोधित करने से रोक रहा है।

किसी भी मामले में, मुझे लगता है कि यह इसके लायक होने की तुलना में अधिक परेशानी है।

लेकिन हो सकता है आप आप कुछ भाषा में पहले से मौजूद क्या का उपयोग कर करना चाहते हैं कर सकते हैं, अर्थात्, lambdas और विधि कॉल, एक "धाराप्रवाह स्विच" के रूप में:

Switch.Value(true) 
    .Case(() => Foo(),() => Console.WriteLine("foo")) 
    .Case(() => Bar() == 2,() => Console.WriteLine("bar == 2")); 

आप बुरा है कि सभी नहीं है, तो हालत मूल्यों का मूल्यांकन हर बार किया जाएगा, आप इसे थोड़ा सा सरल बनाते हैं:

Switch.Value(true) 
    .Case(Foo(),() => Console.WriteLine("foo")) 
    .Case(Bar() == 2,() => Console.WriteLine("bar == 2")); 
संबंधित मुद्दे