2009-07-07 11 views
19

मेरे पास कक्षा A है और एक वर्ग B है जो कक्षा A प्राप्त करता है और इसे कुछ और क्षेत्रों के साथ बढ़ाता है।ऑब्जेक्ट को उप-वर्ग ऑब्जेक्ट में "क्लोन" कैसे करें?

एक वस्तु प्रकार A की a के बाद, मैं प्रकार B का एक उद्देश्य b कि सभी डेटा है कि आपत्ति a निहित होता है कैसे बना सकते हैं?

मैंने a.MemberwiseClone() की कोशिश की है, लेकिन यह मुझे केवल एक और प्रकार A ऑब्जेक्ट देता है। और मैं AB में नहीं डाल सकता क्योंकि विरासत संबंध केवल विपरीत कलाकारों को अनुमति देता है।

ऐसा करने का सही तरीका क्या है?

+0

उत्तर के लिए धन्यवाद। मैं इसके लिए एक स्वचालित तरीका ढूंढ रहा था लेकिन आप सुझाव दे रहे हैं कि ऐसा कोई नहीं है। :( – Vizu

+1

दुर्भाग्य से, नहीं। आप एक निर्माता या कुछ फार्म का एक कारखाना विधि जोड़ने की आवश्यकता होगी। –

+0

@Vizu जो विधि आप को अपनाने की थी, मैं भी चाहता हूँ कुछ इसी तरह, कृपया यहाँ डाल आप इसे –

उत्तर

8

एक विकल्प क्लास B कि एक तर्क के रूप में एक वर्ग एक लेता है के लिए एक निर्माता को जोड़ने के लिए है यह स्वचालित रूप से भाषा में बनाया करने का कोई साधन नहीं है ...।

तो फिर तुम कर सकता है:

B newB = new B(myA); 

निर्माता बस, जरूरत भर में प्रासंगिक डेटा कॉपी कर सकते हैं कि इस मामले में।

+0

यह संभव है कि एक उप वर्ग को सुपर क्लास में कॉपी करें, जिसमें कुछ समान फ़ील्ड हैं –

1

बी में एक ctor बनाएँ जो किसी को प्रकार ए के ऑब्जेक्ट में पास करने की अनुमति देता है, फिर ए फ़ील्ड कॉपी करें और बी फ़ील्ड को उचित के रूप में सेट करें।

0

आप बेस बी में कक्षा बी पर एक कनवर्ट विधि बना सकते हैं।

public ClassB Convert(ClassA a) 
{ 
    ClassB b = new ClassB(); 
    // Set the properties 
    return b; 
} 

तुम भी एक निर्माता ClassB ClassA की एक वस्तु में ले के लिए हो सकता था।

11

मैं ए में एक प्रतिलिपि निर्माता जोड़ूंगा, और उसके बाद बी के लिए एक नया कन्स्ट्रक्टर जोड़ूंगा जो ए का उदाहरण लेता है और इसे बेस की कॉपी कन्स्ट्रक्टर में भेज देता है।

+2

स्वीकृत उत्तर वह है जो मैंने हमेशा किया है, लेकिन इस मोड़ सरल और सुरुचिपूर्ण है। – JMD

0

नहीं, आप ऐसा नहीं कर सकते हैं। इसे प्राप्त करने का एक तरीका कक्षा बी पर एक कन्स्ट्रक्टर जोड़ना है जो प्रकार बी के पैरामीटर को स्वीकार करता है, और मैन्युअल रूप से डेटा जोड़ता है।

public class B 
{ 
    public B(A a) 
    { 
    this.Foo = a.foo; 
    this.Bar = a.bar; 
    // add some B-specific data here 
    } 
} 
+3

मैं सहमत नहीं है कि आप एक है कि एक बी रिटर्न पर एक क्लोन() विधि होनी चाहिए, क्योंकि यह एक सर्कुलर निर्भरता परिचय देता है। –

+0

मैं कक्षा बी के लिए निर्माता के साथ सहमत हैं, लेकिन आप CloneToB की जरूरत क्यों() विधि? –

+0

ehm हाँ आप सही हैं, मुझे उस विधि को शामिल नहीं करना चाहिए था। मैंने इसे शामिल किया क्योंकि पोस्टर ने सदस्य WiseCl का उल्लेख किया एक()। वैसे भी, यह कोड अच्छा नहीं है और मैं इसे हटा दूंगा। धन्यवाद। – Razzie

2

Factory Method Pattern का उपयोग करना::

private abstract class A 
    { 
     public int A1 { get; set; } 

     public abstract A CreateInstance(); 

     public virtual A Clone() 
     { 
      var instance = CreateInstance(); 
      instance.A1 = A1; 
      return instance; 
     } 
    } 

    private class B : A 
    { 
     public int A3 { get; set; } 

     public override A CreateInstance() 
     { 
      return new B(); 
     } 

     public override A Clone() 
     { 
      var result = (B) base.Clone(); 
      result.A3 = A3; 
      return result; 
     } 
    } 

    private static void Main(string[] args) 
    { 
     var b = new B() { A1 = 1, A3 = 2 }; 

     var c = b.Clone(); 
    } 
3

आप प्रतिबिंब का उपयोग करके इस लक्ष्य को हासिल कर सकते हैं

तो तुम कुछ इस तरह हो सकता था।

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

नुकसान: प्रदर्शन। प्रतिबिंब धीमा है। हम अभी भी औसत आकार के वर्गों पर मिलीसेकंड की बात कर रहे हैं।

यहाँ एक प्रतिबिंब आधारित उथले प्रति कॉपी-टू-उपवर्ग समर्थन कार्यान्वयन है, विस्तार तरीकों का उपयोग कर:

public static TOut GetShallowCopyByReflection<TOut>(this Object objIn) 
{ 
    Type inputType = objIn.GetType(); 
    Type outputType = typeof(TOut); 
    if (!outputType.Equals(inputType) && !outputType.IsSubclassOf(inputType)) throw new ArgumentException(String.Format("{0} is not a sublcass of {1}", outputType, inputType)); 
    PropertyInfo[] properties = inputType.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.FlattenHierarchy); 
    FieldInfo[] fields = inputType.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.FlattenHierarchy); 
    TOut objOut = (TOut)Activator.CreateInstance(typeof(TOut)); 
    foreach (PropertyInfo property in properties) 
    { 
     try 
     { 
      property.SetValue(objIn, property.GetValue(objIn, null), null); 
     } 
     catch (ArgumentException) { } // For Get-only-properties 
    } 
    foreach (FieldInfo field in fields) 
    { 
     field.SetValue(objOut, field.GetValue(objIn)); 
    } 
    return objOut; 
} 

इस विधि सभी की प्रतिलिपि बनाएगा - निजी और सार्वजनिक, साथ ही सभी क्षेत्रों। गुणों को संदर्भ द्वारा प्रतिलिपि बनाई जाती है, इसे एक उथली प्रतिलिपि बनाते हैं।

ईकाई परीक्षण:

[TestClass] 
public class ExtensionTests { 
    [TestMethod] 
    public void GetShallowCloneByReflection_PropsAndFields() 
    { 
     var uri = new Uri("http://www.stackoverflow.com"); 
     var source = new TestClassParent(); 
     source.SomePublicString = "Pu"; 
     source.SomePrivateString = "Pr"; 
     source.SomeInternalString = "I"; 
     source.SomeIntField = 6; 
     source.SomeList = new List<Uri>() { uri }; 

     var dest = source.GetShallowCopyByReflection<TestClassChild>(); 
     Assert.AreEqual("Pu", dest.SomePublicString); 
     Assert.AreEqual("Pr", dest.SomePrivateString); 
     Assert.AreEqual("I", dest.SomeInternalString); 
     Assert.AreEqual(6, dest.SomeIntField); 
     Assert.AreSame(source.SomeList, dest.SomeList); 
     Assert.AreSame(uri, dest.SomeList[0]);    
    } 
} 

internal class TestClassParent 
{ 
    public String SomePublicString { get; set; } 
    internal String SomeInternalString { get; set; } 
    internal String SomePrivateString { get; set; } 
    public String SomeGetOnlyString { get { return "Get"; } } 
    internal List<Uri> SomeList { get; set; } 
    internal int SomeIntField; 
} 

internal class TestClassChild : TestClassParent {} 
+0

क्या औसत दर्जे का आकार माना जाता है? –

+0

@ adam-l-s Hehe अच्छा सवाल है। जब प्रदर्शन की बात आती है तो हमेशा मेरा जवाब: उपाय। यदि यह आप के लिए काफी तेज़ है, यह उपयोग करें। प्रतिबिंब सामान्य रूप से गुणों तक पहुंचने से 1000 गुना धीमा माना जाता है: http://stackoverflow.com/questions/25458/how-costly-is-net-reflection – Nilzor

0

अपने आधार वर्ग CreateObject आभासी नीचे विधि जोड़ने में ...

public virtual T CreateObject<T>() 
    { 
     if (typeof(T).IsSubclassOf(this.GetType())) 
     { 
      throw new InvalidCastException(this.GetType().ToString() + " does not inherit from " + typeof(T).ToString()); 
     } 

     T ret = System.Activator.CreateInstance<T>(); 

     PropertyInfo[] propTo = ret.GetType().GetProperties(); 
     PropertyInfo[] propFrom = this.GetType().GetProperties(); 

     // for each property check whether this data item has an equivalent property 
     // and copy over the property values as neccesary. 
     foreach (PropertyInfo propT in propTo) 
     { 
      foreach (PropertyInfo propF in propFrom) 
      { 
       if (propT.Name == propF.Name) 
       { 
        propF.SetValue(ret,propF.GetValue(this)); 
        break; 
       } 
      } 
     } 

     return ret; 
    } 

तो आप सुपर वर्ग से एक वास्तविक जीवन उपवर्ग वस्तु बनाने के लिए चाहते हैं का कहना है कि बस कॉल

this.CreateObject<subclass>(); 

ऐसा करना चाहिए!

0

हालांकि किसी ने भी यह सुझाव नहीं दिया है (और यह सभी के लिए स्वीकार्य रूप से काम नहीं करेगा), यह कहा जाना चाहिए कि यदि आपके पास ऑब्जेक्ट बी बनाने का विकल्प है, तो ऑब्जेक्ट बनाने के बजाय ऑब्जेक्ट की प्रतिलिपि बी। उदाहरण के लिए, मान लें कि आप एक ही समारोह में हैं और इस कोड है:

var a = new A(); 
a.prop1 = "value"; 
a.prop2 = "value"; 
... 
// now you need a B object instance... 
var b = new B(); 
// now you need to copy a into b... 

कि पिछले टिप्पणी की कदम के बारे में चिंता करने के बजाय, बस ख के साथ शुरू और मूल्यों को निर्धारित:

var b = new B(); 
b.prop1 = "value"; 
b.prop2 = "value"; 

कृपया डॉन मुझे कम मत करो क्योंकि आपको लगता है कि उपरोक्त बेवकूफ है! मैंने कई प्रोग्रामर का सामना किया है जो अपने कोड पर इतना ध्यान केंद्रित कर रहे हैं कि उन्हें एहसास नहीं हुआ कि एक आसान समाधान उन्हें चेहरे पर देख रहा है। :)

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