2009-06-02 18 views
18

सी # में मुझे एक विधि को परिभाषित करने में सक्षम होना चाहिए, लेकिन इसे एक या दो रिटर्न प्रकार लौटाएं। जब मैं इसे करने का प्रयास करता हूं तो संकलक मुझे एक त्रुटि देता है, लेकिन यह जानने के लिए पर्याप्त स्मार्ट क्यों नहीं है कि मुझे किस विधि को कॉल करने की आवश्यकता है?वापसी मूल्यों को ओवरलोड करना

int x = FunctionReturnsIntOrString(); 

संकलक मुझे विभिन्न कार्यों के साथ दो कार्यों को रोकने से क्यों रोक देगा?

+1

charlieday, क्या आप कुछ और विवरण प्रदान कर सकते हैं कि आप एक ऐसी विधि क्यों चाहते हैं जो एकाधिक रिटर्न प्रकारों को वापस कर सके? मुझे आश्चर्य है कि सिस्टम नेमस्पेस में कन्वर्ट क्लास का पालन करने के लिए एक अच्छा मॉडल हो सकता है। इसमें विभिन्न रिटर्न प्रकारों के कई रूपांतरण विधियां हैं लेकिन यह विधि के नाम पर रिटर्न प्रकार को एन्कोड करता है। जैसे ToBoolean, ToByte, ToChar, आदि –

+4

कारण यह है कि आपके परिदृश्य में, प्रकार की जानकारी "दोनों तरीकों से बहती जा रही है"। भाषा डिजाइन का एक बुनियादी सिद्धांत यह है कि आप स्वतंत्र रूप से अभिव्यक्ति के प्रत्येक भाग के प्रकार का विश्लेषण करने में सक्षम होना चाहिए। हम स्वतंत्र रूप से कॉल अभिव्यक्ति के प्रकार को निर्धारित करने में सक्षम होना चाहते हैं जो इसे सौंपा जा रहा है। इस नियम का अपवाद लैम्ब्डा अभिव्यक्ति है; लैम्ब्डा अभिव्यक्तियों में प्रकार की जानकारी "प्रवाह दोनों तरीकों" बनाना बहुत मुश्किल था। विवरण के लिए मेरे ब्लॉग में "अज्ञात विधियों बनाम लैम्ब्डा अभिव्यक्ति" देखें। –

+1

आप यहां मेरा उत्तर http: // stackoverflow देख सकते हैं।कॉम/प्रश्न/1366136/ओवरलोडिंग-ऑन-आधार-ऑफ-रिटर्न-टाइप-केवल/14337184 # 14337184 –

उत्तर

21

हालांकि यह इस विशेष परिदृश्य में स्पष्ट हो सकता है, ऐसे कई परिदृश्य हैं जहां यह वास्तव में स्पष्ट नहीं है। चलो एक उदाहरण

class Bar { 
    public static int Foo(); 
    public static string Foo(); 
} 

के लिए निम्न API ले यह बस संभव नहीं है संकलक पता करने के लिए के लिए जो फू निम्न परिदृश्यों

void Ambiguous() { 
    Bar.Foo(); 
    object o = Bar.Foo(); 
    Dog d = (Dog)(Bar.Foo()); 
    var x = Bar.Foo(); 
    Console.WriteLine(Bar.Foo()); 
} 

इन में कॉल करने के लिए बस कुछ संक्षिप्त नमूने हैं। अधिक संकुचित और बुरी समस्याएं निश्चित रूप से मौजूद हैं।

+1

आप को ओवरलोडेड पैरामीटर के साथ एक ही समस्या हो सकती है और सी # कंपाइलर आपको चेतावनी देता है। रिटर्न प्रकारों के बारे में चेतावनी के साथ क्या समस्या है? – charlieday

+1

अधिभारित पैरामीटर के साथ सी # में ऐसे उदाहरण का वर्णन करें। सिद्धांत रूप में सी # कंपाइलर अस्पष्टता के चेहरे में एक त्रुटि संदेश उत्पन्न करने की अनुमति देगा। यह सिर्फ एक नहीं उठाएगा और आपको एक त्रुटि देगा। –

+1

@charlieday, मुझे विश्वास नहीं है कि चेतावनी देने के लिए सी # कंपाइलर की क्षमता समस्या है। मेरा * अनुमान * मुद्दा लागत की रेखा के साथ अधिक है। यह एक ऐसी सुविधा है जिसमें सीमित मूल्य और परिदृश्यों की एक गैर-मामूली संख्या है जहां यह पूरी तरह विफल हो जाएगी (मेरे नमूने देखें)। कम लाभ बनाम लागत के कारण अक्सर ऐसी विशेषताएं कट जाती हैं। मैं सी # टीम पर काम नहीं करता हूं और यह बात नहीं कर सकता कि यह कभी भी एक डिजाइन मीटिंग में आया है या नहीं। सच में, मुझे यह भी यकीन नहीं है कि यह आईएल स्तर पर कानूनी है या नहीं। – JaredPar

2

वापसी का प्रकार विधि के हस्ताक्षर का हिस्सा नहीं है, केवल नाम और पैरामीटर प्रकार। इस वजह से, आपके पास दो विधियां नहीं हो सकती हैं जो केवल रिटर्न प्रकार से भिन्न होती हैं। इसके आस-पास जाने का एक तरीका आपके ऑब्जेक्ट को वापस करने की विधि के लिए होगा, फिर कॉलिंग कोड को इसे एक int या स्ट्रिंग में डालना होगा।

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

+0

लेकिन आईएल में, वापसी प्रकार का उपयोग विधि की पहचान करने के लिए किया जाता है ... ildasm का उपयोग करके आप रेट्रान प्रकार निर्दिष्ट कर सकते हैं एक कॉलवर्ट निर्देश निर्दिष्ट है। – charlieday

+0

इससे कोई फर्क नहीं पड़ता कि आईएल में क्या है - सी # विनिर्देश क्या है, विशेष रूप से धारा 3.6, जहां यह कहता है "एक विधि के हस्ताक्षर में विशेष रूप से रिटर्न प्रकार शामिल नहीं है"। Http://msdn.microsoft.com/en-us/library/aa691131(loband).aspx – Bevan

+0

देखें - याद रखें, एमएसआईएल में "ओवरलोड रिज़ॉल्यूशन" जैसी कोई चीज़ नहीं है। आईएल में, आपको हमेशा स्पष्ट रूप से यह बताना होगा कि आप किस विधि को बुला रहे हैं। सी # में यह मामला नहीं है। –

10

क्या आप सही प्रकार को वापस करने के लिए जेनेरिक का उपयोग करने के बारे में हैं।

public T SomeFunction<T>() 
{ 
    return T 
} 

int x = SomeFunction<int>(); 
string y = SomeFunction<string>(); 

नोट: यह कोड

+0

यह कभी-कभी थोड़ा मुश्किल हो सकता है लेकिन यदि सही तरीके से किया जाता है तो निश्चित रूप से जाने का तरीका निश्चित रूप से होता है। मैं आमतौर पर एक कदम आगे जाता हूं और फ़ंक्शन बूलियन घोषित करता हूं, और वापसी वस्तु संदर्भ द्वारा भेजी जाती है। इस तरह से आप जानते हैं कि किसी भी कास्टिंग मुद्दों से बचने के दौरान कोई त्रुटि आई है। यह आपको करने की शक्ति देता है: अगर (! कुछ फ़ंक्शन (रेफ रिटर्नस्टिंग)) DoErrorHandling(); –

+6

यह कोड काम नहीं करता है। –

1

परीक्षण नहीं किया गया है सी # में कोई overridin वापसी प्रकार है, आईएल अधिभावी लेकिन सी # नहीं ... अभी तक उस तरह का समर्थन करता है।

2

क्योंकि कभी कभी यह वास्तव में नहीं बता सकता जो एक यह तो उपयोग करना चाहिए (अपने उदाहरण यह हो सकता है, लेकिन सभी मामलों रहे हैं कि स्पष्ट):

void SomeMethod(int x) { ... } 
void SomeMethod(string x) { ... } 

इस संदर्भ में, अगर आप फोन SomeMethod(FunctionReturnsIntOrString()) क्या करना चाहिए संकलक करते हैं?

9

केवल वापसी मूल्यों के साथ भिन्न होने वाला फ़ंक्शन ओवरलोडिंग के लिए योग्य नहीं है।

int x = FunctionReturnsIntOrString(); 
double y = FunctionReturnsIntOrString(); 

उपरोक्त मामले संकलक सही कार्यों की पहचान लेकिन जिन मामलों में मान पर विचार कर सकते में निर्दिष्ट नहीं हैं, यह अस्पष्ट है।

FunctionReturnsIntOrString(); //int version 
FunctionReturnsIntOrString(); //double version 

कंपाइलर अधिभारित विधियों को यहां हल नहीं कर सकता है।

+1

ठीक है ... वह एक और समझ में आता है ... वापसी मूल्य को त्याग दिया। – charlieday

3

मुझे लगता है कि आप को गंभीरता से पुनर्विचार करने के लिए आप क्या कर रहे हैं और कैसे हैं, लेकिन आप यह कर सकते हैं: इस तरह यह लागू करने से

int i = FunctionReturnsIntOrString<int>(); 
string j = FunctionReturnsIntOrString<string>(); 

:

private T FunctionReturnsIntOrString<T>() 
{ 
    int val = 1; 
    if (typeof(T) == typeof(string) || typeof(T) == typeof(int)) 
    { 
     return (T)(object)val; 
    } 
    else 
    { 
     throw new ArgumentException("or some other exception type"); 
    } 
} 

लेकिन sooo कई देखते हैं कारण नहीं है।

+0

मुझे लगता है कि ऐसा करने का प्राथमिक कारण यह नहीं है क्योंकि यह टी == टाइपऑफ (स्ट्रिंग) अगर रनटाइम पर अमान्य कैस्टएक्सप्शन फेंक देगा। समाधान देने के लिए –

+0

+1, लेकिन यह भी समझाते हुए कि यह शायद एक अच्छा प्रोग्रामिंग अभ्यास नहीं है। – ebrown

+3

हालांकि यह खराब गंध करता है, मैं सोच रहा हूं कि क्या आप कारण बता सकते हैं कि इस तरह कोड क्यों नहीं लिखना चाहिए? –

26
C# 3.0 language specification की धारा 1.6.6 के अंतिम पैराग्राफ से

:

The signature of a method must be unique in the class in which the method is declared. The signature of a method consists of the name of the method, the number of type parameters and the number, modifiers, and types of its parameters. The signature of a method does not include the return type.

आईएल में दो तरीकों वापसी प्रकार से अकेले में भिन्नता हो सकती है, लेकिन प्रतिबिंब के बाहर वहाँ एक तरीका है कि केवल अलग है कॉल करने के लिए किसी भी तरह है वापसी प्रकार हो।

+5

spec अंश के लिए धन्यवाद! –

+0

"किसी विधि के हस्ताक्षर में वापसी प्रकार शामिल नहीं है", इस पंक्ति ने मुझे प्रबुद्ध किया। – Gaddigesh

1

आपको किसी बुलाए गए विधि को मान असाइन करने की आवश्यकता नहीं है। उदाहरण के लिए:

int FunctionReturnsIntOrString() {return 0;} 
string FunctionReturnsIntOrString() {return "some string";} 

//some code 
//... 

int integer = FunctionReturnsIntOrString(); //It probably could have figured this one out 

FunctionReturnsIntOrString(); //this is valid, which method would it call? 
4

यह वाक्य रचना आप प्रश्न में बाहर से पता चला पाने के लिए संभव है, लेकिन आप वहाँ पाने के लिए चालाकी से काफी अच्छी रकम में संलग्न करने के लिए है।

चलिए समस्या को और अधिक ठोस रूप से स्थापित करते हैं। मुझे लगता है कि मुख्य बिंदु, वाक्यविन्यास है। हम इस हैं:

int intValue = GetData(); 
string stringValue = GetData(); 
DateTime[] dateTimeArrayValue = GetData(); 

हालांकि, हम इस काम करने के लिए नहीं करना चाहती:

double doubleValue = GetData(); 
DateTime? nullableDateTimeValue = GetData(); 

आदेश यह पूरा करने के लिए, हम GetData() से वापसी मान में एक मध्यस्थ वस्तु का उपयोग करने के लिए है, जिसकी परिभाषा ऐसा लगता है:

public class Data 
{ 
    public int IntData { get; set; } 
    public string StringData { get; set; } 
    public DateTime[] DataTimeArrayData { get; set; } 

    public MultiReturnValueHelper<int, string, DateTime[]> GetData() 
    { 
     return new MultiReturnValueHelper<int, string, DateTime[]>(
      this.IntData, 
      this.StringData, 
      this.DataTimeArrayData); 
    } 
} 

आपका कार्यान्वयन, बिल्कुल अलग होगा, लेकिन यह करेगा। अब चलिए MultiReturnValueHelper परिभाषित करते हैं।

public class MultiReturnValueHelper<T1, T2, T3> : Tuple<T1, T2, T3> 
{ 
    internal MultiReturnValueHelper(T1 item1, T2 item2, T3 item3) 
     : base(item1, item2, item3) 
    { 
    } 

    public static implicit operator T1(MultiReturnValueHelper<T1, T2, T3> source) 
    { 
     return source.Item1; 
    } 

    public static implicit operator T2(MultiReturnValueHelper<T1, T2, T3> source) 
    { 
     return source.Item2; 
    } 

    public static implicit operator T3(MultiReturnValueHelper<T1, T2, T3> source) 
    { 
     return source.Item3; 
    } 
} 

दोहराएँ T1 के लिए इस परिभाषा, T2, T3, आदि सामान्य मामले के लिए।

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

data["Hello"] = "World"; 
data["infamy"] = new DateTime(1941, 12, 7); 
data[42] = "Life, the universe, and everything"; 

इस वाक्य को पूरा करने के सटीक तंत्र पाठक के लिए एक व्यायाम के रूप में छोड़ दिया जाता है:

एक अन्य एप्लिकेशन के पास निम्न की तरह वाक्यविन्यास सक्षम बनाना है।

इस समस्या के लिए अधिक सामान्य उद्देश्य समाधान (जो मुझे लगता है, एक भेदभावपूर्ण संघ की समस्या के समान) के लिए, कृपया my answer to that question देखें।

+0

इस तरह के कोड से पहले निपटने के बाद: 'डेटा [" हैलो "] =" विश्व "; डेटा ["infamy"] = नया डेटटाइम (1 9 41, 12, 7); डेटा [42] = "जीवन, ब्रह्मांड, और सबकुछ"; ' मुझे इसके साथ कुछ भी नहीं करना है। यदि आपको कभी भी इस तरह वाक्यविन्यास की आवश्यकता है, तो बस मान लें कि आप इसे गलत कर रहे हैं और इसके बजाय टाइप किए गए ऑब्जेक्ट का उपयोग करने पर विचार करना चाहिए। – aaronburro

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