2011-12-25 28 views
14

मैं एक आधार वर्ग हैसी # विरासत। बेस वर्ग से व्युत्पन्न वर्ग

public class A 
{ 
    public string s1; 
    public string s2; 
} 

मैं भी एक व्युत्पन्न वर्ग है:

public class B : A 
{ 
    public string s3; 
} 

मान लीजिए मेरा कार्यक्रम वर्ग ए का एक उदाहरण बनाया

A aClassInstance = new A(); 

कुछ पैरामीटर सेट किए गए थे:

aClassInstance.s1 = "string 1"; 
aClassInstance.s2 = "string 2"; 

इस बिंदु पर मैं कक्षा बी का एक उदाहरण बनाना चाहेंगे लेकिन मैं बी चाहते हैं पहले से ही वर्ग ए के अपने उदाहरण के मूल्यों के लिए

यह काम नहीं किया:

public B bClassInstance = new B(): 
bClassInstance = (B)aClassInstance; 

न तो DID इस:

निर्मित कक्षा ए के भीतर एक क्लोन विधि

public B cloneA() {  
    A a = new A(); 
    a = (A)this.MemberwiseClone() 
    return(B)a; 
} 

वी.एस. कोड ऊपर के दोनों लेता है - बू टी मैं रन-टाइम त्रुटियों

कृपया मदद

+2

क्लोनिंग करते समय सावधान रहें - विशेष रूप से यदि आपकी कक्षा में उत्परिवर्तनीय संदर्भ प्रकार के क्षेत्र हैं। तय करें कि क्या आप एक गहरे क्लोन या उथले क्लोन चाहते हैं, और इसे दस्तावेज करें। – TrueWill

+1

सही। इस विशेष वर्ग में कोई संदर्भ नहीं है, इसलिए इसके लिए एक उथले क्लोन काम करता है। मुझे यहां रुचि रखने वाले किसी भी व्यक्ति के लिए उथले बनाम गहरे क्लोनिंग पर एक अच्छी पोस्ट मिली: http://itpksingh.blogspot.com/2009/08/shallow-copyingdeep-copyingobject.html – Sam

+0

ValueInjector का उपयोग करके एक समाधान मिला। StackOverFlow मुझे अभी तक "मेरे अपने प्रश्न का उत्तर देने" की अनुमति नहीं दे रहा है। एक बार ऐसा करने के बाद, पूर्ण विवरण पोस्ट करेंगे। – Sam

उत्तर

21

आपके पास मूल समस्या यह है कि आपको B का एक उदाहरण बनाना है (जिसमें A प्रकार के गुण शामिल हैं)। A उदाहरण क्लोन करने के लिए आपका दृष्टिकोण काम नहीं करेगा, क्योंकि इससे आपको A टाइप का उदाहरण मिल जाता है, जिसे आप B में परिवर्तित नहीं कर सकते हैं।

मैं कक्षा ए और बी के लिए रचनाकार लिखूंगा जो टाइप ए के पैरामीटर लेते हैं। कक्षा बी के निर्माता केवल अपनी बेस क्लास ए को मान देते हैं।वर्ग एक के निर्माता जानता है कि कैसे खुद को खेतों कॉपी करने के लिए:

class A { 
    public A(A copyMe) { 
     s1 = copyMe.s1; 
     ... 
    } 

class B : A { 

    public B(A aInstance) : base(aInstance) { 
    } 

} 

इसे इस तरह का उपयोग करें:

A a = new A(); 
a.s1 = "..."; 

B b = new B(a); 

संपादित

आप बदलना होगा नहीं करना चाहती जब नए फ़ील्ड या प्रोप जोड़ते समय A का कन्स्ट्रक्टर, आप गुणों की प्रतिलिपि बनाने के लिए प्रतिबिंब का उपयोग कर सकते हैं। या तो क्या आप प्रतिलिपि बनाना चाहते है, या बस सब रंगमंच की सामग्री/A के क्षेत्र कॉपी को सजाने के लिए एक कस्टम विशेषता का उपयोग करें:

public A (A copyMe) { 
    Type t = copyMe.GetType(); 
    foreach (FieldInfo fieldInf in t.GetFields()) 
    { 
     fieldInf.SetValue(this, fieldInf.GetValue(copyMe)); 
    } 
    foreach (PropertyInfo propInf in t.GetProperties()) 
    { 
     propInf.SetValue(this, propInf.GetValue(copyMe)); 
    } 
} 

मैं कोड की कोशिश की havn't, लेकिन बात स्पष्ट हो जाना चाहिए।

+0

मैं इसे अपग्रेड करने की कोशिश कर रहा हूं इसलिए प्रत्येक सदस्य को अलग-अलग कॉपी करने की आवश्यकता नहीं है: कक्षा ए { सार्वजनिक ए (एक प्रतिलिपि) { s1 = copyMe.s1; (ए) copyMe.MemberwiseClone() को मेरे कॉल ए के एक उथले क्लोन को वापस करना चाहिए जो मुझे चाहिए। अब हमें बस बी कन्स्ट्रक्टर को पास करने की ज़रूरत है ... सवाल यह है कि कैसे। दुर्भाग्य से हम ऐसा नहीं कर सकते: क्लास ए { सार्वजनिक ए (ए copyMe) { इस = (ए) copyMe.MemberwiseClone() } } ... } – Sam

+1

@Sam: समस्या यह है कि आपको टाइप बी का ऑब्जेक्ट बनाना है क्योंकि ए बी का हिस्सा है, आपको नए बी इंस्टेंस के गुणों को सेटिंग्स का एक तरीका ढूंढना होगा, जो आपके ए क्लोन ए * के हैं। दृष्टिकोण काम नहीं करेगा क्योंकि यह आपको टाइप ए का उदाहरण देता है, जहां आपको बी के उदाहरण की आवश्यकता होती है! आप क्या कर सकते हैं, ए के निर्माता में प्रतिबिंब का उपयोग करना है। मैं इसे प्रतिबिंबित करने के लिए अपना उत्तर अपडेट करूंगा। – Jan

8

आप कक्षा एक में एक सामान्य क्लोन विधि बना सकते हैं:

 public T Clone<T>() where T : A, new() { 
      return new T() { a = this.a, b = this.b}; 
    } 

या आप क्लोनिंग बढ़ाई बनाना चाहते हैं तो:

 public T Clone<T>() where T : A, new() { 
      var result = new T(); 
      this.CopyTo(result); 
      return result; 
    } 

    protected virtual void CopyTo(A other) { 
      other.a = this.a; 
      other.b = this.b; 
    } 

आप इस तरह इसका इस्तेमाल:

 A a = new A(); 
    // do stuff with a 
    // Create a B based on A: 
    B b = a.Clone<B>(); 

कृपया ध्यान दें: आपके उदाहरण में, नया ए(), और MemberwiseClone दोनों प्रकार का एक नया ऑब्जेक्ट ए

यदि आप कॉपी विधि को स्वयं कोड नहीं करना चाहते हैं, तो आप एक टूल देख सकते हैं AutoMapper की तरह।

+0

धन्यवाद! इस उदाहरण में, क्या मुझे सभी सदस्यों को सेट करना होगा (जैसे = = this.a, b = this.b, आदि)। यदि कक्षा में कई सदस्य हैं, वैसे भी प्रत्येक को कोडिंग से बचने के लिए? (अगर मैं एक और सदस्य जोड़ने का फैसला करता हूं, तो मुझे इसे क्लोनिंग फ़ंक्शन में भी सेट करना होगा) – Sam

+0

आप प्रतिबिंब के साथ कुछ बना सकते हैं (सभी फ़ील्ड हालांकि लूप, और उन्हें कॉपी करें), लेकिन अनुभव से मुझे पता है, आप बेहतर करेंगे खुद को कॉपी करने पर नियंत्रण करें। कभी-कभी आपको एक उथली प्रतिलिपि की आवश्यकता होती है, कुछ वस्तुओं के लिए आपको एक गहरी प्रतिलिपि की आवश्यकता होती है। – GvS

+0

क्यों नहीं अन्य = (ए) यह।MemberwiseClone(); 'ऊपर मैं काम करता हूं (प्रत्येक संपत्ति को सेट करने के बजाय)। मैं प्रत्येक संपत्ति को स्थापित करने या प्रतिबिंब का उपयोग करने से बचने की कोशिश कर रहा हूं। – PeterX

1

आसपास खेलने और सबकुछ पढ़ने के बाद मैं जीवीएस और जन के काम के उपरोक्त दोनों समाधानों पर अपनी आंखें प्राप्त कर सकता हूं। हालांकि, अंतिम परिणाम जो मैं प्राप्त करना चाहता था उसे कॉपी विधियों में प्रत्येक सदस्य को लिखने के लिए मजबूर नहीं किया जाना चाहिए।

क्यों: ए) यदि कक्षा संपादित की जाती है और दूसरी वस्तु जोड़ दी जाती है, तो कॉपी विधि को अपडेट करना होगा। अगर कोई और कक्षा को अद्यतन करता है, तो वे ऐसा करना भूल सकते हैं।

बी) बहुत से सदस्य हो सकते हैं, और उन्हें असाइन करने में समय लग सकता है।

सी) यह सही "महसूस" नहीं करता है। (शायद क्योंकि मैं बहुत आलसी हूँ)।

सौभाग्य से, मैं एक ही विचार के साथ अकेला नहीं हूं। ValueInjector के माध्यम से एक बहुत ही आसान समाधान मिला। (इन बोर्डों पर बहुत चर्चा की गई है)।

A a = new A(); 
a.s1 = "..."; 


B b = new B(); 
b.InjectFrom(a); 

है कि यह

:) जाहिर है आप शामिल करना होगा:

dll (http://valueinjecter.codeplex.com/documentation)

कोड हो जाता है प्राप्त करने के बाद :

using Omu.ValueInjecter; 

और संदर्भों में इसे जोड़ना न भूलें।

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