दिलचस्प पोस्ट
नक्शे के बीच का अंतर, लागू करना और पंडों में तरीकों को लागू करना सरणी से सभी अनूठे तत्व प्राप्त करने के लिए jQuery फ़ंक्शन? एक्लिप्स में जार या युद्ध से फाइलें बहिष्कृत करें स्पर्श पर पिक्सेल रंग कैसे प्राप्त करें? PHP विंडोज़ मशीन पर एसएसएच 2 स्थापित करें मैं एंड्रॉइड एप्लिकेशन के ढेर के आकार के उपयोग को कैसे पहचानूं? स्रोत नियंत्रण – वितरित सिस्टम बनाम गैर-वितरित – क्या अंतर है? आपका पसंदीदा विजुअल बेसिक 6.0 टूल और टिप्स rpy2 विंडोज 7 पर स्थापित करें पायथन में प्राकृतिक / सापेक्ष दिन पासवर्ड के लिए स्ट्रिंग के ऊपर चार पसंदीदा क्यों हैं? gson.toJson () StackOverflowError फेंकता है स्क्रीन के बीच अंतर। AwailHeight और window.height () तारों / चरित्र के एक सदिश को समन्वित करें इन खंडों में सभी मूल्यों का मिलान करना

क्यों सी # अनुक्रमित गुणों को लागू नहीं करता है?

मुझे पता है, मुझे पता है … एरिक लिपर्ट ने इस तरह के प्रश्न का उत्तर आमतौर पर "जैसा कुछ है, क्योंकि यह डिजाइनिंग, कार्यान्वयन, परीक्षण और दस्तावेज की कीमत के लायक नहीं था "।

लेकिन फिर भी, मैं एक बेहतर स्पष्टीकरण चाहता हूं … मैं इस ब्लॉग पोस्ट को नए सी # 4 सुविधाओं के बारे में पढ़ रहा था, और COM इंटरॉप के बारे में खंड में, निम्नलिखित भाग ने मेरा ध्यान पकड़ा:

वैसे, यह कोड एक और नई सुविधा का उपयोग करता है: अनुक्रमित गुण (रेंज के बाद उन वर्ग कोष्ठक पर करीब से देखें)। लेकिन यह सुविधा केवल COM इंटरॉप के लिए उपलब्ध है; आप सी # 4.0 में अपनी स्वयं की अनुक्रमित गुण नहीं बना सकते

ठीक है, लेकिन क्यों ? मुझे पहले से ही पता था और अफसोस था कि सी # में अनुक्रमित गुण बनाना संभव नहीं था, लेकिन इस वाक्य ने मुझे इसके बारे में फिर से सोचने में मदद की। मैं इसे लागू करने के लिए कई अच्छे कारण देख सकता हूं:

  • सीएलआर इसका समर्थन करता है (उदाहरण के लिए, PropertyInfo.GetValue में एक index पैरामीटर है), इसलिए यह दया है कि हम इसका लाभ सी # में नहीं कर सकते हैं
  • यह COM इंटरॉप के लिए समर्थित है, जैसा कि लेख में दिखाया गया है (गतिशील डिस्पैच का उपयोग करके)
  • यह VB.NET में कार्यान्वित किया गया है
  • सूचकांक बनाने के लिए पहले से ही संभव है, यानी वस्तु के लिए एक सूचकांक लागू करने के लिए, इसलिए यह संभवतः विचार करने के लिए गुणों को बढ़ाने के लिए, एक ही वाक्यविन्यास को बनाए रखने और संपत्ति के नाम

यह उस प्रकार की बातें लिखने की अनुमति देगा:

 public class Foo { private string[] _values = new string[3]; public string Values[int index] { get { return _values[index]; } set { _values[index] = value; } } } 

वर्तमान में केवल एकमात्र समाधान जो मुझे पता है एक आंतरिक वर्ग (उदाहरण के लिए Values संकलन) बनाने के लिए है, जो एक इंडेक्सर को लागू करता है, और Values संपत्ति को बदलता है ताकि वह उस आंतरिक वर्ग का एक उदाहरण वापस कर सके।

यह करना बहुत आसान है, लेकिन परेशान है … तो शायद संकलक यह हमारे लिए कर सकता है! एक विकल्प इंडेक्सर का कार्यान्वयन करने वाला एक आंतरिक वर्ग उत्पन्न करेगा, और इसे एक सार्वजनिक जेनेरिक इंटरफ़ेस के माध्यम से प्रदर्शित करेगा:

 // interface defined in the namespace System public interface IIndexer<TIndex, TValue> { TValue this[TIndex index] { get; set; } } public class Foo { private string[] _values = new string[3]; private class <>c__DisplayClass1 : IIndexer<int, string> { private Foo _foo; public <>c__DisplayClass1(Foo foo) { _foo = foo; } public string this[int index] { get { return _foo._values[index]; } set { _foo._values[index] = value; } } } private IIndexer<int, string> <>f__valuesIndexer; public IIndexer<int, string> Values { get { if (<>f__valuesIndexer == null) <>f__valuesIndexer = new <>c__DisplayClass1(this); return <>f__valuesIndexer; } } } 

लेकिन जाहिर है, उस मामले में संपत्ति वास्तव में एक IIndexer<int, string> और वास्तव में एक अनुक्रमित संपत्ति नहीं होगी … यह वास्तविक सीएलआर अनुक्रमित संपत्ति उत्पन्न करने के लिए बेहतर होगा।

तुम क्या सोचते हो ? क्या आप सी # में इस सुविधा को देखना चाहेंगे? यदि नहीं, तो क्यों?

Solutions Collecting From Web of "क्यों सी # अनुक्रमित गुणों को लागू नहीं करता है?"

हम कैसे सी # 4 बनाया है यहाँ है

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

फिर हम सुविधाओं को "यह बुरा है, हमें कभी भी नहीं करना चाहिए" में बाल्टी लगाया, "यह बढ़िया है, हमें इसे करना है", और "यह अच्छा है, लेकिन इस बार ऐसा नहीं करें"।

फिर हमने देखा कि हमारे पास "कितना बजट" डिजाइन करना, कार्यान्वित करना, परीक्षण करना, दस्तावेज बनाना, जहाज बनाना और बनाए रखना था और यह पता चला कि हम बजट में 100% थे।

इसलिए हमने बाल्टी से "सामान के लिए" को बाल्टी से "गोट हैं" से सामान का एक गुच्छा चले गए

अनुक्रमित गुण "कभी भी" सूची के शीर्ष के निकट कहीं भी नहीं थे। वे "अच्छी" सूची पर बहुत कम हैं और "खराब विचार" सूची के साथ छेड़खानी

हर मिनट हम डिजाइनिंग, कार्यान्वयन, परीक्षण, दस्तावेज या अच्छा बनाए रखने के लिए खर्च करते हैं एक्स एक मिनट है जो हम ए, बी, सी, डी, ई, एफ और जी पर भयानक सुविधाओं पर खर्च नहीं कर सकते। हमें क्रूर रूप से प्राथमिकता दी जानी है ताकि हम केवल सर्वोत्तम संभव सुविधाएं अनुक्रमित गुण अच्छा होगा, लेकिन वास्तव में कार्यान्वित करने के लिए अच्छी तरह से कहीं भी कहीं भी अच्छा नहीं है।

एसी # इंडेक्सर एक अनुक्रमित संपत्ति है इसे डिफ़ॉल्ट रूप से Item नाम दिया गया है (और आप इसे उदाहरण के तौर पर वीबी के रूप में संदर्भित कर सकते हैं), और यदि आप चाहते हैं तो आप इसे इंडेडेनरनाम नाम से बदल सकते हैं।

मुझे यकीन नहीं है कि, विशेष रूप से, यह इस तरह से डिजाइन किया गया था, लेकिन यह एक जानबूझकर सीमा लगती है। हालांकि, फ्रेमवर्क डिज़ाइन दिशानिर्देशों के अनुरूप है, जो गैर-अनुक्रमित संपत्ति के सदस्य संग्रह के लिए एक अनुक्रमणीय वस्तु लौटने के दृष्टिकोण की सिफारिश करते हैं। Ie "अनुक्रमणीय होना" एक प्रकार का एक लक्षण है; यदि यह एक से अधिक तरीकों से सूचक है, तो यह वास्तव में कई प्रकारों में विभाजित होना चाहिए।

क्योंकि आप पहले से ही ऐसा कर सकते हैं, और यह आपको ऊ पहलुओं में सोचने के लिए मजबूर कर रहा है, इंडेडेड गुण जोड़कर भाषा में अधिक शोर बस जोड़ देगा। और दूसरी बात करने के लिए एक और तरीका है

 class Foo { public Values Values { ... } } class Values { public string this[int index] { ... } } foo.Values[0] 

मैं व्यक्तिगत रूप से 10 तरीकों की बजाय, कुछ करने का केवल एक ही तरीका देखना चाहूंगा लेकिन बेशक यह एक व्यक्तिपरक राय है।

मैं अनुक्रमित गुणों के विचारों का समर्थन करता था लेकिन फिर महसूस किया कि यह भयानक अस्पष्टता को जोड़ देगा और वास्तव में कार्यक्षमता को बेमाना देगा I अनुक्रमित गुणों का मतलब होगा कि आपके पास बाल संग्रहण उदाहरण नहीं है। यह दोनों अच्छे और बुरे हैं यह लागू करने में कम परेशानी होती है और आपको संदर्भित मालिक वर्ग में संदर्भ की आवश्यकता नहीं होती है। लेकिन इसका भी मतलब है कि आप उस बच्चे के संग्रह को कुछ भी नहीं दे सकते हैं; आप को हर बार एक बार गणना करना होगा न ही आप इसे पर एक foreach कर सकते हैं सबसे ज़्यादा, आप किसी अनुक्रमित संपत्ति को देखने से नहीं बता सकते हैं कि क्या वह या संग्रहण संपत्ति है

यह तर्क तर्कसंगत है लेकिन यह सिर्फ अनमोलता और अचानक अड़चन की ओर जाता है।

मुझे अनुक्रमित गुणों की कमी बहुत निराशाजनक लगता है जब साफ, संक्षिप्त कोड लिखने की कोशिश करते हैं। इंडेक्सेड प्रॉपर्टी के पास अलग-अलग अर्थ है जो क्लास संदर्भ प्रदान करने से अलग है, जो अनुक्रमित या व्यक्तिगत तरीके प्रदान करते हैं। मुझे यह थोड़ा परेशान लगता है कि एक अनुक्रमित संपत्ति को लागू करने वाली आंतरिक वस्तु तक पहुंच प्रदान करना स्वीकार्य माना जाता है क्योंकि वह अक्सर ऑब्जेक्ट उन्मुखीकरण के मुख्य घटकों में से एक को तोड़ता है: इनकैप्सुलेशन

मैं इस समस्या को अक्सर पर्याप्त रूप से चलाता हूं, लेकिन आज मैं इसे फिर से सामना करना पड़ा ताकि मैं एक वास्तविक दुनिया कोड उदाहरण प्रदान करूंगा। इंटरफ़ेस और क्लास को लिखित स्टोर्स एप्लिकेशन कॉन्फ़िगरेशन जो ढीले से संबंधित जानकारी का एक संग्रह है। मुझे नामित स्क्रिप्ट के टुकड़े जोड़ने की आवश्यकता थी और स्क्रिप्ट के टुकड़े कॉन्फ़िगरेशन का केवल एक हिस्सा हैं, क्योंकि अज्ञात वर्ग अनुक्रमणक का उपयोग करके एक बहुत ही गलत संदर्भ निहित होगा।

यदि अनुक्रमित गुण सी # में उपलब्ध थे I नीचे दिए गए कोड को लागू कर सकता था (सिंटैक्स यह [कुंजी] परिवर्तित किया गया PropertyName [key])

 public interface IConfig { // Other configuration properties removed for examp[le /// <summary> /// Script fragments /// </summary> string Scripts[string name] { get; set; } } /// <summary> /// Class to handle loading and saving the application's configuration. /// </summary> internal class Config : IConfig, IXmlConfig { #region Application Configuraiton Settings // Other configuration properties removed for examp[le /// <summary> /// Script fragments /// </summary> public string Scripts[string name] { get { if (!string.IsNullOrWhiteSpace(name)) { string script; if (_scripts.TryGetValue(name.Trim().ToLower(), out script)) return script; } return string.Empty; } set { if (!string.IsNullOrWhiteSpace(name)) { _scripts[name.Trim().ToLower()] = value; OnAppConfigChanged(); } } } private readonly Dictionary<string, string> _scripts = new Dictionary<string, string>(); #endregion /// <summary> /// Clears configuration settings, but does not clear internal configuration meta-data. /// </summary> private void ClearConfig() { // Other properties removed for example _scripts.Clear(); } #region IXmlConfig void IXmlConfig.XmlSaveTo(int configVersion, XElement appElement) { Debug.Assert(configVersion == 2); Debug.Assert(appElement != null); // Saving of other properties removed for example if (_scripts.Count > 0) { var scripts = new XElement("Scripts"); foreach (var kvp in _scripts) { var scriptElement = new XElement(kvp.Key, kvp.Value); scripts.Add(scriptElement); } appElement.Add(scripts); } } void IXmlConfig.XmlLoadFrom(int configVersion, XElement appElement) { // Implementation simplified for example Debug.Assert(appElement != null); ClearConfig(); if (configVersion == 2) { // Loading of other configuration properites removed for example var scripts = appElement.Element("Scripts"); if (scripts != null) foreach (var script in scripts.Elements()) _scripts[script.Name.ToString()] = script.Value; } else throw new ApplicaitonException("Unknown configuration file version " + configVersion); } #endregion } 

दुर्भाग्य से अनुक्रमित संपत्तियां लागू नहीं की गई हैं इसलिए मैंने उन्हें स्टोर करने के लिए एक क्लास लागू किया और उस तक पहुंच प्रदान की। यह एक अवांछनीय कार्यान्वयन है क्योंकि इस डोमेन मॉडल में कॉन्फ़िगरेशन क्लास का उद्देश्य सभी विवरणों को शामिल करना है। इस वर्ग के ग्राहक नाम से विशिष्ट स्क्रिप्ट के टुकड़े तक पहुंचेंगे और उन पर गिनना या गणना करने का कोई कारण नहीं होगा।

मैं इसे लागू कर सकता था:

 public string ScriptGet(string name) public void ScriptSet(string name, string value) 

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

अनुक्रमित संपत्ति के रूप में इसी तरह की क्षमता को लागू करने के लिए मुझे निम्न कोड लिखना पड़ता है, जो आपको नोटिस कराना होगा, काफी अधिक जटिल है और इस प्रकार पढ़ना, समझना और बनाए रखने के लिए कठिन है।

 public interface IConfig { // Other configuration properties removed for examp[le /// <summary> /// Script fragments /// </summary> ScriptsCollection Scripts { get; } } /// <summary> /// Class to handle loading and saving the application's configuration. /// </summary> internal class Config : IConfig, IXmlConfig { public Config() { _scripts = new ScriptsCollection(); _scripts.ScriptChanged += ScriptChanged; } #region Application Configuraiton Settings // Other configuration properties removed for examp[le /// <summary> /// Script fragments /// </summary> public ScriptsCollection Scripts { get { return _scripts; } } private readonly ScriptsCollection _scripts; private void ScriptChanged(object sender, ScriptChangedEventArgs e) { OnAppConfigChanged(); } #endregion /// <summary> /// Clears configuration settings, but does not clear internal configuration meta-data. /// </summary> private void ClearConfig() { // Other properties removed for example _scripts.Clear(); } #region IXmlConfig void IXmlConfig.XmlSaveTo(int configVersion, XElement appElement) { Debug.Assert(configVersion == 2); Debug.Assert(appElement != null); // Saving of other properties removed for example if (_scripts.Count > 0) { var scripts = new XElement("Scripts"); foreach (var kvp in _scripts) { var scriptElement = new XElement(kvp.Key, kvp.Value); scripts.Add(scriptElement); } appElement.Add(scripts); } } void IXmlConfig.XmlLoadFrom(int configVersion, XElement appElement) { // Implementation simplified for example Debug.Assert(appElement != null); ClearConfig(); if (configVersion == 2) { // Loading of other configuration properites removed for example var scripts = appElement.Element("Scripts"); if (scripts != null) foreach (var script in scripts.Elements()) _scripts[script.Name.ToString()] = script.Value; } else throw new ApplicaitonException("Unknown configuration file version " + configVersion); } #endregion } public class ScriptsCollection : IEnumerable<KeyValuePair<string, string>> { private readonly Dictionary<string, string> Scripts = new Dictionary<string, string>(); public string this[string name] { get { if (!string.IsNullOrWhiteSpace(name)) { string script; if (Scripts.TryGetValue(name.Trim().ToLower(), out script)) return script; } return string.Empty; } set { if (!string.IsNullOrWhiteSpace(name)) Scripts[name.Trim().ToLower()] = value; } } public void Clear() { Scripts.Clear(); } public int Count { get { return Scripts.Count; } } public event EventHandler<ScriptChangedEventArgs> ScriptChanged; protected void OnScriptChanged(string name) { if (ScriptChanged != null) { var script = this[name]; ScriptChanged.Invoke(this, new ScriptChangedEventArgs(name, script)); } } #region IEnumerable public IEnumerator<KeyValuePair<string, string>> GetEnumerator() { return Scripts.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } #endregion } public class ScriptChangedEventArgs : EventArgs { public string Name { get; set; } public string Script { get; set; } public ScriptChangedEventArgs(string name, string script) { Name = name; Script = script; } } 

एक और वैकल्पिक हल सी + में अनुक्रमणिका का समर्थन करने वाले गुणों के आसान निर्माण पर सूचीबद्ध है, जिसके लिए कम काम की आवश्यकता होती है।

संपादित करें : मुझे यह भी मूल प्रश्न के जवाब में जोड़ना चाहिए, कि अगर हम पुस्तकालय समर्थन के साथ वांछित वाक्य रचना को पूरा कर सकते हैं, तो मुझे लगता है कि इसे सीधे भाषा में जोड़ने के लिए एक बहुत मजबूत मामला होना चाहिए, ताकि भाषा ब्लोट को कम करें

वैसे मैं कहूंगा कि उन्होंने इसे जोड़ा नहीं है क्योंकि यह डिजाइन, कार्यान्वयन, परीक्षण और दस्तावेजीकरण की लागत के लायक नहीं था।

एक तरफ मजाक कर रहा है, शायद इसकी वजह यह है कि कामकाज सरल हैं और सुविधा कभी भी बनाम बनाम लाभ कटौती नहीं करता है। मुझे यह आश्चर्य नहीं होगा कि यह रेखा के नीचे एक बदलाव के रूप में दिखाई देता है।

आप यह भी उल्लेख करना भूल गए हैं कि एक आसान समाधान सिर्फ एक नियमित तरीका है:

 public void SetFoo(int index, Foo toSet) {...} public Foo GetFoo(int index) {...} 

इंडेक्सिंग कार्यक्षमता प्रॉक्सी के लिए लैम्ब्डा का उपयोग कर एक साधारण सामान्य समाधान है

केवल अनुक्रमण को पढ़ने के लिए

 public class RoIndexer<TIndex, TValue> { private readonly Func<TIndex, TValue> _Fn; public RoIndexer(Func<TIndex, TValue> fn) { _Fn = fn; } public TValue this[TIndex i] { get { return _Fn(i); } } } 

अस्थिर अनुक्रमण के लिए

 public class RwIndexer<TIndex, TValue> { private readonly Func<TIndex, TValue> _Getter; private readonly Action<TIndex, TValue> _Setter; public RwIndexer(Func<TIndex, TValue> getter, Action<TIndex, TValue> setter) { _Getter = getter; _Setter = setter; } public TValue this[TIndex i] { get { return _Getter(i); } set { _Setter(i, value); } } } 

और एक कारखाना

 public static class Indexer { public static RwIndexer<TIndex, TValue> Create<TIndex, TValue>(Func<TIndex, TValue> getter, Action<TIndex, TValue> setter) { return new RwIndexer<TIndex, TValue>(getter, setter); } public static RoIndexer<TIndex, TValue> Create<TIndex, TValue>(Func<TIndex, TValue> getter) { return new RoIndexer<TIndex, TValue>(getter); } } 

मेरे अपने कोड में मैं इसका इस्तेमाल कर रहा हूं

 public class MoineauFlankContours { public MoineauFlankContour Rotor { get; private set; } public MoineauFlankContour Stator { get; private set; } public MoineauFlankContours() { _RoIndexer = Indexer.Create(( MoineauPartEnum p ) => p == MoineauPartEnum.Rotor ? Rotor : Stator); } private RoIndexer<MoineauPartEnum, MoineauFlankContour> _RoIndexer; public RoIndexer<MoineauPartEnum, MoineauFlankContour> FlankFor { get { return _RoIndexer; } } } 

और MoineauFlankContours की एक उदाहरण के साथ मैं कर सकता हूँ

 MoineauFlankContour rotor = contours.FlankFor[MoineauPartEnum.Rotor]; MoineauFlankContour stator = contours.FlankFor[MoineauPartEnum.Stator]; 

बस अपने आप को भी पता चला कि आप इसे लागू करने के लिए स्पष्ट रूप से कार्यान्वित इंटरफेस का उपयोग कर सकते हैं, जैसा कि यहां दिखाया गया है: सी # में अनुक्रमित संपत्ति नामांकित है? (उस उत्तर में दिखाया गया दूसरा तरीका देखें)