2012-02-15 18 views
14

एक सहयोगी ने मुझे एक दिलचस्प कोड नमूना पारित किया है जो InvalidProgramException ("सीएलआर एक अवैध प्रोग्राम का पता चला") के साथ दुर्घटनाग्रस्त हो गया है।"सीएलआर ने एक अमान्य प्रोग्राम का पता लगाया" जब एक विस्तार विधि

समस्या जेआईटी समय पर होती है, जिसमें यह ठीक है लेकिन "अपमानजनक" रेखा के साथ विधि के ठीक पहले अपवाद फेंक दिया जाता है - मुझे लगता है कि यह JIT'd है।

प्रश्न में पंक्ति Enumerable.ToDictionary पर कॉल कर रही है और दूसरे तर्क के रूप में Func में गुज़र रही है।

यदि Func तर्क लैम्बडा के साथ पूरी तरह से निर्दिष्ट है तो यह काम करता है; अगर यह एक विधि समूह के रूप में निर्दिष्ट है, अगर विफल रहता है। निश्चित रूप से ये दोनों बराबर हैं?

यह मुझे स्टंप किया गया है (और सहयोगी जिसने इसे खोजा!) - और यह निश्चित रूप से एक जेआईटी त्रुटि की तरह लगता है।

[संपादित करें: क्षमा करें - मैं पास हो गया और दौर मामलों असफल गलत तरीके से कोड नमूने में - अब ठीक किया (वर्णन ऊपर सही था)]

किसी को भी एक व्याख्या है?

using System; 
using System.Linq; 

internal class Program 
{ 
    private static void Main(string[] args) 
    { 
     Test.Try(); 
    } 
} 

public class Test 
{ 
    public static readonly int[] integers = new[] { 1, 3, 5 }; 
    public static void Try() 
    { 
     var line = new Line { A = 3, B = 5 }; 

     // PASSES 
     var dict = integers.ToDictionary<int, int, decimal>(i => i, i => line.Compute(i)); 

     // FAILS 
     //var dict = integers.ToDictionary<int, int, decimal>(i => i, line.Compute); 

     Console.WriteLine(string.Join(" ", dict.Select(kv => kv.Key + "-" + kv.Value))); 
    } 
} 

public class Line 
{ 
    public decimal A; 
    public decimal B; 
} 

public static class SimpleCompute 
{ 
    public static decimal Compute(this Line line, int value) 
    { 
     return line.A*value + line.B; 
    } 
} 
+0

असल में, मेरे स्थानीय इंस्टॉल पर, आपकी "पास" लाइन भी –

+0

विफल हो जाती है यह मेरे (v4.0, x86) बॉक्स पर ठीक काम कर रहा है - .NET का कौन सा संस्करण आप चल रहे हैं, और क्या आर्किटेक्चर? –

+0

दिलचस्प! यदि आप एक्सटेंशन विधि को हटाते हैं (यानी सरल कॉम्प्यूट को लाइन पर एक इंस्टेंस विधि के रूप में रखें) क्या यह काम करता है? अगर मैं ऐसा करता हूं तो यह मेरे लिए करता है? –

उत्तर

15

कंपाइलर बग।

जानकारी के लिए, मेरे पास async सीटीपी है, जो संबंधित हो सकता है; csc रिपोर्ट: 4.0.30319.440

के बीच एक अंतर लगता है:

.method public hidebysig static void TryTwo() cil managed 
{ 
    .maxstack 4 
    .locals init (
     [0] class Line <>g__initLocal6) 
    L_0000: newobj instance void Line::.ctor() 
    L_0005: stloc.0 
    L_0006: ldloc.0 
    L_0007: ldc.i4.3 
    L_0008: newobj instance void [mscorlib]System.Decimal::.ctor(int32) 
    L_000d: stfld valuetype [mscorlib]System.Decimal Line::A 
    L_0012: ldloc.0 
    L_0013: ldc.i4.5 
    L_0014: newobj instance void [mscorlib]System.Decimal::.ctor(int32) 
    L_0019: stfld valuetype [mscorlib]System.Decimal Line::B 
    L_001e: ldsfld int32[] Test::integers 
    L_0023: ldsfld class [mscorlib]System.Func`2<int32, int32> Test::CS$<>9__CachedAnonymousMethodDelegate8 
    L_0028: brtrue.s L_003b 
    L_002a: ldnull 
    L_002b: ldftn int32 Test::<TryTwo>b__7(int32) 
    L_0031: newobj instance void [mscorlib]System.Func`2<int32, int32>::.ctor(object, native int) 
    L_0036: stsfld class [mscorlib]System.Func`2<int32, int32> Test::CS$<>9__CachedAnonymousMethodDelegate8 
    L_003b: ldsfld class [mscorlib]System.Func`2<int32, int32> Test::CS$<>9__CachedAnonymousMethodDelegate8 
    L_0040: call class [mscorlib]System.Collections.Generic.Dictionary`2<!!1, !!2> [System.Core]System.Linq.Enumerable::ToDictionary<int32, int32, valuetype [mscorlib]System.Decimal>(class [mscorlib]System.Collections.Generic.IEnumerable`1<!!0>, class [mscorlib]System.Func`2<!!0, !!1>, class [mscorlib]System.Func`2<!!0, !!2>) 
    L_0045: pop 
    L_0046: ldstr "TryTwo complete" 
    L_004b: call void [mscorlib]System.Console::WriteLine(string) 
    L_0050: ret 
} 

बनाम

.method public hidebysig static void TryFive() cil managed 
{ 
    .maxstack 4 
    .locals init (
     [0] class Line line, 
     [1] class [mscorlib]System.Func`2<int32, valuetype [mscorlib]System.Decimal> func, 
     [2] class Line <>g__initLocal9) 
    L_0000: newobj instance void Line::.ctor() 
    L_0005: stloc.2 
    L_0006: ldloc.2 
    L_0007: ldc.i4.3 
    L_0008: newobj instance void [mscorlib]System.Decimal::.ctor(int32) 
    L_000d: stfld valuetype [mscorlib]System.Decimal Line::A 
    L_0012: ldloc.2 
    L_0013: ldc.i4.5 
    L_0014: newobj instance void [mscorlib]System.Decimal::.ctor(int32) 
    L_0019: stfld valuetype [mscorlib]System.Decimal Line::B 
    L_001e: ldloc.2 
    L_001f: stloc.0 
    L_0020: ldloc.0 
    L_0021: ldftn valuetype [mscorlib]System.Decimal SimpleCompute::Compute(class Line, int32) 
    L_0027: newobj instance void [mscorlib]System.Func`2<int32, valuetype [mscorlib]System.Decimal>::.ctor(object, native int) 
    L_002c: stloc.1 
    L_002d: ldsfld int32[] Test::integers 
    L_0032: ldsfld class [mscorlib]System.Func`2<int32, int32> Test::CS$<>9__CachedAnonymousMethodDelegateb 
    L_0037: brtrue.s L_004a 
    L_0039: ldnull 
    L_003a: ldftn int32 Test::<TryFive>b__a(int32) 
    L_0040: newobj instance void [mscorlib]System.Func`2<int32, int32>::.ctor(object, native int) 
    L_0045: stsfld class [mscorlib]System.Func`2<int32, int32> Test::CS$<>9__CachedAnonymousMethodDelegateb 
    L_004a: ldsfld class [mscorlib]System.Func`2<int32, int32> Test::CS$<>9__CachedAnonymousMethodDelegateb 
    L_004f: ldloc.1 
    L_0050: call class [mscorlib]System.Collections.Generic.Dictionary`2<!!1, !!2> [System.Core]System.Linq.Enumerable::ToDictionary<int32, int32, valuetype [mscorlib]System.Decimal>(class [mscorlib]System.Collections.Generic.IEnumerable`1<!!0>, class [mscorlib]System.Func`2<!!0, !!1>, class [mscorlib]System.Func`2<!!0, !!2>) 
    L_0055: pop 
    L_0056: ldstr "TryFour complete" 
    L_005b: call void [mscorlib]System.Console::WriteLine(string) 
    L_0060: ret 
} 

आप में देखो, तो:

public static void TryTwo() // fails 
{ 
    var line = new Line {A = 3, B = 5}; 

    var dict = integers.ToDictionary<int, int, decimal>(i => i, line.Compute); 
    Console.WriteLine("TryTwo complete"); 
} 
public static void TryFive() // works 
{ 
    var line = new Line { A = 3, B = 5 }; 

    Func<int, decimal> func = line.Compute; 
    var dict = integers.ToDictionary<int, int, decimal>(i => i, func); 
    Console.WriteLine("TryFour complete"); 
} 

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

L_0023: ldsfld class [mscorlib]System.Func`2<int32, int32> Test::CS$<>9__CachedAnonymousMethodDelegate8 
L_0028: brtrue.s L_003b 
L_002a: ldnull 
L_002b: ldftn int32 Test::<TryTwo>b__7(int32) 
L_0031: newobj instance void [mscorlib]System.Func`2<int32, int32>::.ctor(object, native int) 
L_0036: stsfld class [mscorlib]System.Func`2<int32, int32> Test::CS$<>9__CachedAnonymousMethodDelegate8 
L_003b: ldsfld class [mscorlib]System.Func`2<int32, int32> Test::CS$<>9__CachedAnonymousMethodDelegate8 
L_0040: call class [mscorlib]System.Collections.Generic.Dictionary`2<!!1, !!2> [System.Core]System.Linq.Enumerable::ToDictionary<int32, int32, valuetype [mscorlib]System.Decimal>(class [mscorlib]System.Collections.Generic.IEnumerable`1<!!0>, class [mscorlib]System.Func`2<!!0, !!1>, class [mscorlib]System.Func`2<!!0, !!2>) 
ऊपर की

सब है "जाँच करें कि क्या कैश्ड i => i मौजूद है, अगर यह नहीं बना, तो इसे लोड"। यह दूसरे प्रतिनिधि के साथ कुछ भी नहीं करता है। नतीजतन, विधि कॉल करने के लिए ढेर पर पर्याप्त मूल्य नहीं हैं।

+0

धन्यवाद मार्क। आपका विवरण स्टैकउन्डरफ्लो त्रुटि बताता है कि पीवीवीरिफ़ ने असेंबली पर भी रिपोर्ट की है (मुझे शायद मूल प्रश्न में उल्लेख किया जाना चाहिए था)। बहुत सराहना की! –

+0

@Rob बस जोड़ने के लिए: इसे ठीक करने के लिए उचित चैनलों के साथ पास कर दिया गया है। –

+0

धन्यवाद फिर मार्क - मैं बस सोच रहा था कि इसके बारे में क्या करना है, लेकिन आपने इसे हल किया है। फिर, बहुत सराहना की। –