जहां सी # संकलक गलती कोड नहीं है जहां एक स्थिर विधि एक आवृत्ति विधि को कॉल करती है?


110

निम्न कोड में एक स्टैटिक विधि है, Foo()उदाहरण के लिए, एक कॉल विधि Bar():

public sealed class Example
{
    int count;

    public static void Foo( dynamic x )
    {
        Bar(x);
    }

    void Bar( dynamic x )
    {
        count++;
    }
}

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

तो एक डायनामिक पैरामीटर होने के कारण कोड को कैसे संकलित किया जाता है? ReSharper इसे या तो एक त्रुटि के रूप में नहीं दिखाता है।

दृश्य स्टूडियो 2008 में 1: * संपादित करें

संपादित करें 2: जोड़ा sealedक्योंकि यह एक उपवर्ग एक स्थिर हो सकता है कि संभव है Bar(...)विधि। यहां तक ​​कि सीलबंद संस्करण भी संकलित करता है जब यह संभव नहीं होता है कि उदाहरण विधि के अलावा कोई भी विधि रनटाइम पर कॉल की जा सके।


8
बहुत अच्छे प्रश्न के लिए +1
cuongle

40
यह एरिक-लिपर्ट-प्रश्न है।
ओलिवियर जैकोट-डेसकोम्बर्स 15

3
मुझे पूरा यकीन है कि जॉन स्कीट को पता होगा कि इस एशो थियो के साथ क्या करना है?) @ ओलिवियरजैकॉट-डेसॉम्ब्स
हज़ारों

2
@ ओलिवर, जॉन स्कीट शायद संकलन करने के लिए कोड चाहता था, इसलिए संकलक इसे अनुमति देता है :-))
माइक स्कॉट

5
यह एक और उदाहरण है कि आपको dynamicतब तक उपयोग क्यों नहीं करना चाहिए जब तक आपको वास्तव में आवश्यकता न हो।
15

जवाबों:


71

अद्यतन: नीचे उत्तर # 2012 में (# 2018) मई की शुरुआत से पहले लिखा गया था । में क्या सी # 7.3 में नया क्या है , अनुभाग में सुधार अधिभार उम्मीदवारों , मद 1, यह समझाया गया है कि कैसे अधिभार संकल्प नियम तो बदल गया है कि गैर स्थिर भार के जल्दी छोड़ दिए जाते हैं। तो नीचे दिए गए उत्तर (और इस पूरे प्रश्न) में अब तक केवल ऐतिहासिक रुचि है!


(प्री सी # 7.3 :)

किसी कारण से, अधिभार संकल्प हमेशा स्थिर बनाम गैर-स्थैतिक की जाँच करने से पहले सबसे अच्छा मैच पाता है । कृपया इस कोड को सभी स्थिर प्रकारों के साथ आज़माएँ:

class SillyStuff
{
  static void SameName(object o) { }
  void SameName(string s) { }

  public static void Test()
  {
    SameName("Hi mom");
  }
}

यह संकलित नहीं होगा क्योंकि सबसे अच्छा अधिभार एक लेने वाला है string। लेकिन हे, यह एक उदाहरण विधि है, इसलिए कंपाइलर शिकायत करता है (दूसरा-सबसे अच्छा अधिभार लेने के बजाय)।

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

लेट एडिशन: कुछ पृष्ठभूमि जिन पर उन्होंने इस मज़ेदार आदेश को करने के लिए चुना, उन्हें एरिक लिपर्ट के इस ब्लॉग पोस्ट से अनुमान लगाया जा सकता है ।


मूल प्रश्न में कोई अधिभार नहीं हैं। स्थिर अधिभार दिखाने वाले उत्तर प्रासंगिक नहीं हैं। यह जवाब देने के लिए मान्य नहीं है "अगर आपने यह लिखा है ..." क्योंकि मैंने नहीं लिखा है कि :-)
माइक स्कॉट

5
@MikeScott मैं सिर्फ आपको यह समझाने की कोशिश करता हूं कि C # में ओवरलोड रिज़ॉल्यूशन हमेशा इस तरह से होता है: (1) स्टेटिक / नॉन-स्टैटिक की अवहेलना करने वाले सर्वश्रेष्ठ मैच का पता लगाएं। (२) अब हम जानते हैं कि किस अधिभार का उपयोग करना है, तो स्थैतिक की जाँच करें। इस वजह से, जब dynamicभाषा में पेश किया गया था, तो मुझे लगता है कि C # के डिजाइनरों ने कहा: "हम dynamicअभिव्यक्ति के समय (2) संकलन-समय पर विचार नहीं करेंगे ।" इसलिए मेरा उद्देश्य यहां यह विचार करना है कि उन्होंने रनटाइम तक स्थिर बनाम उदाहरण की जांच क्यों नहीं की। मैं कहूंगा, यह जाँच बाध्यकारी समय पर होती है
जेपी स्टिग नीलसन

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

45
मैंने C # कंपाइलर का यह भाग लिखा है, और Jeppe सही है। कृपया इसे वोट करें। ओवरलोड रिज़ॉल्यूशन यह जांचने से पहले होता है कि क्या दी गई विधि एक स्थिर या एक इंस्टेंस विधि है, और इस मामले में हम रनटाइम के लिए अधिभार रिज़ॉल्यूशन को स्थगित कर देते हैं और इसलिए रनटाइम के साथ-साथ स्टेटिक / इंस्टेंस चेक भी। इसके अतिरिक्त, संकलक गतिशील त्रुटियों को खोजने के लिए "सर्वोत्तम प्रयास" में रखता है जो कि व्यापक नहीं है।
क्रिस बर्ट

30

फू का एक पैरामीटर "x" है जो गतिशील है, जिसका अर्थ है कि बार (x) एक गतिशील अभिव्यक्ति है।

उदाहरण के लिए पूरी तरह से संभव होगा जैसे कि विधि:

static Bar(SomeType obj)

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


14
लेकिन जब आप उदाहरण बार विधि निकालते हैं, तो यह अब संकलित नहीं होता है।
जस्टिन हार्वे

1
@Justin दिलचस्प - एक चेतावनी? या कोई त्रुटि? किसी भी तरह, यह केवल विधि-समूह के रूप में मान्य हो सकता है, रनटाइम के लिए पूर्ण अधिभार संकल्प को छोड़कर।
मार्क Gravell

1
@Marc, चूंकि कोई अन्य बार () विधि नहीं है, आप प्रश्न का उत्तर नहीं दे रहे हैं। क्या आप इसे समझा सकते हैं कि केवल एक बार () पद्धति है जिसमें कोई अधिभार नहीं है? जब कोई अन्य तरीका नहीं कहा जा सकता है तो रनटाइम को क्यों स्थगित किया जाए? या है? नोट: मैंने कक्षा को सील करने के लिए कोड को संपादित किया है, जो अभी भी संकलित है।
माइक स्कॉट

1
क्रम को क्यों आस्थगित करें के लिए के रूप में @mike: क्योंकि है कि क्या गतिशील साधन
मार्क Gravell

2
@ माइक असंभव बात नहीं है; जो जरूरी है, वह जरूरी है । गतिशील के साथ पूरा बिंदु यह है कि यह संकलक का काम नहीं है।
मार्क Gravell

9

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

"सही" विधि रनटाइम के दौरान निर्धारित की जाएगी। कंपाइलर यह नहीं जान सकता कि रनटाइम के दौरान कोई वैध तरीका है या नहीं।

"डायनामिक" कीवर्ड को डायनेमिक और स्क्रिप्ट भाषाओं के लिए परिभाषित किया गया है, जहां विधि को किसी भी समय, रनटाइम के दौरान भी परिभाषित किया जा सकता है। क्रेजी स्टफ

यहाँ एक नमूना जो कि ints को संभालता है लेकिन कोई तार नहीं है, क्योंकि विधि उदाहरण पर है।

class Program {
    static void Main(string[] args) {
        Example.Foo(1234);
        Example.Foo("1234");
    }
}
public class Example {
    int count;

    public static void Foo(dynamic x) {
        Bar(x);
    }

    public static void Bar(int a) {
        Console.WriteLine(a);
    }

    void Bar(dynamic x) {
        count++;
    }
}

आप सभी "गलत" कॉल को संभालने के लिए एक विधि जोड़ सकते हैं, जिसे संभाला नहीं जा सकता था

public class Example {
    int count;

    public static void Foo(dynamic x) {
        Bar(x);
    }

    public static void Bar<T>(T a) {
        Console.WriteLine("Error handling:" + a);
    }

    public static void Bar(int a) {
        Console.WriteLine(a);
    }

    void Bar(dynamic x) {
        count++;
    }
}

क्या आपके उदाहरण में कॉलिंग कोड उदाहरण के लिए नहीं होना चाहिए। उदाहरण के लिए ... (...) के बजाय। (...)? क्या आपके उदाहरण में Foo () अप्रासंगिक नहीं है? मैं वास्तव में आपके उदाहरण को नहीं समझता। स्थैतिक सामान्य विधि को जोड़ने से समस्या क्यों होगी? क्या आप विकल्प के रूप में देने के बजाय उस विधि को शामिल करने के लिए अपना उत्तर संपादित कर सकते हैं?
माइक स्कॉट

लेकिन मैंने जो उदाहरण प्रस्तुत किया है, उसमें केवल एक ही उदाहरण विधि है और कोई अतिभार नहीं है इसलिए संकलन-समय पर आप जानते हैं कि ऐसी कोई स्थिर विधियाँ नहीं हैं जिन्हें हल किया जा सके। यदि आप कम से कम एक जोड़ते हैं तो ही स्थिति बदलती है और कोड मान्य होता है।
माइक स्कॉट

लेकिन इस उदाहरण में अभी भी एक से अधिक बार () विधि है। मेरे उदाहरण में केवल एक विधि है। इसलिए किसी भी स्टैटिक बार () विधि को कॉल करने की कोई संभावना नहीं है। कॉल को संकलन-समय पर हल किया जा सकता है।
माइक स्कॉट

@ माइक हो सकता है! = है; गतिशील के साथ, यह ऐसा करने के लिए आवश्यक नहीं है
मार्क Gravell

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