मैं एक TryParse विधि कैसे डिज़ाइन करूंगा जो एक पार्सिंग त्रुटि के मामले में विस्तृत जानकारी प्रदान करता है?


9

उपयोगकर्ता इनपुट को पार्स करते समय, आमतौर पर अपवादों को फेंकने और पकड़ने के लिए नहीं बल्कि सत्यापन विधियों का उपयोग करने की सिफारिश की जाती है। .NET BCL में, यह उदाहरण के बीच का अंतर होगा, int.Parse(अमान्य डेटा पर एक अपवाद फेंकता है) और int.TryParse( falseअमान्य डेटा पर रिटर्न )।

मैं अपना खुद का डिजाइन कर रहा हूं

Foo.TryParse(string s, out Foo result)

विधि और मैं वापसी मूल्य के बारे में अनिश्चित हूं। मैं bool.NET की अपनी TryParseविधि की तरह उपयोग कर सकता हूं , लेकिन यह त्रुटि के प्रकार के बारे में कोई संकेत नहीं देगा , सटीक कारण के बारे में क्यों s नहीं पार्स किया जा सकता है Foo। (उदाहरण के लिए, sबेमिसाल कोष्ठक, या वर्णों की गलत संख्या, या इसके Barबिना Baz, आदि हो सकते हैं)

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

मैं इस मुद्दे पर बहुत सारे वर्कअराउंड के बारे में सोच सकता हूं (स्टेटस कोड्स लौटाएं, त्रुटि स्ट्रिंग लौटाएं, आउट पैरामीटर के रूप में एक एरर स्ट्रिंग जोड़ें), लेकिन वे सभी उनके संबंधित डाउनसाइड हैं, और मैं भी सम्मेलनों के अनुरूप रहना चाहता हूं .NET फ्रेमवर्क

इस प्रकार, मेरा प्रश्न इस प्रकार है:

.NET फ्रेमवर्क में ऐसी विधियाँ हैं जो (क) अपवादों को फेंकने के बिना इनपुट इनपुट और (ख) अभी भी एक साधारण सच्चे / झूठे बूलियन की तुलना में अधिक विस्तृत त्रुटि जानकारी लौटाती हैं?


1
यह लिंक यह निष्कर्ष नहीं निकालता है कि अपवादों को फेंकने और पकड़ने की अनुशंसा नहीं की जाती है। ऐसे समय होते हैं जो सबसे अच्छा तरीका है Parse()
paparazzo

जवाबों:


5

मैं आपके वापसी प्रकार के लिए मोनड पैटर्न का उपयोग करने की सलाह दूंगा

ParseResult<Foo> foo = FooParser.Parse("input");

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

आप Fooअपने उपयोग के मामले के आधार पर जेनेरिक का उपयोग करने के बजाय एक पार्स परिणाम वर्ग को विशिष्ट बना सकते हैं ।

एक फू विशिष्ट पार्स परिणाम वर्ग कुछ इस तरह लग सकता है:

class FooParseResult
{
     Foo Value { get; set; }
     bool PassedRequirement1 { get; set; }
     bool PassedRequirement2 { get; set; }
}

यहाँ मोनाड संस्करण है:

class ParseResult<T>
{
     T Value { get; set; }
     string ParseErrorMessage { get; set; }
     bool WasSuccessful { get; set; }
}

मैं .net ढांचे में किसी भी तरीके से अवगत नहीं हूं जो विस्तृत पार्स त्रुटि जानकारी लौटाता है।


मैं यूआई लेयर बाइंडिंग के बारे में आपकी टिप्पणी को समझता हूं, लेकिन इस मामले में फू का एक मानकीकृत, विहित स्ट्रिंग प्रतिनिधित्व मौजूद है, इसलिए इसका अर्थ Foo.ToStringऔर है Foo.Parse
हेइन्ज़ी

और, मेरे साहसिक प्रश्न पर ध्यान दें, क्या आप मुझे इस पैटर्न का उपयोग करने वाले .NET BCL से एक उदाहरण दे सकते हैं?
हेइन्ज़ी

4
वह कैसा सन्यासी है?
जैक्सबी

@ हिनजी: कोई भी तरीका जो रिटर्न Func<T>करता है, उस मानदंड को पूरा करेगा, यदि आप Tउस जानकारी को शामिल करते हैं जिसकी आपको आवश्यकता है। विस्तृत त्रुटि जानकारी वापस करना काफी हद तक आप पर निर्भर करता है। क्या आपने एक का उपयोग करने पर विचार किया है Maybe<T>? देखिए mikhail.io/2016/01/monads-explained-in-csharp
रॉबर्ट हार्वे

@JacquesB: मैं थोड़े ही सोच रहा था। विधि हस्ताक्षर आधुनिक व्यवहार के साथ संगत है, लेकिन यह इसके बारे में है।
रॉबर्ट हार्वे

1

आप MVC फ्रेमवर्क में ModelState को देख सकते हैं । यह कुछ इनपुट के प्रयास किए गए पार्स का प्रतिनिधित्व करता है और इसमें त्रुटियों का संग्रह हो सकता है।

उस ने कहा, मुझे नहीं लगता कि इसके लिए .net BCL में एक आवर्ती पैटर्न है, क्योंकि अपवाद है - बेहतर या बदतर के लिए - .net में त्रुटि की स्थिति की रिपोर्ट करने के लिए स्थापित पैटर्न। मुझे लगता है कि आपको बस आगे बढ़ना चाहिए और अपनी समस्या को हल करने के लिए अपने स्वयं के समाधान को लागू करना चाहिए, उदाहरण के लिए ParseResultदो उपवर्गों के साथ एक वर्ग, SuccessfulParseऔर FailedParse, जहां SuccessfulParseएक मूल्य के साथ संपत्ति है और FailedParseएक त्रुटि संदेश संपत्ति है। C # 7 में पैटर्न से मेल खाते हुए इसे मिलाना बहुत सुंदर हो सकता है।


1

मैं एक ऐसी TryParse/Convert/etc.विधि का उपयोग करना चाहता हूं, जिसमें मुझे कभी-कभी यह जानने की आवश्यकता होती है कि यह कैसे और क्यों विफल हुआ।

मैं इस बात से प्रेरणा लेता हूं कि कुछ धारावाहिक कैसे त्रुटियों को संभालते हैं और घटनाओं का उपयोग करते हैं। इस तरह मेरी TryX(..., out T)पद्धति के लिए वाक्यविन्यास किसी अन्य के रूप में साफ दिखता है और falseपैटर्न का तात्पर्य है कि मज़बूती से एक साधारण रिटर्न देता है।

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

public class Program
{
    public static void Main()
    {
        var c = new MyConverter();

        //here's where I'm subscibing to errors that occur
        c.Error += (sender, args) => Console.WriteLine(args.Details);

        c.TryCast<int>("5", out int i);
    }
}

//here's our converter class
public class MyConverter
{
    //invoke this event whenever something goes wrong and fill out your EventArgs with details
    public event EventHandler<MyEventArgs> Error;

    //intentionally stupid implementation
    public bool TryCast<T>(object input, out T output)
    {
        bool success = true;
        output = default (T);

        //try-catch here because it's an easy way to demonstrate my example
        try
        {
            output = (T)input;
        }
        catch (Exception ex)
        {
            success = false;
            Error?.Invoke(this, new MyEventArgs{Details = ex.ToString()});
        }

        return success;
    }
}

//stores whatever information you want to make available
public class MyEventArgs : EventArgs
{
    public string Details {get; set;}
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.