2012-12-19 19 views
16

मैं अपनी डब्ल्यूसीएफ डेटा सेवा में जेसन.NET का उपयोग कर रहा हूं।कन्स्ट्रक्टर को कॉल किए बिना कक्षा को बेकार कैसे करें?

यहाँ मेरी क्लास है (सरलीकृत):

[DataContract] 
public class Component 
{ 
    public Component() 
    { 
     // I'm doing some magic here. 
    } 
} 

मुझे लगता है कि वर्ग कैसे deserialize कर सकते हैं एक निर्माता JsonConvert.DeserializeObject का उपयोग कर लागू बिना?

क्षमा करें अगर स्पष्ट नहीं है, तो प्रश्न पूछने के लिए स्वतंत्र महसूस करें।

+0

संभव नहीं AFAIK। एक उदाहरण बनाते समय एक कन्स्ट्रक्टर हमेशा निष्पादित किया जाता है। – Maarten

+3

@ मार्टन http://msdn.microsoft.com/en-us/library/system.runtime.serialization.formatterservices.getsafeuninitializedobject.aspx –

+0

Thanx! मैंने आज कुछ सीखा :-) – Maarten

उत्तर

7
  1. आप एक वर्ग है कि CustomCreationConverter से विरासत बना सकते हैं और FormatterServices.GetSafeUninitializedObject का उपयोग अपने वस्तु बनाने के लिए कर सकता है। यह कन्स्ट्रक्टर को बुलाता है।

    कस्टमक्रिएशन कनवर्टर here के बारे में अधिक जानकारी।

  2. एक वर्ग पर [JsonObject(MemberSerialization.Fields)] रखने Json.NET FormatterServices.GetSafeUninitializedObject डिफ़ॉल्ट रूप से उपयोग (हालांकि फील्ड्स मोड भी सार्वजनिक/निजी के बजाय सार्वजनिक गुण है जो आप नहीं चाहते हो सकता है क्षेत्रों को क्रमानुसार जाएगा) कर देगा।

  3. उस तर्क को ले जाएं जिसे आप डिफ़ॉल्ट कन्स्ट्रक्टर के बाहर नहीं चलाना चाहते हैं।

+0

बहुत बहुत धन्यवाद! किसी कारण से, जब मैंने '[JsonObject (सदस्य Serialization.Fields)] 'की कोशिश की, तो उसने' StackOverflowException' का उत्पादन किया। तो मैं पहले संस्करण पसंद करते हैं। क्या आप कृपया मुझे बता सकते हैं - क्या कई वर्गों के लिए सार्वभौमिक 'कस्टमक्रिएशन कनवर्टर' बनाने का कोई तरीका है? –

+1

कस्टमक्रिएशन कनवर्टर स्रोत कोड कॉपी करें और जो भी आप चाहते हैं उसे करने के लिए संशोधित करें। यह सिर्फ जेसन कनवर्टर से प्राप्त होता है - https://github.com/JamesNK/Newtonsoft.Json/blob/master/Src/Newtonsoft.Json/Converters/CustomCreationConverter.cs –

10

एक निर्माता हमेशा से आह्वान किया जाता है। मेरे पास आमतौर पर दो रचनाकार होते हैं। क्रमबद्धता के लिए एक (डिफ़ॉल्ट निर्माता) और सभी "नियमित" कोड के लिए एक:

[DataContract] 
public class Component 
{ 
    // for JSON.NET 
    protected Component() 
    { 
    } 

    public Component(allMandatoryFieldsHere) 
    { 
     // I'm doing some magic here. 
    } 
} 

कि जिस तरह से मैं भी सुनिश्चित करें कि देव सभी जानकारी जो आवश्यक हैं निर्दिष्ट कर सकते हैं।

हालांकि, मैं वास्तव में अनुशंसा नहीं करता कि आप डीटीओ के अलावा कुछ भी उपयोग करते हैं, जबकि सूचनाओं को स्थानांतरित करते समय अन्यथा आपकी वस्तुओं के encapsulation को रोकने के लिए संभव है (कोई भी किसी भी क्षेत्र के साथ किसी भी क्षेत्र को प्रारंभ कर सकता है)। कुंआ। यदि आप एनीमिक मॉडल के अलावा कुछ भी उपयोग करते हैं।

FormatterServices.GetSafeUninitializedObject का उपयोग करना इसलिए एक बदसूरत कामकाज है, क्योंकि कोई भी यह नहीं बता सकता कि आप सभी वस्तुओं को एक अनियमित तरीके से बनाते हैं। एक कारण के लिए कन्स्ट्रक्टर प्रारंभिक है। यह बेहतर है कि कक्षाएं बता सकती हैं कि मैंने "सीरियलाइजेशन" कन्स्ट्रक्टर प्रदान करके असली कन्स्ट्रक्टर को कॉल करना ठीक नहीं है जैसा कि मैंने सुझाव दिया था।

+0

लेकिन जहां तक ​​मुझे पता है, डिफ़ॉल्ट 'DataContractJsonSerializer' एक कन्स्ट्रक्टर का आह्वान नहीं करता है। –

+0

@ इगोरशस्टिन: यही कारण है कि आपको केवल डीटीओ के साथ इसका उपयोग करना चाहिए। JSON.NET अधिक अच्छी तरह से व्यवहार कर रहा है। – jgauffin

0

अक्रमांकन पर निर्माता कॉल से बचने के लिए सबसे अच्छा विकल्प विशेष अनुबंध समाधानकर्ता निर्माता JsonConstructor विशेषता के साथ चिह्नित बिना सभी वर्गों के लिए निर्माता समारोह को ओवरराइड करता है कि बनाने के लिए है। इस तरह से आप अभी भी JSON.NET को कन्स्ट्रक्टर को कॉल करने के लिए मजबूर कर सकते हैं यदि आपको वास्तव में इसकी आवश्यकता है, लेकिन अन्य सभी वर्गों को .NET में मानक डेटाकंट्रैक सीरियलाइज़र में बहुत अधिक बनाया जाएगा। यहाँ कोड है:

/// <summary> 
/// Special contract resolver to create objects bypassing constructor call. 
/// </summary> 
public class NoConstructorCreationContractResolver : DefaultContractResolver 
{ 
    /// <summary> 
    /// Creates a <see cref="T:Newtonsoft.Json.Serialization.JsonObjectContract"/> for the given type. 
    /// </summary> 
    /// <param name="objectType">Type of the object.</param> 
    /// <returns> 
    /// A <see cref="T:Newtonsoft.Json.Serialization.JsonObjectContract"/> for the given type. 
    /// </returns> 
    protected override JsonObjectContract CreateObjectContract(Type objectType) 
    { 
     // prepare contract using default resolver 
     var objectContract = base.CreateObjectContract(objectType); 

     // if type has constructor marked with JsonConstructor attribute or can't be instantiated, return default contract 
     if (objectContract.OverrideConstructor != null || objectContract.CreatedType.IsInterface || objectContract.CreatedType.IsAbstract) 
      return objectContract; 

     // prepare function to check that specified constructor parameter corresponds to non writable property on a type 
     Func<JsonProperty, bool> isParameterForNonWritableProperty = 
      parameter => 
      { 
       var propertyForParameter = objectContract.Properties.FirstOrDefault(property => property.PropertyName == parameter.PropertyName); 

       if (propertyForParameter == null) 
        return false; 

       return !propertyForParameter.Writable; 
      };     

     // if type has parameterized constructor and any of constructor parameters corresponds to non writable property, return default contract 
     // this is needed to handle special cases for types that can be initialized only via constructor, i.e. Tuple<> 
     if (objectContract.ParametrizedConstructor != null 
      && objectContract.ConstructorParameters.Any(parameter => isParameterForNonWritableProperty(parameter))) 
      return objectContract; 

     // override default creation method to create object without constructor call 
     objectContract.DefaultCreatorNonPublic = false; 
     objectContract.DefaultCreator =() => FormatterServices.GetSafeUninitializedObject(objectContract.CreatedType); 

     return objectContract; 
    } 
} 

आपको बस बस अक्रमांकन से पहले serializer सेटिंग में इस अनुबंध समाधानकर्ता निर्धारित है।

1

अन्य पहले से ही दूसरे कन्स्ट्रक्टर का उल्लेख करते हैं, लेकिन 2 विशेषताओं का उपयोग करते हुए: [जेसन कॉन्स्ट्रक्टर] और [अप्रचलित] आप इसे याद रखने के लिए मनुष्यों को छोड़ने से कहीं ज्यादा बेहतर कर सकते हैं।

public ChatMessage() 
    { 
     MessageID = ApplicationState.GetNextChatMessageID(); // An expensive call that uses up an otherwise free ID from a limited set and does disk access in the process. 
    } 


    [JsonConstructor] // This forces JsonSerializer to call it instead of the default. 
    [Obsolete("Call the default constructor. This is only for JSONserializer", true)] // To make sure that calling this from your code directly will generate a compiler error. JSONserializer can still call it because it does it via reflection. 
    public ChatMessage(bool DO_NOT_CALL_THIS) 
    { 
    } 

[जेसन कॉन्स्ट्रक्टर] जेसनएसरियलाइज़र को डिफ़ॉल्ट रूप से कॉल करने के लिए मजबूर करता है।
[अप्रचलित ("...", सच)] यह सुनिश्चित करता है कि इसे सीधे आपके कोड से कॉल करने से एक कंपाइलर त्रुटि उत्पन्न होगी। JSONserializer अभी भी इसे कॉल कर सकता है क्योंकि यह प्रतिबिंब के माध्यम से करता है।

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

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