मैं डिज़ाइन के समय में वेरिएबल के प्रकार को विश्वसनीय रूप से कैसे निर्धारित कर सकता हूं, जिसे var का उपयोग करके घोषित किया गया है?


109

मैं emacs में C # के लिए एक पूर्ण (intellisense) सुविधा पर काम कर रहा हूं।

यह विचार है, यदि कोई उपयोगकर्ता एक टुकड़ा टाइप करता है, तो एक विशेष कीस्ट्रोक संयोजन के माध्यम से पूरा करने के लिए कहता है, तो पूर्णता को निर्धारित करने के लिए पूर्ण सुविधा .NET प्रतिबिंब का उपयोग करेगी।

ऐसा करने के लिए आवश्यक है कि जिस प्रकार की चीज़ पूरी हो रही है, उसे जाना जाए। यदि यह एक स्ट्रिंग है, तो संभावित तरीकों और गुणों का एक ज्ञात सेट है; यदि यह एक इंट 32 है, तो इसका एक अलग सेट है, और इसी तरह।

सिमेंटिक का उपयोग करते हुए, एक कोड लेसर / पार्सर पैकेज जो कि एमएसीएस में उपलब्ध है, मैं चर घोषणाओं, और उनके प्रकारों का पता लगा सकता हूं। यह देखते हुए, कि प्रकार पर विधियों और गुणों को प्राप्त करने के लिए प्रतिबिंब का उपयोग करना सीधा है, और फिर उपयोगकर्ता के लिए विकल्पों की सूची प्रस्तुत करें। (ठीक है, बहुत सीधा नहीं है emacs के भीतर करने के लिए , लेकिन emacs के अंदर एक पॉलीशेल प्रोसेस को चलाने की क्षमता का उपयोग करने से , यह बहुत आसान हो जाता है। मैं प्रतिबिंब बनाने के लिए एक कस्टम .NET असेंबली लिखता हूं, इसे पॉवरशेल में लोड करता हूं, और फिर भीतर टाइप करता हूं। emacs कमांड भेज सकते हैं और कॉमिंस के माध्यम से प्रतिक्रियाएं पढ़ सकते हैं। परिणामस्वरूप emacs प्रतिबिंब के परिणाम जल्दी प्राप्त कर सकते हैं।)

समस्या तब आती है जब कोड varपूरा होने की घोषणा में कोड का उपयोग करता है। इसका मतलब है कि प्रकार स्पष्ट रूप से निर्दिष्ट नहीं है, और पूरा होने पर काम नहीं करेगा।

जब varकीवर्ड के साथ चर घोषित किया जाता है, तो मैं वास्तविक रूप से उपयोग किए जाने वाले वास्तविक प्रकार को कैसे निर्धारित कर सकता हूं ? बस स्पष्ट होने के लिए, मुझे इसे रनटाइम पर निर्धारित करने की आवश्यकता नहीं है। मैं इसे "डिजाइन समय" पर निर्धारित करना चाहता हूं।

अब तक मेरे पास ये विचार हैं:

  1. संकलन और आह्वान करें:
    • घोषणा विवरण निकालें, जैसे 'var foo = "a string value"; `
    • एक कथन को 'foo.GetType ();'
    • गतिशील रूप से परिणामी C # टुकड़े को एक नई असेंबली में संकलित करें
    • एक नए AppDomain में असेंबली को लोड करें, फ्रैमेक्शन चलाएं और वापसी प्रकार प्राप्त करें।
    • असेंबली को अनलोड और त्यागें

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

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

  2. संकलन करें और IL का निरीक्षण करें

    बस एक मॉड्यूल में घोषणा को संकलित करें, और फिर संकलक द्वारा अनुमान लगाया गया वास्तविक प्रकार निर्धारित करने के लिए, आईएल का निरीक्षण करें। यह कैसे संभव होगा? आईएल की जांच करने के लिए मैं क्या उपयोग करूंगा?

किसी भी बेहतर विचार वहाँ? टिप्पणियाँ? सुझाव?


EDIT - इस बारे में और सोचना, संकलन-और-आह्वान स्वीकार्य नहीं है, क्योंकि आह्वान के दुष्प्रभाव हो सकते हैं। इसलिए पहले विकल्प को खारिज करना चाहिए।

इसके अलावा, मुझे लगता है कि मैं .NET 4.0 की उपस्थिति को स्वीकार नहीं कर सकता।


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

यह वास्तव में पूरा होने वाले परिदृश्यों के एक सबसेट के लिए काम करता है।

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

var x = "hello there"; 
x.?

पूरा होने का एहसास है कि x एक स्ट्रिंग है, और उचित विकल्प प्रदान करता है। यह निम्न स्रोत कोड को उत्पन्न और संकलित करके ऐसा करता है:

namespace N1 {
  static class dmriiann5he { // randomly-generated class name
    static void M1 () {
       var x = "hello there"; 
    }
  }
}

... और फिर सरल प्रतिबिंब के साथ आईएल का निरीक्षण किया।

यह भी काम करता है:

var x = new XmlDocument();
x.? 

इंजन उत्पन्न स्रोत कोड के खंड का उपयोग करके उपयुक्त जोड़ता है, ताकि यह ठीक से संकलित हो, और फिर आईएल निरीक्षण समान हो।

यह भी काम करता है:

var x = "hello"; 
var y = x.ToCharArray();    
var z = y.?

इसका मतलब सिर्फ यह है कि आईएल निरीक्षण को पहले के बजाय तीसरे स्थानीय चर का प्रकार खोजना होगा।

और इस:

var foo = "Tra la la";
var fred = new System.Collections.Generic.List<String>
    {
        foo,
        foo.Length.ToString()
    };
var z = fred.Count;
var x = z.?

... जो सिर्फ एक स्तर गहरा है कि पूर्व उदाहरण।

लेकिन, जो भी काम नहीं करता है वह किसी भी स्थानीय चर पर पूरा होता है जिसका प्रारंभ उदाहरण के सदस्य या स्थानीय विधि तर्क पर किसी भी बिंदु पर निर्भर करता है। पसंद:

var foo = this.InstanceMethod();
foo.?

न ही LINQ सिंटैक्स।

मुझे यह सोचना होगा कि उन चीजों को कितना मूल्यवान है इससे पहले कि मैं उन्हें पूरा करने के लिए एक "सीमित डिजाइन" (हैक के लिए विनम्र शब्द) के माध्यम से उन्हें संबोधित करने पर विचार करूं।

विधि तर्कों या उदाहरण के तरीकों पर निर्भरता के साथ मुद्दे को संबोधित करने के लिए एक दृष्टिकोण को प्रतिस्थापित करना होगा, कोड के टुकड़े में जो उत्पन्न होता है, संकलित किया जाता है और फिर आईएल का विश्लेषण किया जाता है, उसी प्रकार के "सिंथेटिक" स्थानीय संस्करणों के साथ उन चीजों के संदर्भ।


एक अन्य अद्यतन - उदाहरणों पर पूरा करना जो उदाहरण के सदस्यों पर निर्भर करता है, अब काम करता है।

मैंने जो किया वह प्रकार (अर्थ के माध्यम से) से पूछताछ की गई, और फिर सभी मौजूदा सदस्यों के लिए सिंथेटिक स्टैंड-इन सदस्यों को उत्पन्न किया। इस तरह एक सी # बफर के लिए:

public class CsharpCompletion
{
    private static int PrivateStaticField1 = 17;

    string InstanceMethod1(int index)
    {
        ...lots of code here...
        return result;
    }

    public void Run(int count)
    {
        var foo = "this is a string";
        var fred = new System.Collections.Generic.List<String>
        {
            foo,
            foo.Length.ToString()
        };
        var z = fred.Count;
        var mmm = count + z + CsharpCompletion.PrivateStaticField1;
        var nnn = this.InstanceMethod1(mmm);
        var fff = nnn.?

        ...more code here...

... उत्पन्न कोड जो संकलित हो जाता है, ताकि मैं आउटपुट से सीख सकूं IL स्थानीय प्रकार का nn प्रकार, निम्न प्रकार दिखता है:

namespace Nsbwhi0rdami {
  class CsharpCompletion {
    private static int PrivateStaticField1 = default(int);
    string InstanceMethod1(int index) { return default(string); }

    void M0zpstti30f4 (int count) {
       var foo = "this is a string";
       var fred = new System.Collections.Generic.List<String> { foo, foo.Length.ToString() };
       var z = fred.Count;
       var mmm = count + z + CsharpCompletion.PrivateStaticField1;
       var nnn = this.InstanceMethod1(mmm);
      }
  }
}

सभी प्रकार के और स्थिर प्रकार के सदस्य कंकाल कोड में उपलब्ध हैं। यह सफलतापूर्वक संकलित करता है। उस समय, स्थानीय संस्करण का प्रकार निर्धारित करना प्रतिबिंब के माध्यम से सीधा है।

क्या यह संभव है:

  • emacs में शक्तियां चलाने की क्षमता
  • सी # कंपाइलर वास्तव में तेज है। मेरी मशीन पर, इन-मेमोरी असेंबली को संकलित करने में लगभग 0.5 का समय लगता है। के-केस्ट्रोक्स विश्लेषण के लिए पर्याप्त उपवास नहीं है, लेकिन उपवास सूची की ऑन-डिमांड पीढ़ी का समर्थन करने के लिए पर्याप्त तेज़ है।

मैंने अभी तक LINQ में नहीं देखा है।
यह एक बहुत बड़ी समस्या होगी क्योंकि सिमेंटिक लेक्सर / पार्सर एमएसीएस में C # के लिए है, LINQ नहीं करता है।


4
प्रकार के फू को संकलक द्वारा प्रकार के अनुमान के माध्यम से समझा जाता है और भरा जाता है। मुझे संदेह है कि तंत्र पूरी तरह से अलग हैं। शायद टाइप-इनफेक्शन इंजन में हुक होता है? बहुत कम से कम मैं एक टैग के रूप में 'टाइप-इनफेक्शन' का उपयोग करूंगा।
जॉर्ज मौअर

3
एक "नकली" ऑब्जेक्ट मॉडल बनाने की आपकी तकनीक जिसमें सभी प्रकार हैं लेकिन वास्तविक वस्तुओं में से कोई भी शब्दार्थ एक अच्छा नहीं है। इस तरह मैंने दिन में वापस दृश्य इंटरडेव में JScript के लिए IntelliSense किया; हम IE ऑब्जेक्ट मॉडल का "नकली" संस्करण बनाते हैं जिसमें सभी विधियाँ और प्रकार होते हैं लेकिन कोई भी दुष्प्रभाव नहीं होता है, और फिर संकलित समय में पार्स किए गए कोड पर थोड़ा दुभाषिया चलाते हैं और देखते हैं कि कौन सा प्रकार वापस आता है।
एरिक लिपर्ट

जवाबों:


202

मैं आपके लिए वर्णन कर सकता हूं कि हम "वास्तविक" सी # आईडीई में कुशलतापूर्वक कैसे करते हैं।

पहली चीज जो हम करते हैं वह एक पास है जो स्रोत कोड में केवल "शीर्ष स्तर" सामान का विश्लेषण करता है। हम सभी विधि निकायों को छोड़ देते हैं। यह हमें प्रोग्राम के स्रोत कोड में नामस्थान, प्रकार और विधियों (और निर्माणकर्ता, आदि) के बारे में जानकारी का एक डेटाबेस बनाने के लिए जल्दी से अनुमति देता है। यदि आप कीस्ट्रोक्स के बीच करने की कोशिश कर रहे हैं तो हर विधि निकाय में कोड की हर एक पंक्ति का विश्लेषण करने में बहुत लंबा समय लगेगा।

जब IDE को किसी विशेष निकाय के अंदर एक विशेष अभिव्यक्ति के प्रकार को काम करने की आवश्यकता होती है - तो कहें कि आपने "foo" टाइप किया है। और हमें यह पता लगाने की आवश्यकता है कि फू के सदस्य क्या हैं - हम एक ही काम करते हैं; हम उतने ही काम को छोड़ देते हैं, जितना हम कर सकते हैं।

हम एक पास से शुरू करते हैं जो केवल स्थानीय चर का विश्लेषण करता है उस पद्धति के भीतर घोषणाओं का । जब हम उस पास को चलाते हैं तो हम "स्कोप" और "नाम" की एक जोड़ी से एक "टाइप निर्धारक" की मैपिंग करते हैं। "प्रकार निर्धारक" एक ऐसी वस्तु है जो "यदि मुझे आवश्यकता है तो" मैं इस स्थानीय के प्रकार को काम कर सकता हूं। स्थानीय के प्रकार को काम करना महंगा हो सकता है इसलिए हम उस काम को स्थगित करना चाहते हैं यदि हमें आवश्यकता है।

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

String x = "hello";
var y = x.ToCharArray();
var z = from foo in y where foo.

और अब हमें यह समझने की जरूरत है कि फू टाइप चार का है। हम एक डेटाबेस का निर्माण करते हैं जिसमें सभी मेटाडेटा, विस्तार विधियाँ, स्रोत कोड प्रकार, और इसी तरह की अन्य चीजें हैं। हम एक डेटाबेस बनाते हैं जिसमें x, y और z के लिए टाइप निर्धारक होते हैं। हम दिलचस्प अभिव्यक्ति वाले कथन का विश्लेषण करते हैं। हम इसे वाक्य-रचना में बदलकर शुरू करते हैं

var z = y.Where(foo=>foo.

फू के प्रकार को काम करने के लिए हमें पहले y के प्रकार को जानना चाहिए। तो इस बिंदु पर हम टाइप निर्धारणकर्ता से पूछते हैं "वाई का प्रकार क्या है"? इसके बाद एक एक्सप्रेशन मूल्यांकनकर्ता शुरू होता है जो x.ToCharArray () को पार्स करता है और पूछता है कि "x का प्रकार क्या है"? हमारे पास इसके लिए एक प्रकार का निर्धारणकर्ता है जो कहता है कि "मुझे वर्तमान संदर्भ में" स्ट्रिंग "देखने की आवश्यकता है"। वर्तमान प्रकार में कोई प्रकार स्ट्रिंग नहीं है, इसलिए हम नाम स्थान में देखते हैं। यह वहां नहीं है इसलिए हम निर्देशों का उपयोग करते हुए देखते हैं और पता चलता है कि "सिस्टम का उपयोग करना" है और सिस्टम में एक प्रकार का स्ट्रिंग है। ठीक है, ताकि एक्स का प्रकार हो।

हम तब System.String के मेटाडेटा को ToCharArray के प्रकार के लिए क्वेरी करते हैं और यह कहते हैं कि यह एक System.Char [] है। उत्तम। तो हमारे पास y के लिए एक प्रकार है।

अब हम पूछते हैं कि "System.Char [] का एक तरीका कहाँ है?" नहीं, तो हम निर्देशों का उपयोग कर रहे हैं; हमने पहले से ही एक ऐसे डेटाबेस को प्री-कॉम्पट्यूट किया है जिसमें विस्तार विधियों के सभी मेटाडेटा हैं जो संभवतः उपयोग किए जा सकते हैं।

अब हम कहते हैं, "ठीक है, जहाँ अठारह दर्जन विस्तार विधियाँ हैं, जहाँ स्कोप का नाम दिया गया है, क्या उनमें से किसी का पहला औपचारिक पैरामीटर है जिसका प्रकार System.Char [] के साथ संगत है?" इसलिए हम परिवर्तनीयता परीक्षण का दौर शुरू करते हैं। हालांकि, जहां विस्तार के तरीके सामान्य हैं , जिसका अर्थ है कि हमें टाइप इंट्रैक्शन करना होगा।

मैंने एक विशेष प्रकार के अवरोही इंजन को लिखा है जो पहले तर्क से एक विस्तार विधि तक अधूरा निष्कर्ष बनाने में मदद कर सकता है। हम टाइपकर्ता को चलाते हैं और पता लगाते हैं कि कोई ऐसा तरीका है जो एक लेता है IEnumerable<T>, और यह कि हम System.Char [] से IEnumerable<System.Char>, तो T System.Char से एक अनुमान लगा सकते हैं ।

इस पद्धति का हस्ताक्षर है Where<T>(this IEnumerable<T> items, Func<T, bool> predicate) , और हम जानते हैं कि टी सिस्टम है। हम यह भी जानते हैं कि कोष्ठक के अंदर विस्तार विधि के लिए पहला तर्क एक लंबोदर है। तो हम एक लैम्बडा एक्सप्रेशन टाइप अवर को शुरू करते हैं जो कहता है कि "औपचारिक पैरामीटर foo को सिस्टम.चार्ज माना जाता है", बाकी लैम्बडा का विश्लेषण करते समय इस तथ्य का उपयोग करें।

अब हमारे पास लैम्ब्डा के शरीर का विश्लेषण करने के लिए आवश्यक सभी जानकारी है, जो "फू" है। हम फू के प्रकार को देखते हैं, हमें पता चलता है कि लैम्ब्डा बाइंडर के अनुसार यह System.Char है, और हम कर रहे हैं; हम System.Char के लिए टाइप जानकारी प्रदर्शित करते हैं।

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

सौभाग्य!


8
एरिक, पूर्ण उत्तर के लिए धन्यवाद। आपने मेरी आँखें काफी खोल दी हैं। Emacs के लिए, मैं एक गतिशील, बीच-कीस्ट्रोक्स इंजन का उत्पादन करने के लिए इच्छुक नहीं था, जो उपयोगकर्ता अनुभव की गुणवत्ता के मामले में विज़ुअल स्टूडियो के साथ प्रतिस्पर्धा करेगा। एक चीज के लिए, मेरे डिजाइन में निहित ~ 0.5s विलंबता के कारण, emacs- आधारित सुविधा है और केवल ऑन-डिमांड रहेगी; कोई टाइप-फ़ॉरवर्ड सुझाव नहीं। दूसरे के लिए - मैं var स्थानीय लोगों के बुनियादी समर्थन को लागू करूंगा, लेकिन जब मैं बाल प्राप्त करूंगा, या जब निर्भरता का ग्राफ एक निश्चित सीमा से अधिक हो जाएगा, तो मैं खुशी से पंट करूंगा। निश्चित नहीं है कि वह सीमा अभी तक क्या है। एक बार फिर धन्यवाद।
चीजो

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

21
@Dan: मैंने सोर्स कोड देखा है (या लिखा है) और यह मेरे दिमाग को चकरा देता है कि यह भी काम करता है। :-) वहाँ कुछ बालों सामान है।
एरिक लिपर्ट

11
ग्रहण लोग शायद इसे बेहतर करते हैं क्योंकि वे सी # संकलक और आईडीई टीम की तुलना में अधिक भयानक हैं ।
एरिक लिपर्ट

23
मुझे यह बेवकूफी भरी टिप्पणी करना बिल्कुल याद नहीं है। इसका कोई मतलब भी नहीं है। मैं नशे में धुत हो गया होगा। माफ़ करना।
टॉमस आंद्रले

15

मैं आपको मोटे तौर पर बता सकता हूं कि डेल्फी आईडीई इंटेलीजेंस करने के लिए डेल्फी कंपाइलर के साथ कैसे काम करता है (कोड अंतर्दृष्टि क्या डेल्फी इसे कहते हैं)। यह C # पर 100% लागू नहीं है, लेकिन यह एक दिलचस्प दृष्टिकोण है जो विचार के योग्य है।

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

पार्स मोटे तौर पर एलएल (2) पुनरावर्ती वंश है, अभिव्यक्ति को छोड़कर, जो ऑपरेटर पूर्वता का उपयोग करके पार्स किया जाता है। डेल्फी के बारे में अलग-अलग चीजों में से एक यह है कि यह एक एकल-पास भाषा है, इसलिए इसका उपयोग करने से पहले निर्माण को घोषित करने की आवश्यकता है, इसलिए उस जानकारी को बाहर लाने के लिए किसी शीर्ष-स्तरीय पास की आवश्यकता नहीं है।

सुविधाओं के इस संयोजन का मतलब है कि पार्सर के पास किसी भी बिंदु के लिए कोड जानकारी के लिए आवश्यक सभी जानकारी है जहां इसकी आवश्यकता है। जिस तरह से यह काम करता है वह यह है: आईडीई कर्सर की स्थिति के संकलक के लेक्सर को सूचित करता है (बिंदु जहां कोड अंतर्दृष्टि वांछित है) और लेक्सर इसे एक विशेष टोकन में बदल देता है (इसे किबिज टोकन कहा जाता है)। जब भी पार्सर इस टोकन से मिलता है (जो कहीं भी हो सकता है) यह जानता है कि यह संपादक के पास वापस आने वाली सभी सूचनाओं को वापस भेजने का संकेत है। यह एक longjmp का उपयोग करता है क्योंकि यह सी में लिखा है; यह क्या करता है यह सिंटैक्टिक कंस्ट्रक्शन (यानी व्याकरणिक संदर्भ) के प्रकार के अंतिम कॉलर को सूचित करता है किबिट्ज बिंदु में पाया गया था, साथ ही साथ उस बिंदु के लिए आवश्यक सभी प्रतीकात्मक तालिकाओं। उदाहरण के लिए, यदि संदर्भ एक अभिव्यक्ति में है जो एक विधि का एक तर्क है, तो हम विधि अधिभार की जांच कर सकते हैं, तर्क प्रकारों को देख सकते हैं, और केवल उन प्रतीकों को हल कर सकते हैं जो उस तर्क प्रकार को हल कर सकते हैं (यह एक में कटौती करता है) ड्रॉप-डाउन में बहुत अप्रासंगिक अपराध)। यदि यह एक नेस्टेड स्कोप रेफरेंस संदर्भ में है (उदाहरण के लिए एक "।") के बाद, पार्सर ने स्कोप के संदर्भ को वापस सौंप दिया है, और आईडीई उस स्कोप में पाए गए सभी प्रतीकों को फिर से जोड़ सकता है।

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

अब, विशिष्ट प्रश्न के लिए: के साथ घोषित चर के प्रकार का वर्णन varपास्कल जिस तरह से निरंतर होता है, उसके बराबर होता है। यह इनिशियलाइज़ेशन एक्सप्रेशन के प्रकार से आता है। ये प्रकार नीचे से ऊपर तक बनाए गए हैं। यदि xप्रकार का है Integer, और yप्रकार का है Double, तो प्रकार का x + yहोगा Double, क्योंकि वे भाषा के नियम हैं; आदि आप इन नियमों का पालन करते हैं जब तक कि आपके पास दाहिने हाथ की ओर पूर्ण अभिव्यक्ति के लिए एक प्रकार नहीं है, और यह वह प्रकार है जो आप बाईं ओर प्रतीक के लिए उपयोग करते हैं।


7

यदि आप सार सिंटैक्स ट्री बनाने के लिए अपने स्वयं के पार्सर को लिखना नहीं चाहते हैं, तो आप पार्सर्स का उपयोग शार्पडेवलप या मोनोडेवलप से देख सकते हैं , जो दोनों खुले स्रोत हैं।


4

Intellisense सिस्टम आमतौर पर एक सार सिंटैक्स ट्री का उपयोग करके कोड का प्रतिनिधित्व करते हैं, जो उन्हें कंपाइलर की तरह ही कमोबेश उसी तरह के फंक्शन को 'var' वेरिएबल में असाइन करने की सुविधा देता है। यदि आप VS Intellisense का उपयोग करते हैं, तो आप नोटिस कर सकते हैं कि जब तक आप वैध (resolvable) असाइनमेंट अभिव्यक्ति दर्ज करना समाप्त नहीं कर लेते, तब तक यह आपको var का प्रकार नहीं देगा। यदि अभिव्यक्ति अभी भी अस्पष्ट है (उदाहरण के लिए, यह अभिव्यक्ति के लिए सामान्य तर्कों का पूरी तरह से अनुमान नहीं लगा सकता है), तो var प्रकार हल नहीं होगा। यह एक काफी जटिल प्रक्रिया हो सकती है, क्योंकि आपको प्रकार को हल करने के लिए पेड़ में काफी गहराई तक चलने की आवश्यकता हो सकती है। उदाहरण के लिए:

var items = myList.OfType<Foo>().Select(foo => foo.Bar);

वापसी का प्रकार है IEnumerable<Bar>, लेकिन यह जानना आवश्यक है:

  1. myList प्रकार है कि लागू होता है IEnumerable
  2. एक विस्तार विधि है OfType<T> जो IEnumerable पर लागू होती है।
  3. परिणामी मूल्य है IEnumerable<Foo>और एक विस्तार विधि है Selectजो इस पर लागू होती है।
  4. लंबोदर अभिव्यक्ति foo => foo.Barमें फू के प्रकार का पैरामीटर फू है। यह Select के उपयोग से अनुमान लगाया जाता है, जो एक लेता है Func<TIn,TOut>और चूंकि TIn ज्ञात होता है (Foo), फू का प्रकार अनुमान किया जा सकता है।
  5. प्रकार फू में एक संपत्ति बार है, जो टाइप बार का है। हम जानते हैं कि चुनिंदा रिटर्न IEnumerable<TOut>और टुट को लंबोदर अभिव्यक्ति के परिणाम से अनुमान लगाया जा सकता है, इसलिए परिणामी प्रकार के आइटम होने चाहिए IEnumerable<Bar>

सही, यह बहुत गहरा हो सकता है। मैं सभी निर्भरताओं को हल करने के साथ सहज हूं। बस इस बारे में सोचते हुए, मैंने जो पहला विकल्प बताया - संकलन और आह्वान - बिल्कुल स्वीकार्य नहीं है, क्योंकि कोड को लागू करने के दुष्प्रभाव हो सकते हैं, जैसे डेटाबेस को अपडेट करना, और ऐसा कुछ नहीं है जो एक संपादक को करना चाहिए। संकलन ठीक है, आह्वान नहीं है। जहां तक ​​एएसटी का निर्माण होता है, मुझे नहीं लगता कि मैं ऐसा करना चाहता हूं। वास्तव में मैं उस नौकरी को संकलक के लिए टालना चाहता हूं, जो पहले से ही जानता है कि यह कैसे करना है। मैं कंपाइलर से पूछना चाहता हूं कि वह मुझे बताए कि मैं क्या जानना चाहता हूं। मुझे बस एक सरल उत्तर चाहिए।
चेसो

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

1
@ चेहेसो: कंपाइलर उस प्रकार के विश्लेषण को सेवा के रूप में पेश नहीं करता है। मुझे उम्मीद है कि भविष्य में यह होगा लेकिन कोई वादा नहीं करता।
एरिक लिपर्ट

हां, मुझे लगता है कि जाने का तरीका हो सकता है - सभी निर्भरता को हल करें और फिर आईएल का संकलन और निरीक्षण करें। @, जानने के लिए अच्छा है। अभी के लिए अगर मैं पूर्ण एएसटी विश्लेषण करने की इच्छा नहीं रखता हूं, तो मुझे मौजूदा उपकरणों का उपयोग करके इस सेवा का उत्पादन करने के लिए एक गंदे हैक का सहारा लेना चाहिए। उदाहरण के लिए, कोड के एक बुद्धिमानी से निर्मित टुकड़े को संकलित करें और फिर जवाब पाने के लिए ILDASM (या समान) का उपयोग प्रोग्रामेटिक रूप से करें।
चीज़ो

4

चूंकि आप Emacs को लक्षित कर रहे हैं, इसलिए CEDET सूट के साथ शुरुआत करना सबसे अच्छा हो सकता है। सभी विवरण जो एरिक लिपर्ट पहले से ही C ++ के CEDET / अर्थ टूल में कोड विश्लेषक में शामिल हैं। एक सी # पार्सर भी है (जिसे शायद थोड़ा टीएलसी की जरूरत है) इसलिए केवल गायब हुए हिस्से सी # के लिए आवश्यक भागों को ट्यून करने से संबंधित हैं।

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

डैनियल का जवाब पार्सिंग और विश्लेषण करने के लिए मोनड्यूवल का उपयोग करने का सुझाव देता है। यह मौजूदा सी # पार्सर के बजाय एक वैकल्पिक तंत्र हो सकता है, या इसका उपयोग मौजूदा पार्सर को बढ़ाने के लिए किया जा सकता है।


ठीक है, मुझे CEDET के बारे में पता है, और मैं शब्दार्थ के लिए contrib निर्देशिका में C # समर्थन का उपयोग कर रहा हूं। सिमेंटिक स्थानीय चर और उनके प्रकारों की सूची प्रदान करता है। एक पूरा इंजन उस सूची को स्कैन कर सकता है और उपयोगकर्ता को सही विकल्प प्रदान कर सकता है। समस्या तब होती है जब चर है var। सिमेंटिक सही रूप से इसे var के रूप में पहचानता है, लेकिन प्रकार का अनुमान प्रदान नहीं करता है। मेरा प्रश्न विशेष रूप से था कि कैसे संबोधित किया जाए । मैंने मौजूदा CEDET को पूरा करने में भी भाग लिया, लेकिन मैं यह पता नहीं लगा सका कि कैसे। CEDET के लिए प्रलेखन ... आह ... पूरा नहीं है।
चेसो

साइड कमेंट - CEDET निश्चित रूप से महत्वाकांक्षी है, लेकिन मुझे इसका उपयोग करना और विस्तार करना कठिन लगा। वर्तमान में पार्सर "नेमस्पेस" को C # में एक क्लास इंडिकेटर के रूप में मानता है। मैं यह भी पता नहीं लगा सका कि "नामस्थान" को एक अलग वाक्यविन्यास तत्व के रूप में कैसे जोड़ा जाए। ऐसा करने से अन्य सभी वाक्यात्मक विश्लेषणों को रोक दिया गया, और मैं यह पता नहीं लगा सका कि क्यों। मैंने पहले कठिनाई को पूरा करने की रूपरेखा के साथ मुझे समझाया था। इन समस्याओं से परे, टुकड़ों के बीच सीम और ओवरलैप हैं। एक उदाहरण के रूप में, नेविगेशन अर्थ और सीनेटर दोनों का हिस्सा है। CEDET मोहक लगता है, लेकिन अंत में ... यह करने के लिए प्रतिबद्ध बहुत बुरा है।
चीज़ो

चेसो, यदि आप CEDET के कम प्रलेखित भागों में से सबसे अधिक प्राप्त करना चाहते हैं, तो आपका सबसे अच्छा शर्त मेलिंग सूची की कोशिश करना है। उन क्षेत्रों में प्रश्नों को हल करना आसान है जिन्हें अभी तक अच्छी तरह से विकसित नहीं किया गया है, इसलिए अच्छे समाधान निकालने के लिए, या मौजूदा लोगों को समझाने के लिए कुछ पुनरावृत्तियों की आवश्यकता होती है। सी # के लिए विशेष रूप से, क्योंकि मुझे इसके बारे में कुछ भी पता नहीं है, इसलिए कोई भी सरल उत्तर नहीं होगा।
एरिक

2

यह अच्छा करने के लिए एक कठिन समस्या है। मूल रूप से आपको अधिकांश लेक्सिंग / पार्सिंग / टाइपेकिंग के माध्यम से भाषा की कल्पना / संकलक को मॉडल करना होगा और स्रोत कोड का एक आंतरिक मॉडल बनाना होगा जिसे आप तब क्वेरी कर सकते हैं। एरिक इसका विस्तार से वर्णन करता है C # के लिए। आप हमेशा एफ # कंपाइलर सोर्स कोड (एफ # सीटीपी का हिस्सा) डाउनलोड कर सकते हैं और एफ # कंपाइलर से service.fsiबाहर निकलने वाले इंटरफ़ेस को देखने के लिए एक नज़र डाल सकते हैं, जो एफ # भाषा सेवा इंटेलीजेंस प्रदान करने के लिए खपत करती है, हीन प्रकारों के लिए टूलटिप्स, आदि। एक संभावित 'इंटरफ़ेस' की भावना यदि आपके पास पहले से ही एक कॉल करने के लिए एपीआई के रूप में कंपाइलर उपलब्ध था।

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

संक्षेप में, मुझे लगता है कि 'कम बजट' संस्करण को अच्छी तरह से करना बहुत कठिन है, और 'वास्तविक' संस्करण बहुत अच्छा है, बहुत अच्छा है। (जहाँ 'कठिन' यहाँ 'प्रयास' और 'तकनीकी कठिनाई' दोनों को मापता है।)


हां, "कम बजट" संस्करण में कुछ स्पष्ट सीमाएं हैं। मैं यह तय करने की कोशिश कर रहा हूं कि "काफी अच्छा" क्या है, और क्या मैं उस बार को पूरा कर सकता हूं। अपने स्वयं के अनुभव में मैंने अब तक जो कुछ भी किया है, उसे डॉगफूडिंग करते हुए, यह एम # को लिखते हुए बहुत अच्छे बनाता है।
चेसो


0

समाधान "1" के लिए आपके पास .NET 4 में एक नई सुविधा है जो इसे जल्दी और आसानी से करने के लिए है। इसलिए यदि आप अपने प्रोग्राम को .NET 4 में परिवर्तित कर सकते हैं तो यह आपका सबसे अच्छा विकल्प होगा।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.