2011-07-28 12 views
17

स्पष्ट रूप से, प्रतिबंधित निष्पादन क्षेत्र की गारंटी इटरेटर्स पर लागू नहीं होती है (संभवत: वे कैसे लागू की जाती हैं और सभी), लेकिन क्या यह एक बग या डिज़ाइन है? [नीचे उदाहरण देखें।]क्या सी # प्रयास करें- आखिरकार सीईआर इटरेटर में तोड़ते हैं?

यानी सीईआर पर नियमों के साथ क्या नियम हैं?

using System.Runtime.CompilerServices; 
using System.Runtime.ConstrainedExecution; 

class Program 
{ 
    static bool cerWorked; 
    static void Main(string[] args) 
    { 
     try 
     { 
      cerWorked = true; 
      foreach (var v in Iterate()) { } 
     } 
     catch { System.Console.WriteLine(cerWorked); } 
     System.Console.ReadKey(); 
    } 

    [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] 
    unsafe static void StackOverflow() 
    { 
     Big big; 
     big.Bytes[int.MaxValue - 1] = 1; 
    } 

    static System.Collections.Generic.IEnumerable<int> Iterate() 
    { 
     RuntimeHelpers.PrepareConstrainedRegions(); 
     try { cerWorked = false; yield return 5; } 
     finally { StackOverflow(); } 
    } 

    unsafe struct Big { public fixed byte Bytes[int.MaxValue]; } 
} 

(कोड ज्यादातर here से चोरी हो।)

+2

इसके लिए आपको यह देखने के लिए पहला व्यक्ति क्या लगता है ... कम से कम जहां तक ​​मैं इसके अन्य संदर्भों के लिए गुगलिंग से कह सकता हूं। –

+0

मुझे यह https://vmccontroller.svn.codeplex.com/svn/VmcController/VmcServices/DetectOpenFiles.cs कोड का स्निपेट मिला जिसमें अनसुलझा लेखक सीईआर नहीं प्राप्त कर रहा है जिसे वह सोचता है कि वह हो रहा है। –

+0

@ ब्रायन: लॉल, अच्छा। मुझे लगता है कि ऐसा कुछ ऐसा होता है जो अधिकतर लोग अक्सर उपयोग नहीं करते हैं, और जो लोग शायद पहले से ही इसके बारे में सोचा बिना सहजता से जानते हैं। बस मेरा अनुमान है, यद्यपि। – Mehrdad

उत्तर

14

ठीक है, मैं नहीं जानता कि यदि यह एक बग या सिर्फ एक वास्तव में अजीब किनारे मामला है जिसमें CERs को संभालने के लिए तैयार किया गया है नहीं कर रहे थे।

तो यहां प्रासंगिक कोड है।

private static IEnumerable<int> Iterate() 
{ 
    RuntimeHelpers.PrepareConstrainedRegions(); 
    try { cerWorked = false; yield return 5; } 
    finally { StackOverflow(); } 
} 

इस संकलित जाता है और हमें परावर्तक हम इस मिल के साथ सी # में डिकंपाइल करने का प्रयास करते हैं।

private static IEnumerable<int> Iterate() 
{ 
    RuntimeHelpers.PrepareConstrainedRegions(); 
    cerWorked = false; 
    yield return 5; 
} 

अब बस एक सेकंड प्रतीक्षा करें! परावर्तक यह सब खराब हो गया है। यह वास्तव में आईएल जैसा दिखता है।

.method private hidebysig static class [mscorlib]System.Collections.Generic.IEnumerable`1<int32> Iterate() cil managed 
{ 
    .maxstack 2 
    .locals init (
     [0] class Sandbox.Program/<Iterate>d__1 d__, 
     [1] class [mscorlib]System.Collections.Generic.IEnumerable`1<int32> enumerable) 
    L_0000: ldc.i4.s -2 
    L_0002: newobj instance void Sandbox.Program/<Iterate>d__1::.ctor(int32) 
    L_0007: stloc.0 
    L_0008: ldloc.0 
    L_0009: stloc.1 
    L_000a: br.s L_000c 
    L_000c: ldloc.1 
    L_000d: ret 
} 

है ध्यान दें कि, वास्तव में, क्या परावर्तक कहते हैं के बावजूद PrepareConstrainedRegions करने के लिए कोई कॉल। तो यह कहां छिप रहा है? खैर, यह ऑटो उत्पन्न IEnumerator की MoveNext विधि में ठीक है। इस बार परावर्तक इसे सही बनाता है।

private bool MoveNext() 
{ 
    try 
    { 
     switch (this.<>1__state) 
     { 
      case 0: 
       this.<>1__state = -1; 
       RuntimeHelpers.PrepareConstrainedRegions(); 
       this.<>1__state = 1; 
       Program.cerWorked = false; 
       this.<>2__current = 5; 
       this.<>1__state = 2; 
       return true; 

      case 2: 
       this.<>1__state = 1; 
       this.<>m__Finally2(); 
       break; 
     } 
     return false; 
    } 
    fault 
    { 
     this.System.IDisposable.Dispose(); 
    } 
} 

और यह कहां StackOverflow पर रहस्यमय तरीके से स्थानांतरित हुआ? m_Finally2() विधि के अंदर।

private void <>m__Finally2() 
{ 
    this.<>1__state = -1; 
    Program.StackOverflow(); 
} 

तो एक छोटे से अधिक बारीकी से इस परीक्षण कर सकते हैं। अब हमारे पास PrepareConstainedRegions के बाहर try ब्लॉक के अंदर कॉल है जहां यह होना चाहिए। और हमारे StackOverflow कॉल finally ब्लॉक से try ब्लॉक पर स्थानांतरित हो गया है।

documentationPrepareConstrainedRegions के अनुसार try ब्लॉक से तत्काल पहले होना चाहिए। तो धारणा यह है कि अगर कहीं और रखा गया तो यह अप्रभावी है।

लेकिन, अगर सी # कंपाइलर को वह हिस्सा मिला तो भी सही चीजें खराब हो जाएंगी क्योंकि try ब्लॉक बाधित नहीं हैं। केवल catch, finally, और fault ब्लॉक हैं। और अंदाज लगाइये क्या? StackOverflow कॉल finally ब्लॉक से try ब्लॉक पर ले जाया गया है!

+0

+1, अच्छा जवाब, लेकिन 'गलती' ब्लॉक क्या है? ** संपादित करें: ** कभी भी यह ध्यान न दें कि यह [उपज] से संबंधित कुछ है (http://startbigthinksmall.wordpress.com/2008/06/09/behind-the-scenes-of-the-c-yield-keyword/) –

+1

@ जलाल: नहीं, यह उपज से संबंधित * नहीं * है। यह बहुत ज्यादा है 'पकड़ो {... फेंक; } ', अतिरिक्त 'फेंक' कथन के बिना। (चूंकि वे काफी समान हैं, यह सी # की विशेषता नहीं है।) – Mehrdad

+1

@ जलाल ए गलती ब्लॉक आखिरकार ब्लॉक की तरह है, लेकिन जब केवल अपवाद के कारण नियंत्रण छोड़ देता है तो केवल तब चलता है। [यहां कुछ और है।] (Http://www.simple-talk.com/community/blogs/simonc/archive/2011/02/09/99250.aspx) संकलक इसके कार्यान्वयन में _ _ एक गणितीय राज्य मशीन, लेकिन यह उपज कीवर्ड के लिए विशिष्ट नहीं है। –

संबंधित मुद्दे