2009-10-07 15 views
17

निर्दिष्ट मैं वर्तमान में एक बहुत अजीब समस्या आ रही है और मैं इसे कैसे हल करने के लिए यह पता लगाने नहीं कर पा रहे।XmlSerializer प्रदर्शन जारी जब XmlRootAttribute

मुझे मिला है जटिल प्रकार जिसे मैं XmlSerializer क्लास का उपयोग करके क्रमबद्ध करने की कोशिश कर रहा हूं। यह वास्तव में ठीक काम करता है और प्रकार ठीक से serializes, लेकिन ऐसा करने में एक बहुत लंबा समय लग रहा है; ऑब्जेक्ट में डेटा के आधार पर लगभग 5 सेकंड।

कुछ प्रोफाइलिंग के बाद मैंने समस्या को कम कर दिया है - विचित्र रूप से - XmlRootializer को कॉल करते समय XmlRootAttribute निर्दिष्ट करने के लिए। Serialize। मैं ऐसा करता हूं कि संग्रह के नाम को ArrayOf से क्रमबद्ध किया जा रहा है और कुछ और सार्थक हो। एक बार जब मैं पैरामीटर को हटा देता हूं तो ऑपरेशन लगभग तुरंत होता है!

किसी भी विचार या सुझाव उत्कृष्ट होगा के रूप में मैं पूरी तरह से इस पर स्टम्प्ड रहा हूँ! जब XmlSerializers बनाने

+1

ठीक है, ऐसा लगता है कि समस्या यह है कि वें ई serialization असेंबली हर serializer उदाहरण के लिए उत्पन्न होता है अगर आप serializer के लिए एक प्रकार पैरामीटर के अलावा कुछ भी निर्दिष्ट करते हैं! यही कारण है - मुझे लगता है - मुझे इतना भयानक प्रदर्शन दिखाई दे रहा है। क्या किसी को कोई कारण पता है कि डिफ़ॉल्ट XmlSerializer ऐसा क्यों करेगा? मुझे समझ में नहीं आ रहा है कि रूट नोड नाम निर्दिष्ट करने का मतलब क्यों होगा कि कैश का उपयोग नहीं किया जा सका? – Dougc

उत्तर

23
बस किसी और ने इस समस्या में चलाता है के लिए

(मैं उदाहरण यहां हटा दिया है); , मैं का उपयोग करें तो

public static class XmlSerializerCache 
{ 
    private static readonly Dictionary<string, XmlSerializer> cache = 
          new Dictionary<string, XmlSerializer>(); 

    public static XmlSerializer Create(Type type, XmlRootAttribute root) 
    { 
     var key = String.Format(
        CultureInfo.InvariantCulture, 
        "{0}:{1}", 
        type, 
        root.ElementName); 

     if (!cache.ContainsKey(key)) 
     { 
      cache.Add(key, new XmlSerializer(type, root)); 
     } 

     return cache[key]; 
    } 
} 

बजाय डिफ़ॉल्ट XmlSerializer निर्माता है जो एक XmlRootAttribute लेता उपयोग करने के बजाय निम्नलिखित:

ऊपर जवाब और MSDN से उदाहरण के साथ सशस्त्र मैं निम्नलिखित वर्ग का उपयोग कर इस समस्या को हल करने में कामयाब
var xmlRootAttribute = new XmlRootAttribute("ExampleElement"); 
var serializer = XmlSerializerCache.Create(target.GetType(), xmlRootAttribute); 

मेरा आवेदन अब फिर से प्रदर्शन कर रहा है!

+0

+1, छोटा और मीठा। –

+6

इस पर एक मामूली मामूली अनुकूलन। यदि आप इन लुकअप में से बहुत कुछ करने जा रहे हैं, तो मान-खंड में मान प्राप्त करें। ContainsKey अधिक कुशल है यदि आप केवल यह जानना चाहते हैं कि आइटम मौजूद है, लेकिन इसे प्राप्त नहीं किया गया है, लेकिन चूंकि आप हमेशा मान वापस लेते हैं, तो प्रयास बेहतर है: http://dotnetperls.com/dictionary-lookup –

+0

फिर आप " वापसी "कथन, क्योंकि आपके पास पहले से ही चर में उदाहरण है और" कैश [कुंजी] "के माध्यम से देखने की आवश्यकता नहीं है – Sielu

18

मूल प्रश्न के अनुसरण की टिप्पणी में उल्लेख किया है, .NET विधानसभाओं का उत्सर्जन करता है, और उत्पन्न विधानसभा कैश अगर यह इन दो कंस्ट्रक्टर्स में से एक का उपयोग कर बनाया जाता है:

XmlSerializer(Type) 
XmlSerializer(Type, String) 

विधानसभाओं उत्पन्न अन्य रचनाकारों का उपयोग कैश नहीं किया जाता है, इसलिए .NET को हर बार नई असेंबली उत्पन्न करना होता है।

क्यों? इस उत्तर शायद नहीं बहुत संतोषजनक है, लेकिन परावर्तक में इस घूर रही है, तो आप देख सकते हैं कि कुंजी संग्रहीत और उत्पन्न XmlSerializer विधानसभाओं तक पहुँचने के लिए (TempAssemblyCacheKey) का इस्तेमाल किया बस एक साधारण समग्र serializable प्रकार से बनाया गया कुंजी है और (वैकल्पिक) ने अपने नाम स्थान।

इस प्रकार, SomeType के लिए एक कैश्ड XmlSerializer एक विशेष XmlRootAttribute या डिफ़ॉल्ट से एक है कि क्या यह बताने के लिए कोई तंत्र है।

तकनीकी कारणों के बारे में सोचना मुश्किल है कि कुंजी अधिक तत्वों को समायोजित नहीं कर सकती है, इसलिए शायद यह केवल एक विशेषता है कि किसी को भी लागू करने का समय नहीं था (विशेष रूप से इसमें अन्यथा स्थिर वर्गों को बदलने में शामिल होगा)।

आप इस देखा हो सकता है, लेकिन मामले में आप नहीं है, the XmlSerializer class documentation एक समाधान पर चर्चा करता है:

आप अन्य कंस्ट्रक्टर्स के किसी भी उपयोग करते हैं, एक ही विधानसभा के कई संस्करण उत्पन्न होते हैं और कभी नहीं कर रहे हैं अनलोडेड, जिसके परिणामस्वरूप स्मृति रिसाव और खराब प्रदर्शन होता है। सबसे आसान समाधान में से एक का उपयोग पहले दो रचनाकारों का उल्लेख करना है। अन्यथा, आप एक Hashtable, में विधानसभाओं के रूप में निम्नलिखित उदाहरण में दिखाया गया कैश चाहिए।

+0

उत्कृष्ट। आपकी मदद जेफ के लिए धन्यवाद। मुझे नहीं पता कि मैंने एमएसडीएन दस्तावेज क्यों नहीं पढ़ा, दोह! – Dougc

+0

क्या इस हैशटेबल का उपयोग किया जा रहा है जहां आप एक्सएमएल सीरिएलाइज़र पर नियंत्रण नहीं रखते हैं? मैं विशेष रूप से डब्ल्यूसीएफ सेवा संदर्भ या वेब संदर्भ में सोच रहा हूं? मेरे पास यह मुद्दा है, लेकिन मुझे इसे ठीक करने के लिए कोई रास्ता नहीं दिख रहा है ...! – harrisonmeister

0

एक और जटिल कार्यान्वयन here समझाया गया है। हालांकि परियोजना अब सक्रिय नहीं है।

प्रासंगिक वर्गों यहां दिखाई दे रहे हैं: http://mvpxml.codeplex.com/SourceControl/changeset/view/64156#258382

विशेष रूप से, निम्नलिखित समारोह उत्पन्न करने के लिए एक अद्वितीय कुंजी उपयोगी हो सकता है:

public static string MakeKey(Type type 
    , XmlAttributeOverrides overrides 
    , Type[] types 
    , XmlRootAttribute root 
    , String defaultNamespace) { 
    StringBuilder keyBuilder = new StringBuilder(); 
    keyBuilder.Append(type.FullName); 
    keyBuilder.Append("??"); 
    keyBuilder.Append(SignatureExtractor.GetOverridesSignature(overrides)); 
    keyBuilder.Append("??"); 
    keyBuilder.Append(SignatureExtractor.GetTypeArraySignature(types)); 
    keyBuilder.Append("??"); 
    keyBuilder.Append(SignatureExtractor.GetXmlRootSignature(root)); 
    keyBuilder.Append("??"); 
    keyBuilder.Append(SignatureExtractor.GetDefaultNamespaceSignature(defaultNamespace)); 

    return keyBuilder.ToString(); 
} 
1

बस कुछ इस तरह लागू करने के लिए था और एक से थोड़ा इस्तेमाल किया एक सुविधा अधिभार के साथ @ डौग के समाधान का अधिक अनुकूलित संस्करण:

public static class XmlSerializerCache { 
    private static readonly Dictionary<string, XmlSerializer> cache = new Dictionary<string, XmlSerializer>(); 

    public static XmlSerializer Get(Type type, XmlRootAttribute root) { 
     var key = String.Format("{0}:{1}", type, root.ElementName); 
     XmlSerializer ser; 
     if (!cache.TryGetValue(key, out ser)) { 
      ser = new XmlSerializer(type, root); 
      cache.Add(key, ser); 
     } 
     return ser; 
    } 

    public static XmlSerializer Get(Type type, string root) { 
     return Get(type, new XmlRootAttribute(root)); 
    } 
}