2008-10-08 20 views
8

यह प्रश्न How to indicate that a method was unsuccessful से अनुवर्ती है। Xxx() Tryxxx() पैटर्न कुछ ऐसा है जो कई पुस्तकालयों में बहुत उपयोगी हो सकता है। मैं सोच रहा हूं कि मेरे कोड को डुप्लिकेट किए बिना दोनों कार्यान्वयन की पेशकश करने का सबसे अच्छा तरीका क्या है।"TryParse/Parse like" पैटर्न: इसे लागू करने का सबसे अच्छा तरीका क्या है

क्या सबसे अच्छा है:

public int DoSomething(string a) 
{ 
    // might throw an exception 
} 
public bool TrySomething(string a, out result) 
{ 
    try 
    { 
     result = DoSomething(a) 
     return true; 
    } 
    catch (Exception) 
    { 
     return false; 
    } 

या

public int DoSomething(string a) 
{ 
    int result; 
    if (TrySomething(a, out result)) 
    { 
     return result; 
    } 
    else 
    { 
     throw Exception(); // which exception? 
    } 
} 
public bool TrySomething(string a, out result) 
{ 
    //... 
} 

मैं सहज मान चाहते हैं कि पहला उदाहरण अधिक सही है (यदि आप वास्तव में पता है जो अपवाद हुआ), लेकिन कोशिश नहीं कर सका/पकड़ बहुत महंगा हो? क्या दूसरे उदाहरण में अपवाद को पकड़ने का कोई तरीका है?

+0

मैं आपकी वृत्ति से सहमत हूं (यदि संभव हो तो TryX मामले के अपवाद से बचें) जब तक TryX के आपके कार्यान्वयन को अपवाद नहीं लेना पड़ेगा (यानी अपवाद आपके कोड द्वारा उत्पन्न किया जा रहा है, कोड नहीं आप कॉल करें)। –

+0

इसके अलावा, मुझे यकीन नहीं है कि आपका क्या मतलब है "क्या दूसरे उदाहरण में अपवाद को पकड़ने का कोई तरीका है?" - क्या अपवाद पकड़ो?आप DoSomething से फेंकना चाहते हैं (हालांकि आप जो हुआ उससे अपवाद को फेंक देंगे, सामान्य नहीं)। –

+0

@ जोनाथन: मेरा मतलब था "आंतरिक प्रसंस्करण में हुई अपवाद को दोबारा जोड़ना, जिस तरह से कॉलर जान सकता है कि त्रुटि क्या हुई है" – Luk

उत्तर

13

बनाना TrySomething बस पकड़ने और निगल अपवाद एक बहुत बुरा विचार है। TryXXX पैटर्न का आधा बिंदु अपवादों के प्रदर्शन हिट से बचने के लिए है।

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

public int DoSomething(string input) 
{ 
    int ret; 
    Exception exception = DoSomethingImpl(input, out ret); 
    if (exception != null) 
    { 
     // Note that you'll lose stack trace accuracy here 
     throw exception; 
    } 
    return ret; 
} 

public bool TrySomething(string input, out int ret) 
{ 
    Exception exception = DoSomethingImpl(input, out ret); 
    return exception == null; 
} 

private Exception DoSomethingImpl(string input, out int ret) 
{ 
    ret = 0; 
    if (input != "bad") 
    { 
     ret = 5; 
     return null; 
    } 
    else 
    { 
     return new ArgumentException("Some details"); 
    } 
} 

हालांकि इससे पहले कि आप इसे प्रतिबद्ध करते हैं!

+0

मुझे यह कार्यान्वयन पसंद है, मैं शायद इसे आगे की जांच करूँगा जब मैं कर सकता हूं – Luk

2

पहला उदाहरण सही है यदि आप अपवाद को पकड़ने जा रहे हैं और कुछ भी नहीं करते हैं लेकिन इसके साथ झूठी वापसी करते हैं।

आप नीचे की तरह दिखने के लिए TrySomething को बदल सकते हैं।

public bool TrySomething(string a, out result, bool throwException) 
{ 
    try 
    { 
    // Whatever 
    } 
    catch 
    { 
    if(throwException) 
    { 
     throw; 
    } 
    else 
    { 
     return false; 
    } 
    } 

} 

public bool TrySomething(string a, out result) 
{ 
    return TrySomething(a, out result, false); 
} 

तो DoSomething तरह

public int DoSomething(string a) 
{ 
    int result; 

    // This will throw the execption or 
    // change to false to not, or don't use the overloaded one. 
    TrySomething(a, out result, true) 

    return result;  
} 

देखो आप सार्वजनिक आप इसे एक निजी सदस्य बना सकें से अवगत कराया throwException साथ TrySomething नहीं करना चाहता था, तो होगा।

अपवाद महंगा हो सकता है और आप स्ट्रिंग पर कुछ RegEx जांच कर सकते हैं ताकि किसी को फेंकने से रोका जा सके। यह इस बात पर निर्भर करता है कि आप क्या करने की कोशिश कर रहे हैं।

+0

मेरे पास "throwException" तर्क के साथ संस्करण नहीं होगा; TrySomething बनाम Something को कॉल करने की आपकी पसंद में यह पहले से ही निहित है। यह एक निजी विधि के रूप में ठीक हो सकता है जो सार्वजनिक कार्यान्वयन दोनों के पीछे बैठता है। –

+0

सार्वजनिक तरीकों पर बूल फेंक अपवाद जैसे तर्क होना अच्छा नहीं है - .NET Framework Design दिशानिर्देश देखें। इसके अलावा, अपवादों को निगलना अच्छा नहीं है :) – nightcoder

1

इस मान लिया जाये, सी # है मैं दूसरे उदाहरण कहेंगे

public bool TrySomething(string a, out result) 
{ 
    try 
    { 
     result = DoSomething(a) 
     return true; 
    } 
    catch (Exception) 
    { 
     return false; 
    } 
} 

यह int.TryParse(string s, out int result) में बनाया नकल करता, और मेरे अपने सबसे अच्छे रूप राय में भाषा/पर्यावरण के अनुरूप रहने के लिए।

+2

यह इंटरफ़ेस के साथ संगत है, लेकिन अपवादों के प्रदर्शन हिट से बचने के इरादे से नहीं। यह गलत तरीके से (आईएमओ) * सभी * अपवादों को निगलता है, केवल उन लोगों की बजाय जो कुछ सामान्य रूप से फेंक सकता है। उदाहरण के लिए, मैं नहीं चाहता कि OutOfMemoryException निगल जाए। –

3

मैं आमतौर पर इस पैटर्न का उपयोग करता हूं। इस पर निर्भर करता है कि आंतरिक विधि को कैसे कार्यान्वित किया जाता है या नहीं, यह किसी भी समझ में आता है या नहीं। आप सशर्त पकड़ ब्लॉक का उपयोग करना है, तो यह थोड़ा बुरा प्राप्त कर सकते हैं ...

public object DoSomething(object input){ 
    return DoSomethingInternal(input, true); 
} 

public bool TryDoSomething(object input, out object result){ 
    result = DoSomethingInternal(input, false); 
    return result != null; 
} 

private object DoSomethingInternal(object input, bool throwOnError){ 
    /* do your work here; only throw if you cannot proceed and throwOnError is true */ 
} 
+0

हाँ, लेकिन इसका मतलब है कि DoSomethingInternal को कभी अपवाद नहीं फेंकना चाहिए अगर फेंकने वाला गलत है, जो इसे लागू करने के लिए महंगा हो सकता है, है ना? – Luk

+0

जैसा कि मैंने कहा, आंतरिक विधि के कार्यान्वयन के आधार पर यह बुरा हो सकता है। दूसरे शब्दों में, यदि आप कॉल स्टैक के नीचे नहीं हैं और आप उन विधियों को कॉल करते हैं जो अपवाद फेंक सकते हैं, तो यह सबसे अच्छा पैटर्न नहीं हो सकता है। – Will

+0

हालांकि, अधिकांश समय आप पाएंगे कि आप उन अपवादों को फेंकने से बच सकते हैं जो यहां अन्य उदाहरणों का उपयोग करके फेंक दिए गए थे, इस प्रकार आपको कुछ ढेर-अनचाहे समय बचाते थे। – Will

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

  • कोई संबंधित समस्या नहीं^_^