2011-10-25 11 views
77

मैं इस के समान कोड का उपयोग कर एक विशिष्ट इंटरफ़ेस को लागू प्रकार के लिए एक विधानसभा स्कैन करने के लिए कोशिश कर रहा हूँ:जब Assembly.GetTypes() कॉल ReflectionTypeLoadException को रोकने के लिए

public List<Type> FindTypesImplementing<T>(string assemblyPath) 
{ 
    var matchingTypes = new List<Type>(); 
    var asm = Assembly.LoadFrom(assemblyPath); 
    foreach (var t in asm.GetTypes()) 
    { 
     if (typeof(T).IsAssignableFrom(t)) 
      matchingTypes.Add(t); 
    } 
    return matchingTypes; 
} 

मेरे समस्या है, कि मैं एक ReflectionTypeLoadException मिल कुछ मामलों में asm.GetTypes() पर कॉल करते समय, उदाहरण के लिए यदि असेंबली में ऐसे असेंबली का संदर्भ देने वाले प्रकार होते हैं जो वर्तमान में उपलब्ध नहीं हैं।

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

सवाल यह है: क्या किसी भी तरह से अपवाद का कारण बनने वाले प्रकारों को छोड़ना/अनदेखा करना संभव है लेकिन असेंबली में निहित अन्य प्रकारों को अभी भी संसाधित करना संभव है?

+1

यह जो भी आप खोज रहे हैं उससे अधिक पुनर्लेखन हो सकता है, लेकिन एमईएफ आपको समान कार्यक्षमता देता है। बस अपने प्रत्येक वर्ग को एक [निर्यात] टैग के साथ चिह्नित करें जो यह लागू इंटरफ़ेस निर्दिष्ट करता है। फिर आप उस समय उन इंटरफेस को आयात कर सकते हैं जिन्हें आप रुचि रखते हैं। –

+0

@Drew, आपकी टिप्पणी के लिए धन्यवाद। मैं एमईएफ का उपयोग करने के बारे में सोच रहा था, लेकिन यह देखना चाहता था कि कोई दूसरा, सस्ता समाधान है या नहीं। – M4N

+0

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

उत्तर

101

एक काफी बुरा तरीका होगा:

Type[] types; 
try 
{ 
    types = asm.GetTypes(); 
} 
catch (ReflectionTypeLoadException e) 
{ 
    types = e.Types; 
} 
foreach (var t in types.Where(t => t != null)) 
{ 
    ... 
} 

यह निश्चित रूप से इस यद्यपि क्या करना है के लिए कष्टप्रद है। - मैं इसे वहाँ अपने आप को किया जा रहा है पर बहुत उत्सुक नहीं हूँ

public static IEnumerable<Type> GetLoadableTypes(this Assembly assembly) 
{ 
    // TODO: Argument validation 
    try 
    { 
     return assembly.GetTypes(); 
    } 
    catch (ReflectionTypeLoadException e) 
    { 
     return e.Types.Where(t => t != null); 
    } 
} 

आप अच्छी तरह से पकड़ ब्लॉक से बाहर return बयान स्थानांतरित करने के लिए इच्छा हो सकती है: आप "ग्राहक" कोड में यह अच्छा बनाने के लिए एक विस्तार विधि का उपयोग कर सकता है , लेकिन यह शायद है सबसे कम कोड ...

+2

धन्यवाद, यह एक समाधान प्रतीत होता है (और मैं सहमत हूं, यह एक साफ समाधान प्रतीत नहीं होता है)। – M4N

+3

अपवाद में उजागर किए गए प्रकारों की सूची का उपयोग करने का प्रयास करते समय इस समाधान में अभी भी समस्याएं हैं। टाइप लोड अपवाद के लिए जो कुछ भी कारण है, FileNotFound, BadImage, आदि, अभी भी जारी किए गए प्रकारों के हर एक्सेस पर फेंक देगा। – sweetfa

+0

@sweetfa: हाँ, यह बहुत सीमित है - लेकिन अगर ओपी को सिर्फ नाम ढूंढने की ज़रूरत है, उदाहरण के लिए, यह ठीक होना चाहिए। –

3

क्या आपने Assembly.ReflectionOnlyLoad पर विचार किया है? आप जो करने की कोशिश कर रहे हैं उसे ध्यान में रखते हुए, यह पर्याप्त हो सकता है।

+1

हां मैंने इसे माना था। लेकिन मैंने इसका उपयोग नहीं किया क्योंकि अन्यथा मुझे किसी भी निर्भरता को मैन्युअल रूप से लोड करना होगा। इसके अलावा कोड ReflectionOnlyLoad के साथ निष्पादन योग्य नहीं होगा (आपके द्वारा लिंक किए गए पृष्ठ पर टिप्पणियां अनुभाग देखें)। – M4N

16

हालांकि ऐसा लगता है कि कुछ बिंदु पर ReflectionTypeLoadException प्राप्त किए बिना कुछ भी नहीं किया जा सकता है, ऊपर दिए गए उत्तरों सीमित हैं कि अपवाद से प्रदान किए गए प्रकारों का उपयोग करने के किसी भी प्रयास को अभी भी मूल समस्या के साथ समस्या होगी जो प्रकार को लोड करने में विफल।

इस पर काबू पाने के लिए निम्नलिखित कोड असेंबली के भीतर स्थित लोगों को प्रकार सीमित करता है और भविष्य की सूची को और प्रतिबंधित करने की भविष्यवाणी करता है।

/// <summary> 
    /// Get the types within the assembly that match the predicate. 
    /// <para>for example, to get all types within a namespace</para> 
    /// <para> typeof(SomeClassInAssemblyYouWant).Assembly.GetMatchingTypesInAssembly(item => "MyNamespace".Equals(item.Namespace))</para> 
    /// </summary> 
    /// <param name="assembly">The assembly to search</param> 
    /// <param name="predicate">The predicate query to match against</param> 
    /// <returns>The collection of types within the assembly that match the predicate</returns> 
    public static ICollection<Type> GetMatchingTypesInAssembly(this Assembly assembly, Predicate<Type> predicate) 
    { 
     ICollection<Type> types = new List<Type>(); 
     try 
     { 
      types = assembly.GetTypes().Where(i => i != null && predicate(i) && i.Assembly == assembly).ToList(); 
     } 
     catch (ReflectionTypeLoadException ex) 
     { 
      foreach (Type theType in ex.Types) 
      { 
       try 
       { 
        if (theType != null && predicate(theType) && theType.Assembly == assembly) 
         types.Add(theType); 
       } 
       // This exception list is not exhaustive, modify to suit any reasons 
       // you find for failure to parse a single assembly 
       catch (BadImageFormatException) 
       { 
        // Type not in this assembly - reference to elsewhere ignored 
       } 
      } 
     } 
     return types; 
    } 
1

मेरे मामले में, वही समस्या एप्लिकेशन फ़ोल्डर में अवांछित असेंबली की उपस्थिति के कारण हुई थी। बिन फ़ोल्डर को साफ़ करने और एप्लिकेशन को पुनर्निर्माण करने का प्रयास करें।

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