मुझे अपरिवर्तनीय संग्रह पसंद हैं लेकिन वे अक्सर किसी समस्या की आवश्यकता के समाधान की तरह महसूस करते हैं। how they are implemented के कारण वे unexpectedly slow हो सकते हैं: वे foreach
लूप और इंडेक्सर्स को अधिक एल्गोरिदमिक जटिल बनाने की लागत पर कुशलता से स्मृति का उपयोग करने के लिए बहुत मेहनत करते हैं। कितनी मेमोरी है, उस लागत को औचित्य देना मुश्किल हो सकता है। अपरिवर्तनीय संग्रह (ImmutableArray<T>
के अलावा) के सफल उपयोगों के बारे में वेब पर मिलने वाली जानकारी की कमी है। इसे सुधारने के प्रयास में, मैंने सोचा कि मैं इस मामले के बारे में इस 3+ वर्षीय प्रश्न का उत्तर जोड़ूंगा जहां मुझे ImmutableStack<T>
वास्तव में उपयोगी होने के लिए मिला।
public class TreeNode
{
public TreeNode Parent { get; private set; }
public List<TreeNode> ChildNodes { get; set; }
public TreeNode(TreeNode parent)
{
Parent = parent;
}
}
मैं वर्गों है कि इस बुनियादी पैटर्न कई, कई बार पालन करें, और व्यवहार में, यह मुझे हमेशा के लिए काम किया है बना लिया है:
यह बहुत ही बुनियादी पेड़ की तरह संरचना पर विचार करें। हाल ही में, मैं इस तरह कुछ करने के लिए शुरू कर दिया है:
public class TreeNode
{
public ImmutableStack<TreeNode> NodeStack { get; private set; }
public ImmutableStack<TreeNode> ParentStack { get { return NodeStack.IsEmpty ? ImmutableStack<TreeNode>.Empty : NodeStack.Pop(); } }
public TreeNode Parent { get { return ParentStack.IsEmpty ? null : ParentStack.Peek(); } }
public ImmutableArray<TreeNode> ChildNodes { get; set; }
public TreeNode(TreeNode parent)
{
if (parent == null)
NodeStack = ImmutableStack<TreeNode>.Empty;
else
NodeStack = parent.NodeStack.Push(this);
}
}
कई कारणों से के लिए, मैं एक TreeNode
की ImmutableStack<T>
उदाहरणों है कि मैं केवल एक संदर्भ के बजाय जड़ को पार कर सकते हैं भंडारण पसंद करते हैं पर आए हैं Parent
उदाहरण के लिए।
ImmutableStack<T>
का कार्यान्वयन मूल रूप से एक लिंक की गई सूची है। ImmutableStack<T>
का प्रत्येक उदाहरण वास्तव में एक लिंक की गई सूची पर एक नोड है। यही कारण है कि ParentStack
संपत्ति Pop
NodeStack
है। ParentStack
ImmutableStack<T>
के Parent.NodeStack
के समान उदाहरण लौटाएगा।
- यदि आप
Parent
TreeNode
का संदर्भ संग्रहीत करते हैं, तो सर्कुलर लूप बनाना आसान होगा जो रूट नोड को कभी समाप्त नहीं करने के लिए संचालन का कारण बनता है, और आपको या तो एक स्टैक ओवरफ़्लो या अनंत लूप मिल जाएगा। दूसरी ओर, ImmutableStack<T>
, Pop
-ing द्वारा चढ़ाया जा सकता है, यह गारंटी देता है कि यह समाप्त हो जाएगा।
- तथ्य यह है कि आप एक संग्रह (
ImmutableStack<T>
) का उपयोग का मतलब है कि आप बस यकीन है कि parent
TreeNode
दो बार नहीं होती है जब TreeNode
निर्माण बनाकर पहली जगह में हो रहा से परिपत्र छोरों रोका जा सकता है।
बस के साथ शुरू करने के लिए है कि। मुझे लगता है कि ImmutableStack<T>
पेड़ के संचालन को सरल और सुरक्षित बनाता है। आप (सुरक्षित रूप से) LINQ का उपयोग कर सकते हैं। जानना चाहते हैं कि एक TreeNode
दूसरे का वंशज है या नहीं? आप बस ParentStack.Any(node => node == otherNode)
अधिक आम तौर पर कर सकता है, ImmutableStack<T>
वर्ग किसी भी मामले में जहां आप चाहते हैं एक Stack<T>
कि आप गारंटी ले सकते हैं संशोधित होगा कभी नहीं किया है, या आप एक एक Stack<T>
"स्नैपशॉट" प्राप्त करने के लिए एक आसान तरीका की जरूरत है, लेकिन के लिए है उस ढेर की प्रतियों का एक गुच्छा बनाने के लिए नहीं बनाना चाहते हैं। यदि आपके पास नेस्टेड चरणों की एक श्रृंखला है, तो आप प्रगति को ट्रैक करने के लिए ImmutableStack<T>
का उपयोग कर सकते हैं, और इसलिए जब कोई चरण पूरा हो जाता है, तो यह कार्य को अपने मूल चरण में बंद कर सकता है। जब आप समानांतर में काम करने की कोशिश कर रहे हैं तो इसकी अपरिवर्तनीय प्रकृति विशेष रूप से सहायक होती है।
स्रोत
2017-07-05 22:30:01
http://blogs.msdn.com/b/ericlippert/archive/2007/12/04/immutability-in-c-part-two-a-simple-immutable-stack.aspx –
हाँ, मेरे पास है उस लेख को देखा। लेकिन यह एक कारण प्रदान नहीं करता है कि कुछ संदर्भों में एक अपरिवर्तनीय ढेर उपयोगी क्यों हो सकता है। एक बार फिर, यह अपरिवर्तनीयता की मेरी समझ हो सकती है जो गलत है। –