C# Language
उपवाद सम्भालना
खोज…
बुनियादी अपवाद हैंडलिंग
try
{
/* code that could throw an exception */
}
catch (Exception ex)
{
/* handle the exception */
}
ध्यान दें कि एक ही कोड के साथ सभी अपवादों को संभालना अक्सर सबसे अच्छा तरीका नहीं होता है।
यह आमतौर पर तब उपयोग किया जाता है जब अंतिम उपाय के रूप में कोई आंतरिक अपवाद हैंडलिंग दिनचर्या विफल हो जाती है।
विशिष्ट अपवाद प्रकारों को संभालना
try
{
/* code to open a file */
}
catch (System.IO.FileNotFoundException)
{
/* code to handle the file being not found */
}
catch (System.IO.UnauthorizedAccessException)
{
/* code to handle not being allowed access to the file */
}
catch (System.IO.IOException)
{
/* code to handle IOException or it's descendant other than the previous two */
}
catch (System.Exception)
{
/* code to handle other errors */
}
सावधान रहें कि अपवादों का मूल्यांकन क्रम में किया जाता है और विरासत को लागू किया जाता है। तो आपको सबसे विशिष्ट लोगों के साथ शुरू करने और उनके पूर्वजों के साथ समाप्त करने की आवश्यकता है। किसी भी बिंदु पर, केवल एक कैच ब्लॉक निष्पादित किया जाएगा।
अपवाद वस्तु का उपयोग करना
आपको अपने स्वयं के कोड में अपवाद बनाने और फेंकने की अनुमति है। एक अपवाद को इंस्टेंट करना उसी तरह से किया जाता है जैसे कोई अन्य C # ऑब्जेक्ट।
Exception ex = new Exception();
// constructor with an overload that takes a message string
Exception ex = new Exception("Error message");
फिर आप अपवाद को बढ़ाने के लिए throw
कीवर्ड का उपयोग कर सकते हैं:
try
{
throw new Exception("Error");
}
catch (Exception ex)
{
Console.Write(ex.Message); // Logs 'Error' to the output window
}
नोट: यदि आप कैच ब्लॉक के अंदर एक नया अपवाद फेंक रहे हैं, तो सुनिश्चित करें कि मूल अपवाद "आंतरिक अपवाद" के रूप में पारित किया गया है, उदाहरण के लिए
void DoSomething()
{
int b=1; int c=5;
try
{
var a = 1;
b = a - 1;
c = a / b;
a = a / c;
}
catch (DivideByZeroException dEx) when (b==0)
{
// we're throwing the same kind of exception
throw new DivideByZeroException("Cannot divide by b because it is zero", dEx);
}
catch (DivideByZeroException dEx) when (c==0)
{
// we're throwing the same kind of exception
throw new DivideByZeroException("Cannot divide by c because it is zero", dEx);
}
}
void Main()
{
try
{
DoSomething();
}
catch (Exception ex)
{
// Logs full error information (incl. inner exception)
Console.Write(ex.ToString());
}
}
इस स्थिति में यह मान लिया जाता है कि अपवाद को नियंत्रित नहीं किया जा सकता है, लेकिन संदेश में कुछ उपयोगी जानकारी जोड़ी जाती है (और मूल अपवाद को अभी भी बाहरी अपवाद ब्लॉक द्वारा ex.InnerException
माध्यम से एक्सेस किया जा सकता है)।
यह कुछ इस तरह दिखाएगा:
System.DivideByZeroException: इसे b से विभाजित नहीं किया जा सकता क्योंकि यह शून्य है ---> System.DivideByZeroException: शून्य से विभाजित करने का प्रयास किया गया।
UserQuery.g__DoSomething0_0 () में C: [...] \ LINQPadQuery.cs: पंक्ति 36
--- आंतरिक अपवाद स्टैक ट्रेस का अंत ---
UserQuery.g__DoSomething0_0 () C में: [...] \ LINQPadQuery.cs: पंक्ति 42
UserQuery.Main () में C: [...] \ LINQPadQuery.cs: पंक्ति 55
यदि आप LinqPad में इस उदाहरण की कोशिश कर रहे हैं, तो आप देखेंगे कि लाइन नंबर बहुत सार्थक नहीं हैं (वे हमेशा आपकी मदद नहीं करते हैं)। लेकिन एक उपयोगी त्रुटि पाठ पास करने के रूप में अक्सर ऊपर दिए गए सुझाव में त्रुटि के स्थान को ट्रैक करने के लिए समय कम हो जाता है, जो इस उदाहरण में स्पष्ट रूप से लाइन है
c = a / b;
समारोह में DoSomething()
।
अंत में ब्लॉक करें
try
{
/* code that could throw an exception */
}
catch (Exception)
{
/* handle the exception */
}
finally
{
/* Code that will be executed, regardless if an exception was thrown / caught or not */
}
फाइलों से पढ़ते समय try / catch / finally
ब्लॉक बहुत आसान हो सकता है।
उदाहरण के लिए:
FileStream f = null;
try
{
f = File.OpenRead("file.txt");
/* process the file here */
}
finally
{
f?.Close(); // f may be null, so use the null conditional operator.
}
एक कोशिश ब्लॉक को या तो एक catch
या finally
ब्लॉक द्वारा पालन किया जाना चाहिए। हालांकि, चूंकि कोई पकड़ ब्लॉक नहीं है, इसलिए निष्पादन समाप्ति का कारण होगा। समाप्ति से पहले, अंत में ब्लॉक के अंदर के बयान निष्पादित किए जाएंगे।
फ़ाइल-रीडिंग में हम FileStream
रूप में एक FileStream
using
कर सकते थे ( OpenRead
रिटर्न क्या है) IDisposable
लागू करता है।
यहां तक कि अगर try
ब्लॉक में एक return
बयान है, तो finally
ब्लॉक आमतौर पर निष्पादित करेगा; कुछ मामले हैं जहां यह नहीं होगा:
- जब एक StackOverflow होता है ।
-
Environment.FailFast
- आवेदन प्रक्रिया को मार दिया जाता है, आमतौर पर एक बाहरी स्रोत द्वारा।
WCF सेवाओं के लिए IErrorHandler को लागू करना
WCF सेवाओं के लिए IErrorHandler को लागू करना त्रुटि से निपटने और लॉगिंग को केंद्रीकृत करने का एक शानदार तरीका है। यहां दिखाए गए कार्यान्वयन को किसी भी अनचाहे अपवाद को पकड़ना चाहिए जो कि आपकी WCF सेवाओं में से किसी एक कॉल के परिणामस्वरूप फेंका जाता है। इस उदाहरण में भी दिखाया गया है कि कस्टम ऑब्जेक्ट को कैसे लौटाया जाए, और डिफ़ॉल्ट XML के बजाय JSON कैसे लौटाया जाए।
IErrorHandler लागू करें:
using System.ServiceModel.Channels;
using System.ServiceModel.Dispatcher;
using System.Runtime.Serialization.Json;
using System.ServiceModel;
using System.ServiceModel.Web;
namespace BehaviorsAndInspectors
{
public class ErrorHandler : IErrorHandler
{
public bool HandleError(Exception ex)
{
// Log exceptions here
return true;
} // end
public void ProvideFault(Exception ex, MessageVersion version, ref Message fault)
{
// Get the outgoing response portion of the current context
var response = WebOperationContext.Current.OutgoingResponse;
// Set the default http status code
response.StatusCode = HttpStatusCode.InternalServerError;
// Add ContentType header that specifies we are using JSON
response.ContentType = new MediaTypeHeaderValue("application/json").ToString();
// Create the fault message that is returned (note the ref parameter) with BaseDataResponseContract
fault = Message.CreateMessage(
version,
string.Empty,
new CustomReturnType { ErrorMessage = "An unhandled exception occurred!" },
new DataContractJsonSerializer(typeof(BaseDataResponseContract), new List<Type> { typeof(BaseDataResponseContract) }));
if (ex.GetType() == typeof(VariousExceptionTypes))
{
// You might want to catch different types of exceptions here and process them differently
}
// Tell WCF to use JSON encoding rather than default XML
var webBodyFormatMessageProperty = new WebBodyFormatMessageProperty(WebContentFormat.Json);
fault.Properties.Add(WebBodyFormatMessageProperty.Name, webBodyFormatMessageProperty);
} // end
} // end class
} // end namespace
इस उदाहरण में हम हैंडलर को सेवा व्यवहार से जोड़ते हैं। आप IEndpointBehavior, IContractBehavior, या IOperationBehavior को भी इसी तरह संलग्न कर सकते हैं।
सेवा व्यवहार के लिए संलग्न करें:
using System;
using System.Collections.ObjectModel;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Configuration;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
namespace BehaviorsAndInspectors
{
public class ErrorHandlerExtension : BehaviorExtensionElement, IServiceBehavior
{
public override Type BehaviorType
{
get { return GetType(); }
}
protected override object CreateBehavior()
{
return this;
}
private IErrorHandler GetInstance()
{
return new ErrorHandler();
}
void IServiceBehavior.AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters) { } // end
void IServiceBehavior.ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
var errorHandlerInstance = GetInstance();
foreach (ChannelDispatcher dispatcher in serviceHostBase.ChannelDispatchers)
{
dispatcher.ErrorHandlers.Add(errorHandlerInstance);
}
}
void IServiceBehavior.Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) { } // end
} // end class
} // end namespace
Web.config में पुष्टि करता है:
...
<system.serviceModel>
<services>
<service name="WebServices.MyService">
<endpoint binding="webHttpBinding" contract="WebServices.IMyService" />
</service>
</services>
<extensions>
<behaviorExtensions>
<!-- This extension if for the WCF Error Handling-->
<add name="ErrorHandlerBehavior" type="WebServices.BehaviorsAndInspectors.ErrorHandlerExtensionBehavior, WebServices, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
</behaviorExtensions>
</extensions>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
<ErrorHandlerBehavior />
</behavior>
</serviceBehaviors>
</behaviors>
....
</system.serviceModel>
...
यहाँ कुछ लिंक दिए गए हैं जो इस विषय पर सहायक हो सकते हैं:
https://msdn.microsoft.com/en-us/library/system.servicemodel.dispatcher.ierrorhandler(v=vs.100).aspx
अन्य उदाहरण:
HTTP स्टेटस कोड 401 अनधिकृत होने पर IErrorHandler गलत संदेश दे रहा है
IErrorHandler WCF में मेरी त्रुटियों से निपटने के लिए नहीं लगता है .. कोई विचार?
गैर-ओके http कोड के साथ JSON प्रतिक्रिया कस्टम WCF त्रुटि हैंडलर कैसे करें?
HttpClient अनुरोध के लिए आप सामग्री-प्रकार शीर्षलेख कैसे सेट करते हैं?
कस्टम अपवाद बनाना
आपको उन अपवादों को लागू करने की अनुमति है, जिन्हें किसी अन्य अपवाद की तरह ही फेंक दिया जा सकता है। यह समझ में आता है जब आप अपने अपवादों को रनटाइम के दौरान अन्य त्रुटियों से अलग करना चाहते हैं।
इस उदाहरण में हम एक जटिल इनपुट को पार्स करते समय एप्लिकेशन की स्पष्ट समस्याओं के लिए एक कस्टम अपवाद बनाएंगे।
कस्टम एक्सेप्शन क्लास बनाना
बनाने के लिए एक कस्टम अपवाद की एक उप-वर्ग बनाने Exception
:
public class ParserException : Exception
{
public ParserException() :
base("The parsing went wrong and we have no additional information.") { }
}
जब आप कैचर को अतिरिक्त जानकारी प्रदान करना चाहते हैं तो कस्टम अपवाद बहुत उपयोगी हो जाता है:
public class ParserException : Exception
{
public ParserException(string fileName, int lineNumber) :
base($"Parser error in {fileName}:{lineNumber}")
{
FileName = fileName;
LineNumber = lineNumber;
}
public string FileName {get; private set;}
public int LineNumber {get; private set;}
}
अब, जब आप catch(ParserException x)
तो आपके पास अतिरिक्त catch(ParserException x)
होंगे फाइन-ट्यून अपवाद हैंडलिंग।
कस्टम वर्ग अतिरिक्त परिदृश्यों का समर्थन करने के लिए निम्नलिखित विशेषताओं को लागू कर सकते हैं।
फिर से फेंक
पार्सिंग प्रक्रिया के दौरान, मूल अपवाद अभी भी ब्याज की है। इस उदाहरण में यह एक FormatException
क्योंकि कोड स्ट्रिंग के एक टुकड़े को पार्स करने का प्रयास करता है, जो एक संख्या होने की उम्मीद है। इस मामले में कस्टम अपवाद को ' इनर एक्सेप्शन' को शामिल करने का समर्थन करना चाहिए:
//new constructor:
ParserException(string msg, Exception inner) : base(msg, inner) {
}
क्रमबद्धता
कुछ मामलों में आपके अपवादों को AppDomain की सीमाओं को पार करना पड़ सकता है। यदि आपका पार्सर अपने ही AppDomain में चल रहा है, तो नए पार्सर कॉन्फ़िगरेशन को फिर से लोड करने के लिए। Visual Studio में, आप इस तरह कोड उत्पन्न करने के लिए Exception
टेम्पलेट का उपयोग कर सकते हैं।
[Serializable]
public class ParserException : Exception
{
// Constructor without arguments allows throwing your exception without
// providing any information, including error message. Should be included
// if your exception is meaningful without any additional details. Should
// set message by calling base constructor (default message is not helpful).
public ParserException()
: base("Parser failure.")
{}
// Constructor with message argument allows overriding default error message.
// Should be included if users can provide more helpful messages than
// generic automatically generated messages.
public ParserException(string message)
: base(message)
{}
// Constructor for serialization support. If your exception contains custom
// properties, read their values here.
protected ParserException(SerializationInfo info, StreamingContext context)
: base(info, context)
{}
}
ParserException का उपयोग करना
try
{
Process.StartRun(fileName)
}
catch (ParserException ex)
{
Console.WriteLine($"{ex.Message} in ${ex.FileName}:${ex.LineNumber}");
}
catch (PostProcessException x)
{
...
}
आप अपवादों को पकड़ने और लपेटने के लिए कस्टम अपवादों का उपयोग भी कर सकते हैं। इस तरह कई अलग-अलग त्रुटियों को एकल त्रुटि प्रकार में परिवर्तित किया जा सकता है जो अनुप्रयोग के लिए अधिक उपयोगी है:
try
{
int foo = int.Parse(token);
}
catch (FormatException ex)
{
//Assuming you added this constructor
throw new ParserException(
$"Failed to read {token} as number.",
FileName,
LineNumber,
ex);
}
जब अपने स्वयं के कस्टम अपवादों को उठाकर अपवादों को संभालते हैं, तो आपको आमतौर पर InnerException
संपत्ति में मूल अपवाद को शामिल करना चाहिए, जैसा कि ऊपर दिखाया गया है।
सुरक्षा चिंतायें
यदि अपवाद के कारण को उजागर करना उपयोगकर्ताओं को आपके एप्लिकेशन के आंतरिक कामकाज को देखने की अनुमति देकर सुरक्षा से समझौता कर सकता है तो यह आंतरिक अपवाद को लपेटने के लिए एक बुरा विचार हो सकता है। यह लागू हो सकता है यदि आप एक क्लास लाइब्रेरी बना रहे हैं जो दूसरों द्वारा उपयोग की जाएगी।
यहां बताया गया है कि आप आंतरिक अपवाद को लपेटे बिना एक कस्टम अपवाद कैसे उठा सकते हैं:
try
{
// ...
}
catch (SomeStandardException ex)
{
// ...
throw new MyCustomException(someMessage);
}
निष्कर्ष
कस्टम अपवाद बढ़ाते समय (या तो रैपिंग के साथ या एक अलिखित नए अपवाद के साथ), आपको एक अपवाद उठाना चाहिए जो कॉलर के लिए सार्थक है। उदाहरण के लिए, एक वर्ग पुस्तकालय का उपयोगकर्ता इस बारे में अधिक जानकारी नहीं रख सकता है कि पुस्तकालय अपने आंतरिक कार्य को कैसे करता है। वर्ग पुस्तकालय की निर्भरता द्वारा फेंके गए अपवाद सार्थक नहीं हैं। बल्कि, उपयोगकर्ता एक अपवाद चाहता है जो इस बात के लिए प्रासंगिक है कि क्लास लाइब्रेरी उन निर्भरता का गलत तरीके से उपयोग कैसे कर रही है।
try
{
// ...
}
catch (IOException ex)
{
// ...
throw new StorageServiceException(@"The Storage Service encountered a problem saving
your data. Please consult the inner exception for technical details.
If you are not able to resolve the problem, please call 555-555-1234 for technical
assistance.", ex);
}
अपवाद विरोधी पैटर्न
निगलने की क्रिया
एक व्यक्ति को हमेशा निम्न तरीके से अपवाद फेंकना चाहिए:
try
{
...
}
catch (Exception ex)
{
...
throw;
}
नीचे जैसा अपवाद फिर से फेंकने से मूल अपवाद बाधित हो जाएगा और मूल स्टैक ट्रेस खो जाएगा। कभी भी ऐसा नहीं करना चाहिए! स्टैक ट्रेस से पहले कैच और रीथ्रो खो जाएगा।
try
{
...
}
catch (Exception ex)
{
...
throw ex;
}
बेसबॉल अपवाद हैंडलिंग
सामान्य प्रवाह नियंत्रण निर्माणों के विकल्प के रूप में अपवादों का उपयोग नहीं करना चाहिए जैसे अगर-तब कथन और जबकि लूप। इस विरोधी पैटर्न को कभी-कभी बेसबॉल एक्सेप्शन हैंडलिंग कहा जाता है।
यहाँ विरोधी पैटर्न का एक उदाहरण है:
try
{
while (AccountManager.HasMoreAccounts())
{
account = AccountManager.GetNextAccount();
if (account.Name == userName)
{
//We found it
throw new AccountFoundException(account);
}
}
}
catch (AccountFoundException found)
{
Console.Write("Here are your account details: " + found.Account.Details.ToString());
}
यहाँ यह करने के लिए एक बेहतर तरीका है:
Account found = null;
while (AccountManager.HasMoreAccounts() && (found==null))
{
account = AccountManager.GetNextAccount();
if (account.Name == userName)
{
//We found it
found = account;
}
}
Console.Write("Here are your account details: " + found.Details.ToString());
पकड़ना (अपवाद)
आपके कोड में जेनेरिक अपवाद प्रकार को पकड़ने के लिए लगभग कोई (कुछ नहीं कहते हैं!) कारण हैं। आपको केवल उन अपवाद प्रकारों को पकड़ना चाहिए जिनकी आप अपेक्षा करते हैं, क्योंकि आप अपने कोड में बग छिपाते हैं अन्यथा नहीं।
try
{
var f = File.Open(myfile);
// do something
}
catch (Exception x)
{
// Assume file not found
Console.Write("Could not open file");
// but maybe the error was a NullReferenceException because of a bug in the file handling code?
}
बेहतर है:
try
{
var f = File.Open(myfile);
// do something which should normally not throw exceptions
}
catch (IOException)
{
Console.Write("File not found");
}
// Unfortunatelly, this one does not derive from the above, so declare separatelly
catch (UnauthorizedAccessException)
{
Console.Write("Insufficient rights");
}
यदि कोई अन्य अपवाद होता है, तो हमने जानबूझकर एप्लिकेशन को क्रैश होने दिया, इसलिए यह सीधे डिबगर में कदम रखता है और हम समस्या को ठीक कर सकते हैं। हमें ऐसे किसी कार्यक्रम को शिप नहीं करना चाहिए, जहां इनकी तुलना में कोई अन्य अपवाद किसी भी तरह से हो, इसलिए क्रैश होना कोई समस्या नहीं है।
निम्नलिखित भी एक बुरा उदाहरण है, क्योंकि यह एक प्रोग्रामिंग त्रुटि के आसपास काम करने के लिए अपवादों का उपयोग करता है। यही कारण है कि वे के लिए डिज़ाइन नहीं कर रहे हैं।
public void DoSomething(String s)
{
if (s == null)
throw new ArgumentNullException(nameof(s));
// Implementation goes here
}
try
{
DoSomething(myString);
}
catch(ArgumentNullException x)
{
// if this happens, we have a programming error and we should check
// why myString was null in the first place.
}
एक विधि से अपवाद / एकाधिक अपवादों को अलग करें
कौन कहता है कि आप एक विधि में कई अपवाद नहीं फेंक सकते। यदि आप AggregateException के साथ खेलने के लिए अभ्यस्त हैं, तो आपको गलत होने वाली कई चीज़ों का प्रतिनिधित्व करने के लिए अपना डेटा-स्ट्रक्चर बनाने के लिए लुभाया जा सकता है। निश्चित रूप से एक और डेटा-संरचना थी जो एक अपवाद नहीं है और अधिक आदर्श होगी जैसे कि एक मान्यता के परिणाम। यहां तक कि अगर आप AggregateException के साथ खेलते हैं, तो आप प्राप्त करने वाले पक्ष में हो सकते हैं और हमेशा उन्हें संभालने से यह एहसास नहीं होगा कि वे आपके लिए उपयोग हो सकते हैं।
यह एक विधि निष्पादित करने के लिए काफी प्रशंसनीय है और भले ही यह एक विफलता के रूप में एक पूरे के रूप में आप कई चीजों को उजागर करना चाहते हैं जो कि फेंके गए अपवादों में गलत हो गए। एक उदाहरण के रूप में इस व्यवहार के साथ देखा जा सकता है कि समानांतर तरीके कैसे काम करते थे एक कार्य को कई थ्रेड्स में तोड़ दिया गया था और उनमें से किसी भी संख्या में अपवादों को फेंक दिया जा सकता था और इसे रिपोर्ट करने की आवश्यकता थी। यहाँ एक मूर्खतापूर्ण उदाहरण है कि आप इससे कैसे लाभान्वित हो सकते हैं:
public void Run()
{
try
{
this.SillyMethod(1, 2);
}
catch (AggregateException ex)
{
Console.WriteLine(ex.Message);
foreach (Exception innerException in ex.InnerExceptions)
{
Console.WriteLine(innerException.Message);
}
}
}
private void SillyMethod(int input1, int input2)
{
var exceptions = new List<Exception>();
if (input1 == 1)
{
exceptions.Add(new ArgumentException("I do not like ones"));
}
if (input2 == 2)
{
exceptions.Add(new ArgumentException("I do not like twos"));
}
if (exceptions.Any())
{
throw new AggregateException("Funny stuff happended during execution", exceptions);
}
}
अपवादों का घोंसला बनाना और ब्लॉक को पकड़ने का प्रयास करना।
एक एक अपवाद को catch
में सक्षम है / दूसरे के अंदर catch
ब्लॉक का try
।
इस तरह से कोड के छोटे ब्लॉकों को प्रबंधित किया जा सकता है जो आपके पूरे तंत्र को बाधित किए बिना काम करने में सक्षम हैं।
try
{
//some code here
try
{
//some thing which throws an exception. For Eg : divide by 0
}
catch (DivideByZeroException dzEx)
{
//handle here only this exception
//throw from here will be passed on to the parent catch block
}
finally
{
//any thing to do after it is done.
}
//resume from here & proceed as normal;
}
catch(Exception e)
{
//handle here
}
नोट: पैरेंट कैच ब्लॉक में फेंकने पर अपवादों को निगलने से बचें
सर्वोत्तम प्रथाएं
प्रवंचक पत्रक
कर | ऐसा नहीं |
---|---|
नियंत्रण कथन के साथ नियंत्रण प्रवाह | अपवादों के साथ नियंत्रण प्रवाह |
लॉगिंग द्वारा अनदेखा (अवशोषित) अपवाद का ट्रैक रखें | अपवाद को अनदेखा करें |
throw का उपयोग करके अपवाद दोहराएं | अपवाद फिर से फेंकें - throw new ArgumentNullException() अपवाद throw new ArgumentNullException() या throw ex |
पूर्वनिर्धारित प्रणाली अपवादों को फेंक दें | पूर्वनिर्धारित प्रणाली अपवादों के समान कस्टम अपवादों को फेंक दें |
कस्टम / पूर्वनिर्धारित अपवाद को फेंक दें यदि यह तर्क तर्क के लिए महत्वपूर्ण है | प्रवाह में चेतावनी के लिए कस्टम / पूर्वनिर्धारित अपवादों को फेंक दें |
उन अपवादों को पकड़ें जिन्हें आप संभालना चाहते हैं | हर अपवाद को पकड़ो |
अपवादों के साथ व्यावसायिक तर्क का प्रबंधन न करें।
प्रवाह नियंत्रण अपवादों द्वारा नहीं किया जाना चाहिए। इसके बजाय सशर्त बयानों का उपयोग करें। यदि नियंत्रण को if-else
कथन के साथ स्पष्ट रूप से किया जा सकता है, तो अपवाद का उपयोग न करें क्योंकि यह पठनीयता और प्रदर्शन को कम करता है।
श्री बुरे आचरण द्वारा निम्नलिखित स्निपेट पर विचार करें:
// This is a snippet example for DO NOT
object myObject;
void DoingSomethingWithMyObject()
{
Console.WriteLine(myObject.ToString());
}
जब निष्पादन Console.WriteLine(myObject.ToString());
तक पहुंचता है Console.WriteLine(myObject.ToString());
अनुप्रयोग NullReferenceException को फेंक देगा। मिस्टर बैड प्रैक्टिस ने महसूस किया कि myObject
अशक्त है और NullReferenceException
को पकड़ने और संभालने के लिए अपने स्निपेट को संपादित किया है:
// This is a snippet example for DO NOT
object myObject;
void DoingSomethingWithMyObject()
{
try
{
Console.WriteLine(myObject.ToString());
}
catch(NullReferenceException ex)
{
// Hmmm, if I create a new instance of object and assign it to myObject:
myObject = new object();
// Nice, now I can continue to work with myObject
DoSomethingElseWithMyObject();
}
}
पिछले स्निपेट में केवल अपवाद का तर्क शामिल है, अगर इस बिंदु पर myObject
शून्य नहीं है तो मुझे क्या करना चाहिए? मुझे तर्क के इस हिस्से को कहां कवर करना चाहिए? Console.WriteLine(myObject.ToString());
ठीक बाद Console.WriteLine(myObject.ToString());
? कैसे के बारे में try...catch
बाद try...catch
ब्लॉक को try...catch
?
मिस्टर बेस्ट प्रैक्टिस के बारे में कैसे? वह इसे कैसे संभालेंगे?
// This is a snippet example for DO
object myObject;
void DoingSomethingWithMyObject()
{
if(myObject == null)
myObject = new object();
// When execution reaches this point, we are sure that myObject is not null
DoSomethingElseWithMyObject();
}
श्री बेस्ट प्रैक्टिसेज ने कम कोड और एक स्पष्ट और समझने योग्य तर्क के साथ एक ही तर्क प्राप्त किया।
अपवादों को दोबारा न फेंके
अपवादों को फिर से फेंकना महंगा है। यह प्रदर्शन पर नकारात्मक प्रभाव डालता है। कोड के लिए जो नियमित रूप से विफल रहता है, आप प्रदर्शन के मुद्दों को कम करने के लिए डिज़ाइन पैटर्न का उपयोग कर सकते हैं। यह विषय दो डिज़ाइन पैटर्न का वर्णन करता है जो उपयोगी होते हैं जब अपवाद प्रदर्शन को महत्वपूर्ण रूप से प्रभावित कर सकते हैं।
कोई लॉगिंग के साथ अपवादों को अवशोषित न करें
try
{
//Some code that might throw an exception
}
catch(Exception ex)
{
//empty catch block, bad practice
}
अपवादों को कभी न निगलें। अपवादों को नजरअंदाज करने से उस पल की बचत होगी, लेकिन बाद में स्थिरता के लिए एक अराजकता पैदा होगी। अपवादों को लॉग करते समय, आपको हमेशा अपवाद उदाहरण को लॉग करना चाहिए ताकि पूर्ण स्टैक ट्रेस लॉग हो जाए और केवल अपवाद संदेश न हो।
try
{
//Some code that might throw an exception
}
catch(NullException ex)
{
LogManager.Log(ex.ToString());
}
उन अपवादों को न पकड़ें जिन्हें आप संभाल नहीं सकते
कई संसाधन, जैसे कि यह एक , दृढ़ता से आपको यह विचार करने के लिए आग्रह करता है कि आप उस स्थान पर अपवाद क्यों पकड़ रहे हैं जो आप इसे पकड़ रहे हैं। आपको केवल एक अपवाद को पकड़ना चाहिए यदि आप इसे उस स्थान पर संभाल सकते हैं। यदि आप समस्या को कम करने में मदद करने के लिए वहां कुछ कर सकते हैं, जैसे कि वैकल्पिक एल्गोरिदम की कोशिश करना, बैकअप डेटाबेस से जुड़ना, किसी अन्य फ़ाइलनाम की कोशिश करना, 30 सेकंड का इंतजार करना और फिर से प्रयास करना, या किसी व्यवस्थापक को सूचित करना, आप त्रुटि को पकड़ सकते हैं और ऐसा कर सकते हैं। यदि ऐसा कुछ भी नहीं है जो आप कर सकते हैं और उचित रूप से कर सकते हैं, तो बस "इसे जाने दें" और अपवाद को उच्च स्तर पर नियंत्रित किया जाए। यदि अपवाद पर्याप्त रूप से विनाशकारी है और समस्या की गंभीरता के कारण दुर्घटना के लिए पूरे कार्यक्रम के अलावा कोई उचित विकल्प नहीं है, तो इसे क्रैश होने दें।
try
{
//Try to save the data to the main database.
}
catch(SqlException ex)
{
//Try to save the data to the alternative database.
}
//If anything other than a SqlException is thrown, there is nothing we can do here. Let the exception bubble up to a level where it can be handled.
अनहेल्दी और थ्रेड अपवाद
AppDomain.UnhandledException यह ईवेंट बिना किसी अपवाद के सूचना प्रदान करता है। यह एप्लिकेशन को अपवाद के बारे में जानकारी लॉग करने की अनुमति देता है इससे पहले कि सिस्टम डिफॉल्ट हैंडलर उपयोगकर्ता को अपवाद रिपोर्ट करता है और एप्लिकेशन को समाप्त कर देता है। यदि आवेदन की स्थिति के बारे में पर्याप्त जानकारी उपलब्ध है, तो अन्य क्रियाएँ की जा सकती हैं - जैसे कि बाद में पुनर्प्राप्ति के लिए प्रोग्राम डेटा को सहेजना। सावधानी की सलाह दी जाती है, क्योंकि अपवादों को नियंत्रित नहीं किए जाने पर प्रोग्राम डेटा दूषित हो सकता है।
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
private static void Main(string[] args)
{
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(UnhandledException);
}
Application.ThreadException यह ईवेंट आपके विंडोज फॉर्म के एप्लिकेशन को विंडोज फॉर्म्स थ्रेड्स में होने वाले अनहैंड अपवाद को हैंडल करने की अनुमति देता है। इन अपवादों से निपटने के लिए अपने ईवेंट हैंडलर को थ्रेडएक्ससेप्शन इवेंट में संलग्न करें, जो आपके एप्लिकेशन को अज्ञात स्थिति में छोड़ देगा। जहां संभव हो, अपवादों को एक संरचित अपवाद हैंडलिंग ब्लॉक द्वारा नियंत्रित किया जाना चाहिए।
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
private static void Main(string[] args)
{
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(UnhandledException);
Application.ThreadException += new ThreadExceptionEventHandler(ThreadException);
}
और अंत में अपवाद को संभालना
static void UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
Exception ex = (Exception)e.ExceptionObject;
// your code
}
static void ThreadException(object sender, ThreadExceptionEventArgs e)
{
Exception ex = e.Exception;
// your code
}
अपवाद फेंकना
आपका कोड, और अक्सर ऐसा होना चाहिए, जब कुछ असामान्य हुआ हो, तो एक अपवाद फेंक दें।
public void WalkInto(Destination destination)
{
if (destination.Name == "Mordor")
{
throw new InvalidOperationException("One does not simply walk into Mordor.");
}
// ... Implement your normal walking code here.
}