2012-02-20 14 views
5

का उपयोग कर मैं वर्तमान में सी # में एक घुसपैठ वृक्ष संरचना को लागू करने के लिए एक सरल तरीके से काम कर रहा हूं। चूंकि मैं मुख्य रूप से एक सी ++ प्रोग्रामर हूं, मैं तुरंत सीआरटीपी का उपयोग करना चाहता था। यहाँ मेरी कोड है:सी # - घुमावदार पेड़ संरचना, सीआरटीपी

public class TreeNode<T> where T : TreeNode<T> 
{ 
    public void AddChild(T a_node) 
    { 
     a_node.SetParent((T)this); // This is the part I hate 
    } 

    void SetParent(T a_parent) 
    { 
     m_parent = a_parent; 
    } 

    T m_parent; 
} 

यह काम करता है लेकिन ... मैं नहीं समझ सकता कारण है कि मैं जब, a_node.SetParent ((टी) इस) को कॉल करने के रूप में मैं सामान्य प्रकार प्रतिबंध का उपयोग कर रहा कास्ट करने के लिए है .. । सी # डाली एक लागत है, और मैं एक घुसपैठ संग्रह कार्यान्वयन में इस डाली प्रसार करने के लिए नहीं ...

+0

मैंने अपने उदाहरण को सरल बनाने की अनुमति दी। यदि आप सहमत नहीं हैं तो कृपया वापस आएं। – usr

+1

ईमानदार होने के लिए, यह एक चालाक headf ** के जैसा दिखता है। इसके बजाए संरचना का उपयोग करके वृक्षों का प्रतिनिधित्व करने के अधिक पारंपरिक तरीकों में क्या गलत है? यह आपको क्या खरीदता है? मुझे उम्मीद है कि यह बहुत विरोधी नहीं लगता है। मैं सिर्फ उत्सुक हूँ। – spender

+0

@ इसे आवंटन की संख्या का आधा हिस्सा दें, और उन अनुक्रमों की संख्या को कम कर देता है जिन्हें आपको अनुसरण करने की आवश्यकता है। तो उच्च प्रदर्शन कोड में यह एक उचित व्यापार बंद हो सकता है। छोटे पेड़ों के लिए यह शायद एक बुरा विचार है। – CodesInChaos

उत्तर

3

यह कम से कम TreeNode प्रकार है। यह व्युत्पन्न किया जा सकता है या यह बिल्कुल वृक्षारोपण हो सकता है। SetParent एक टी की अपेक्षा करता है लेकिन टी की तुलना में एक अलग प्रकार हो सकता है। हम जानते हैं कि यह और टी दोनों ट्रीनोड से निकलते हैं लेकिन वे विभिन्न प्रकार के हो सकते हैं।

उदाहरण:

class A : TreeNode<A> { } 
new TreeNode<A>() //'this' is of type 'TreeNode<A>' but required is type 'A' 
0

कोई भी गारंटी है कि T और this के प्रकार के एक ही हैं चाहते हैं। वे TreeNode के असंबद्ध उप-वर्ग भी हो सकते हैं।

आप उत्सुकता से आवर्ती टेम्पलेट पैटर्न में उपयोग किए जाने के लिए T की अपेक्षा करते हैं, लेकिन सामान्य बाधाएं इसे व्यक्त नहीं कर सकती हैं।

एक बेवकूफ कार्यान्वयन StupidNode:TreeNode<OtherNode> के रूप में परिभाषित किया जा सकता है।

0

समस्या इस लाइन के साथ है:

TreeNode<T> where T : TreeNode<T> 

टी एक TreeNode जा रहा है एक पुनरावर्ती परिभाषा यह निर्धारित नहीं किया जा सकता है पूर्व संकलन या यहाँ तक कि स्थिर जाँच की है। टेम्पलेट का उपयोग न करें, या आप & refactor करने के लिए की जरूरत है पेलोड से नोड अलग करता है, तो आप कर (नोड से ही Ie नोड डेटा।)

public class TreeNode<TPayload> 
{ 
    TPayload NodeStateInfo{get;set;} 

    public void AddChild(TreeNode<TPayload> a_node) 
    { 
     a_node.SetParent(this); // This is the part I hate 
    } 

    void SetParent(TreeNode<TPayload> a_parent) 
    { 
    } 
} 

इसके अलावा मुझे यकीन है कि तुम क्यों a_node कॉल कर रहे हैं नहीं कर रहा हूँ .SetParent (यह)। ऐसा लगता है कि AddChild को अधिक उपयुक्त रूप से SetParent नाम दिया गया है, क्योंकि आप इस उदाहरण को a_node के पैरेंट के रूप में सेट कर रहे हैं। हो सकता है कि यह कुछ गूढ़ एल्गोरिदम हो, मैं परिचित नहीं हूं, अन्यथा यह सही नहीं दिखता है।

+0

जबकि रचना आधारित संग्रह आमतौर पर एक बेहतर विचार होते हैं, घुसपैठ संग्रह में उनकी जगह होती है। 'TreeNode जहां टी: TreeNode 'इस संदर्भ में बाधा समझ में आता है। यह उत्सुकता से आवर्ती टेम्पलेट पैटर्न से संतुष्ट हो सकता है। 'AddChild' कार्यान्वयन भी मेरे लिए ठीक दिखता है। एक पेड़ में आप या तो 'सेटपेरेंट' या 'एडचल्ड' को स्पष्ट रूप से कार्यान्वित करते हैं, और उसके बाद दूसरे को आपके द्वारा लागू किए गए कॉल को कॉल करें। – CodesInChaos

0

पर विचार करता है, तो हम लिख कर CRTP सम्मेलन से विचलित क्या होता है ...

public class Foo : TreeNode<Foo> 
{ 
} 

public class Bar : TreeNode<Foo> // parting from convention 
{ 
} 

... और इस प्रकार है तो उपरोक्त कोड फोन:

var foo = new Foo(); 
var foobar = new Bar(); 
foobar.AddChild(foo); 

AddChild कॉल एक InvalidCastException फेंकता कह रहा है Unable to cast object of type 'Bar' to type 'Foo'.

सीआरटीपी मुहावरे के संबंध में - यह अकेले सम्मेलन है जिसे सामान्य प्रकार घोषित करने की आवश्यकता होती है आईएनजी प्रकार भाषा को उन अन्य मामलों का समर्थन करना चाहिए जहां सीआरटीपी सम्मेलन का पालन नहीं किया जाता है। एरिक लिपर्ट ने इस विषय पर एक महान ब्लॉग पोस्ट लिखा, कि वह इस अन्य crtp via c# answer से जुड़ा हुआ है।

ने कहा, अगर आप इस के लिए कार्यान्वयन को बदलने कि सब के सब ...

public class TreeNode<T> where T : TreeNode<T> 
{ 
    public void AddChild(T a_node) 
    { 
     a_node.SetParent(this); 
    } 

    void SetParent(TreeNode<T> a_parent) 
    { 
     m_parent = a_parent; 
    } 

    TreeNode<T> m_parent; 
} 

... ऊपर कोड है कि पहले InvalidCastException फेंक दिया अब काम करता है।परिवर्तन m_ParentTreeNode<T> का एक प्रकार बनाता है; this या तो Foo वर्ग 'मामले में प्रकार T या TreeNode<Foo> से Bar inherits के बाद से Bar वर्ग मामले में TreeNode<T> का एक उपवर्ग बनाने - किसी भी तरह से हमें SetParent में डाली छोड़ और उस चूक द्वारा के बाद से अवैध डाली अपवाद से बचने के लिए अनुमति देता है सभी मामलों में असाइनमेंट कानूनी है। ऐसा करने की लागत अब सभी स्थानों पर T का स्वतंत्र रूप से उपयोग करने में सक्षम नहीं है क्योंकि इसका पहले इस्तेमाल किया गया था जो सीआरटीपी के मूल्य को अधिक बलिदान देता है।

मेरा एक सहयोगी/दोस्त खुद को एक भाषा/भाषा-सुविधा के लिए नौसिखिया मानता है जब तक कि वह ईमानदारी से कह सके कि वह "इसे क्रोध में इस्तेमाल करता है" यानी, वह इस भाषा को बहुत निराश होने के लिए जानता है कि उसे जो कुछ चाहिए उसे पूरा करने का कोई तरीका नहीं है या ऐसा करने से दर्दनाक है। यह बहुत अच्छी तरह से उन मामलों में से एक हो सकता है, क्योंकि यहां सीमाएं और मतभेद हैं जो सत्य को प्रतिबिंबित करते हैं generics are not templates

0

जब आप संदर्भ प्रकारों के साथ काम कर रहे हैं, और आप इस तथ्य के बारे में जानते हैं कि प्रकार के पदानुक्रम के साथ आपकी कलाकार सफल होगी (यहां कोई कस्टम कास्टिंग नहीं), तो वास्तव में कुछ भी डालने की आवश्यकता नहीं है। संदर्भ पूर्णांक का मूल्य कास्ट के पहले और बाद में समान होता है, तो क्यों न केवल कास्ट छोड़ें?

इसका मतलब है कि आप सीआईएल/एमएसआईएल में इस घृणित AddChild विधि को लिख सकते हैं। विधि बॉडी ऑपकोड निम्नानुसार हैं:

ldarg.1 
ldarg.0 
stfld TreeNode<class T>::m_parent 
ret 

.NET उस परवाह नहीं करेगा जिस पर आपने मूल्य डाला नहीं है। जिटर को केवल स्टोर्स के आकार के बारे में परवाह है, जो वे हमेशा संदर्भ के लिए हैं।

लोड अप दृश्य स्टूडियो के लिए आईएल समर्थन विस्तार और MethodImpl.ForwardRef विशेषता के साथ निर्वासन के रूप में सी # प्रणाली की घोषणा (vsix फ़ाइल को खोलने और संशोधित समर्थित संस्करण हो सकता है)। फिर बस एक .il फ़ाइल में कक्षा को फिर से घोषित करें और आपको आवश्यक एक विधि कार्यान्वयन जोड़ें, जिसका शरीर ऊपर प्रदान किया गया है।

ध्यान दें कि यह मैन्युअल रूप से आपकी SetParent विधि को AddChild में भी रेखांकित करता है।

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