2009-02-20 5 views
10

में विभिन्न प्रकार की वस्तुओं के बीच गहरी प्रतिलिपि करने के लिए। ऑब्जेक्टवी 2 ऑब्जेक्टवी 1 के लिए एक अलग नम्सस्पेस में है। टेम्पलेट ClassV1 और ClassV2 के बीचमैं कैसे एक आवश्यकता क्षेत्र नाम से ObjectV1 और ObjectV2 के बीच क्षेत्र मूल्यों और बच्चे संग्रह में से सभी को मैप करने के लिए है सी # नेट

Inheritence के रूप में इन 2 वर्गों स्वतंत्र रूप से विकसित करने की जरूरत है रियायती किया गया है। मैंने सामान्य गुणों के मानचित्रण को निष्पादित करने के लिए दोनों प्रतिबिंब (जो धीमा है) और द्विआधारी क्रमिकरण (जो भी धीमा है) का उपयोग करने पर विचार किया है।

क्या कोई पसंदीदा दृष्टिकोण है? क्या कोई अन्य विकल्प हैं? गति एक समस्या है

+2

प्रतिबिंब-आधारित दृष्टिकोण पर कुछ वास्तविक मीट्रिक प्राप्त करें। आप पाते हैं कि असली दुनिया का प्रदर्शन पूरी तरह से पर्याप्त है - मैंने किया! यदि नहीं, तो क्रिस बल्लार्ड ने जिस तरह से सुझाव दिया ... – kpollock

उत्तर

6

हर बार प्रतिबिंब का उपयोग करने के लिए एक विकल्प के रूप में, आप जो गतिशील Reflection.Emit का उपयोग कर प्रतिलिपि तरीकों बनाता है एक सहायक वर्ग बना सकते हैं - इसका मतलब यह होगा कि आप केवल प्रदर्शन स्टार्टअप पर हिट मिलता है। यह आपको लचीलापन और प्रदर्शन का संयोजन दे सकता है जो आपको चाहिए।

प्रतिबिंब के रूप में। प्रवेश काफी गुंजाइश है, मैं this परावर्तक एडिन की जांच करने का सुझाव दूंगा, जो इस तरह के कोड के निर्माण के लिए शानदार है।

0

हैं, तो आप तरीकों को अपने आप में क्लोन के तरीकों को लागू करना चाहिए।

+0

अच्छा विचार है, लेकिन यह उन वर्गों के बीच निर्भरता पेश करता है जिन्हें मैं टालने की कोशिश कर रहा हूं। धन्यवाद। –

+0

जरूरी नहीं है। आप राज्य को एक सामान्य प्रारूप में क्लोन कर सकते हैं। कक्षाओं को सिर्फ सामान्य प्रोटोकॉल से अवगत होना होगा। –

4

यह नेट का कौन-सा संस्करण है?

उथले प्रतिलिपि के लिए:

3.5 में, आप पूर्व संकलन कर सकते हैं एक Expression यह करने के लिए। 2.0 में, आप HyperDescriptor का उपयोग करने के लिए बहुत आसानी से उपयोग कर सकते हैं। दोनों बड़े पैमाने पर प्रतिबिंब प्रदर्शन करेंगे। PropertyCopy -

वहाँ

MiscUtil में Expression दृष्टिकोण का एक पूर्व डिब्बाबंद दिया गया है:

DestType clone = PropertyCopy<DestType>.CopyFrom(original); 

(अंत उथले)

BinaryFormatter (प्रश्न में) एक विकल्प यहाँ नहीं है - यह मूल और गंतव्य प्रकार अलग होने के बाद से काम नहीं करेगा। डेटा अनुबंध आधारित है, XmlSerializer या DataContractSerializer काम करेगा अगर सभी अनुबंध-नाम से मेल है, लेकिन दो (उथले) विकल्प ऊपर तेज ज्यादा हो सकता है अगर वे संभव हो रहे हैं।

इसके अलावा - अपने प्रकार के आम क्रमबद्धता विशेषताएं (XmlType या DataContract), तो protobuf-netकर सकते हैं (कुछ मामलों में) आप के लिए एक गहरे कॉपी/परिवर्तन प्रकार है के साथ चिह्नित कर रहे हैं:

DestType clone = Serializer.ChangeType<OriginalType, DestType>(original); 

लेकिन यह बहुत समान स्कीमा वाले प्रकारों पर निर्भर करता है (वास्तव में, यह नामों का उपयोग नहीं करता है, यह विशेषताओं पर स्पष्ट "ऑर्डर" आदि का उपयोग करता है)

+0

क्या आप कुछ पूर्व-संकलित अभिव्यक्ति सामग्री और हाइपरडिस्क्रिप्टर को कैसे करें, इस पर कुछ कोड उदाहरण दे सकते हैं? – Svish

+0

मैंने प्रॉपर्टी कॉपी के लिए 1-लाइनर जोड़ा है, लेकिन चेतावनी (अपडेटेड): यह * उथले * प्रतिलिपि करेगा। इसे गहरी प्रतिलिपि करने के लिए कुछ प्रयासों की आवश्यकता होगी (वास्तव में, गहरी प्रतिलिपि हमेशा संभव नहीं होती है)। –

1

यदि गति कोई समस्या है तो आप प्रतिबिंब प्रक्रिया ऑफ़लाइन ले सकते हैं और कॉम के मैपिंग के लिए कोड उत्पन्न करें मोन गुण। आप लाइटवेट कोड जेनरेशन या संकलन के लिए सी # कोड बनाकर पूरी तरह ऑफलाइन का उपयोग करके रनटाइम पर ऐसा कर सकते हैं।

1

यदि आप गंतव्य ऑब्जेक्ट की तत्कालता को नियंत्रित करते हैं, तो जावास्क्रिप्टसेरियलाइज़र का उपयोग करने का प्रयास करें। यह किसी भी प्रकार की जानकारी थूकता नहीं है।

new JavaScriptSerializer().Serialize(new NamespaceA.Person{Id = 1, Name = "A"}) 

रिटर्न

{Id: 1, Name: "A"} 

इस यह एक ही संपत्ति नाम के साथ किसी भी वर्ग deserialize करने के लिए संभव होना चाहिए से।

2

यहाँ एक समाधान है जो मुझे बनाया है:

 /// <summary> 
     /// Copies the data of one object to another. The target object gets properties of the first. 
     /// Any matching properties (by name) are written to the target. 
     /// </summary> 
     /// <param name="source">The source object to copy from</param> 
     /// <param name="target">The target object to copy to</param> 
     public static void CopyObjectData(object source, object target) 
     { 
      CopyObjectData(source, target, String.Empty, BindingFlags.Public | BindingFlags.Instance); 
     } 

     /// <summary> 
     /// Copies the data of one object to another. The target object gets properties of the first. 
     /// Any matching properties (by name) are written to the target. 
     /// </summary> 
     /// <param name="source">The source object to copy from</param> 
     /// <param name="target">The target object to copy to</param> 
     /// <param name="excludedProperties">A comma delimited list of properties that should not be copied</param> 
     /// <param name="memberAccess">Reflection binding access</param> 
     public static void CopyObjectData(object source, object target, string excludedProperties, BindingFlags memberAccess) 
     { 
      string[] excluded = null; 
      if (!string.IsNullOrEmpty(excludedProperties)) 
      { 
       excluded = excludedProperties.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries); 
      } 

      MemberInfo[] miT = target.GetType().GetMembers(memberAccess); 
      foreach (MemberInfo Field in miT) 
      { 
       string name = Field.Name; 

       // Skip over excluded properties 
       if (string.IsNullOrEmpty(excludedProperties) == false 
        && excluded.Contains(name)) 
       { 
        continue; 
       } 


       if (Field.MemberType == MemberTypes.Field) 
       { 
        FieldInfo sourcefield = source.GetType().GetField(name); 
        if (sourcefield == null) { continue; } 

        object SourceValue = sourcefield.GetValue(source); 
        ((FieldInfo)Field).SetValue(target, SourceValue); 
       } 
       else if (Field.MemberType == MemberTypes.Property) 
       { 
        PropertyInfo piTarget = Field as PropertyInfo; 
        PropertyInfo sourceField = source.GetType().GetProperty(name, memberAccess); 
        if (sourceField == null) { continue; } 

        if (piTarget.CanWrite && sourceField.CanRead) 
        { 
         object targetValue = piTarget.GetValue(target, null); 
         object sourceValue = sourceField.GetValue(source, null); 

         if (sourceValue == null) { continue; } 

         if (sourceField.PropertyType.IsArray 
          && piTarget.PropertyType.IsArray 
          && sourceValue != null) 
         { 
          CopyArray(source, target, memberAccess, piTarget, sourceField, sourceValue); 
         } 
         else 
         { 
          CopySingleData(source, target, memberAccess, piTarget, sourceField, targetValue, sourceValue); 
         } 
        } 
       } 
      } 
     } 

     private static void CopySingleData(object source, object target, BindingFlags memberAccess, PropertyInfo piTarget, PropertyInfo sourceField, object targetValue, object sourceValue) 
     { 
      //instantiate target if needed 
      if (targetValue == null 
       && piTarget.PropertyType.IsValueType == false 
       && piTarget.PropertyType != typeof(string)) 
      { 
       if (piTarget.PropertyType.IsArray) 
       { 
        targetValue = Activator.CreateInstance(piTarget.PropertyType.GetElementType()); 
       } 
       else 
       { 
        targetValue = Activator.CreateInstance(piTarget.PropertyType); 
       } 
      } 

      if (piTarget.PropertyType.IsValueType == false 
       && piTarget.PropertyType != typeof(string)) 
      { 
       CopyObjectData(sourceValue, targetValue, "", memberAccess); 
       piTarget.SetValue(target, targetValue, null); 
      } 
      else 
      { 
       if (piTarget.PropertyType.FullName == sourceField.PropertyType.FullName) 
       { 
        object tempSourceValue = sourceField.GetValue(source, null); 
        piTarget.SetValue(target, tempSourceValue, null); 
       } 
       else 
       { 
        CopyObjectData(piTarget, target, "", memberAccess); 
       } 
      } 
     } 

     private static void CopyArray(object source, object target, BindingFlags memberAccess, PropertyInfo piTarget, PropertyInfo sourceField, object sourceValue) 
     { 
      int sourceLength = (int)sourceValue.GetType().InvokeMember("Length", BindingFlags.GetProperty, null, sourceValue, null); 
      Array targetArray = Array.CreateInstance(piTarget.PropertyType.GetElementType(), sourceLength); 
      Array array = (Array)sourceField.GetValue(source, null); 

      for (int i = 0; i < array.Length; i++) 
      { 
       object o = array.GetValue(i); 
       object tempTarget = Activator.CreateInstance(piTarget.PropertyType.GetElementType()); 
       CopyObjectData(o, tempTarget, "", memberAccess); 
       targetArray.SetValue(tempTarget, i); 
      } 
      piTarget.SetValue(target, targetArray, null); 
     } 
+0

अरे वहाँ, मेरे पास आपके दिलचस्प स्निपेट के बारे में एक प्रश्न है। आप एक ऑब्जेक्ट को एक नल लक्ष्य के भीतर डुप्लिकेट करने का प्रबंधन कैसे करेंगे? अगर मैं कोशिश करता हूं तो मुझे अपवाद मिलता है। –

3

आप AutoMapper पर एक नज़र लेने के लिए चाहते हो सकता है, एक पुस्तकालय जो वस्तुओं के बीच मूल्यों को कॉपी में माहिर हैं। यह कॉन्फ़िगरेशन पर सम्मेलन का उपयोग करता है, इसलिए यदि गुणों में वास्तव में समान नाम हैं तो यह आपके लिए लगभग सभी काम करेगा।

+0

मेरी इच्छा है कि मैं +2 या +3 कर सकता हूं :) – jao

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