C# ఎక్సెప్షన్ హ్యాండ్లింగ్ (try, catch, finally, when, Custom Exceptions & IDisposable)

⚡ Modern C# 12 / .NET 8 LTS 📖 Chapter 17 of 20 🚀 Phase 05: అడ్వాన్స్‌డ్ C#, LINQ & ప్రాజెక్ట్ 📅 2026 Academic Edition
📌 Covered in this chapter: రన్‌టైమ్ ఎర్రర్ vs బగ్ · .NET Exception Hierarchy (System.Exception) · try-catch-finally లైఫ్‌సైకిల్ · మల్టిపుల్ క్యాచ్ బ్లాకులు & ఆర్డరింగ్ రూల్ · C# 6+ when ఫిల్టర్లు · throw vs throw ex (కాల్ స్టాక్ నష్టం నివారణ) · ఇన్నర్ ఎక్సెప్షన్లు · డొమైన్-స్పెసిఫిక్ కస్టమ్ ఎక్సెప్షన్లు · IDisposable & using స్టేట్‌మెంట్ / డిక్లరేషన్ · యాంటీ-ప్యాటర్న్స్ · ఎంటర్‌ప్రైజ్ ATM క్యాష్ విత్‌డ్రాయల్ & ఆడిట్ ప్రాజెక్ట్ · 5 ఇంటరాక్టివ్ క్విజ్ ప్రశ్నలు

స్వాగతం Phase 05 కు! 🚀 అడ్వాన్స్‌డ్ C#, ఎంటర్‌ప్రైజ్ రెసిలియెన్స్ & LINQ!

ఒక రూకీ ప్రోగ్రామర్ రాసే కోడ్ కేవలం ప్రతిదీ సవ్యంగా జరిగినప్పుడు మాత్రమే (Happy Path) పనిచేస్తుంది. కానీ ఒక సీనియర్ సాఫ్ట్‌వేర్ ఇంజనీర్ రాసే ప్రొడక్షన్ కోడ్ — ఇంటర్నెట్ కేబుల్ తెగిపోయినా, డేటాబేస్ డౌన్ అయినా, యూజర్ తప్పుడు డేటా ఇచ్చినా, లేదా హార్డ్‌డిస్క్ నిండిపోయినా సరే క్రాష్ అవ్వకుండా సురక్షితంగా రక్షించుకునే రెసిలియెన్స్ (Fault Tolerance & Graceful Degradation) కలిగి ఉంటుంది.

ఈ మొదటి అడ్వాన్స్‌డ్ అధ్యాయంలో C# రన్‌టైమ్ లోపం వచ్చినప్పుడు జరిగే అంతర్గత మెకానిక్స్, try-catch-finally ల అసలైన కాల్ స్టాక్ పనితీరు, throw; vs throw ex; ల మధ్య ఉండే లైఫ్-అండ్-డెత్ డిఫరెన్స్, when కండిషనల్ ఫిల్టర్లు, కస్టమ్ ఎక్సెప్షన్ల నిర్మాణం, మరియు మెమరీ లీక్స్ రాకుండా నిరోధించే IDisposable & using లపై పూర్తి స్థాయి ప్రావీణ్యం సంపాదిద్దాం!

1 💥 రన్‌టైమ్ ఎర్రర్స్ vs కంపైల్-టైమ్ ఎర్రర్స్ — ఎక్సెప్షన్ అంటే ఏమిటి?

కంప్యూటర్ ప్రోగ్రామింగ్‌లో లోపాలు రెండు వేర్వేరు దశల్లో బయటపడతాయి:

  • కంపైల్-టైమ్ ఎర్రర్స్ (Compile-Time Errors): సింటాక్స్ మిస్టేక్స్, టైప్ మిస్‌మ్యాచ్‌లు, సెమికోలన్ మర్చిపోవడం లాంటివి. C# కంపైలర్ వీటిని కోడ్ రన్ అవ్వకముందే పసిగట్టి అడ్డుకుంటుంది.
  • రన్‌టైమ్ ఎక్సెప్షన్స్ (Runtime Exceptions): ప్రోగ్రామ్ విజయవంతంగా కంపైల్ అయి నడుస్తున్న సమయంలో ఊహించని పరిస్థితుల వల్ల (ఉదా: డివైడ్ బై జీరో, నెట్‌వర్క్ టైమౌట్, ఫైల్ డిలీట్ అవ్వడం, నల్ రిఫరెన్స్) తలెత్తే అసాధారణ పరిస్థితులు (Exceptional Conditions).

ఒక ఎక్సెప్షన్ వచ్చినప్పుడు మీరు దాన్ని హ్యాండిల్ చేయకపోతే, CLR (Common Language Runtime) ఆ అప్లికేషన్‌ను వెంటనే కిల్ చేసి క్రాష్ చేస్తుంది (Crash to Desktop). ఎక్సెప్షన్ హ్యాండ్లింగ్ ముఖ్య ఉద్దేశ్యం — ప్రోగ్రామ్ క్రాష్ కాకుండా ఆపి, సమస్యను లాగ్ చేసి, యూజర్‌కు అర్థమయ్యే సందేశాన్ని అందించడం (Fail Gracefully).

2 🌳 .NET Exception Hierarchy — `System.Exception` వృక్షం

C# లోని అన్ని ఎక్సెప్షన్లు ఒక స్పష్టమైన క్లాస్ హైరార్కీని పాటిస్తాయి. వాటన్నింటికీ మూల పురుషుడు System.Exception.

ఎక్సెప్షన్ క్లాస్ ఎప్పుడు వస్తుంది? ఉదాహరణ సందర్భం
NullReferenceException null గా ఉన్న రిఫరెన్స్ వేరియబుల్ యొక్క మెథడ్ లేదా ప్రాపర్టీని కాల్ చేసినప్పుడు string s = null; s.ToUpper();
DivideByZeroException ఒక ఇంటీజర్‌ను సున్నా (0) తో భాగించినప్పుడు int result = 100 / 0;
IndexOutOfRangeException అర్రే పరిధిని దాటి ఇండెక్స్‌ను యాక్సెస్ చేసినప్పుడు int[] a = new int[3]; int x = a[5];
FormatException స్ట్రింగ్‌ను నంబర్‌గా మార్చేటప్పుడు అక్షరాలు ఉన్నప్పుడు int.Parse("హైదరాబాద్");
ArgumentNullException మెథడ్‌కు తప్పనిసరిగా కావాల్సిన పారామీటర్‌కు null పంపినప్పుడు File.ReadAllText(null);
InvalidOperationException ఆబ్జెక్ట్ యొక్క ప్రస్తుత స్థితిలో ఆ ఆపరేషన్ చెల్లనప్పుడు క్లోజ్ అయిన డేటాబేస్ కనెక్షన్‌పై క్వెరీ రన్ చేయడం

3 🛡️ `try`, `catch`, `finally` బ్లాకుల లైఫ్‌సైకిల్

C# లో రన్‌టైమ్ ఎర్రర్లను నియంత్రించడానికి మూడు ప్రాథమిక బ్లాకులు ఉన్నాయి:

  1. try బ్లాక్: ప్రమాదం జరిగే అవకాశం ఉన్న సున్నితమైన కోడ్‌ను ఇక్కడ ఉంచుతాం. ఇందులో ఎర్రర్ రాగానే ఎగ్జిక్యూషన్ అక్కడితో ఆగిపోయి, తగిన catch బ్లాక్‌కు జంప్ అవుతుంది.
  2. catch బ్లాక్: విసిరిన ఎక్సెప్షన్‌ను క్యాచ్ చేసి, పరిష్కరించే లేదా లాగ్ చేసే కోడ్.
  3. finally బ్లాక్: ఎర్రర్ వచ్చినా రాకపోయినా 100% ఖచ్చితంగా ఎగ్జిక్యూట్ అయ్యే క్లీనప్ బ్లాక్! (ఫైల్స్ క్లోజ్ చేయడం, కనెక్షన్స్ రిలీజ్ చేయడం).
csharp · try-catch-finally Flow Control
Console.WriteLine("1. లావాదేవీ ప్రారంభమైంది.");

try
{
    Console.WriteLine("2. సర్వర్‌తో కనెక్ట్ అవుతున్నాం...");
    int totalAmount = 5000;
    int divisor = 0; // ప్రమాదం!
    int sharePerPerson = totalAmount / divisor;
    Console.WriteLine($"3. ఒక్కొక్కరికి వాటా: ₹{sharePerPerson}"); // ఇది ఎప్పటికీ రన్ కాదు!
}
catch (DivideByZeroException ex)
{
    Console.WriteLine($"⚠️ [ఎర్రర్ పట్టుబడింది]: సున్నా మంది వ్యక్తులకు నిధులను పంచలేము! ({ex.Message})");
}
finally
{
    // ఎర్రర్ వచ్చినా సరే ఇది ఖచ్చితంగా రన్ అవుతుంది!
    Console.WriteLine("4. 🧹 [Finally క్లీనప్]: సర్వర్ కనెక్షన్ సురక్షితంగా మూసివేయబడింది.");
}

Console.WriteLine("5. అప్లికేషన్ క్రాష్ అవ్వకుండా ముందుకు సాగుతోంది!");
💡 ఇంటర్వ్యూ ట్విస్ట్: try బ్లాక్ లోపల return 100; అని రాసినప్పటికీ, కంప్యూటర్ ముందుగా finally బ్లాక్‌ను పూర్తి చేసిన తర్వాత మాత్రమే ఆ వాల్యూని కాలర్‌కు రిటర్న్ చేస్తుంది! finally ఎగ్జిక్యూషన్‌ను ఆపడం దాదాపు అసాధ్యం.

4 🎯 బహుళ `catch` బ్లాకులు & ఆర్డరింగ్ రూల్ (Specific to General)

ఒకే try బ్లాక్‌లో వివిధ రకాల ఎర్రర్లు వచ్చే అవకాశం ఉంటుంది. అందువల్ల మనం బహుళ catch బ్లాకులను రాయవచ్చు. కానీ ఇక్కడ C# కంపైలర్ ఒక కఠినమైన నిబంధనను విధిస్తుంది:

"ఎల్లప్పుడూ అత్యంత స్పెసిఫిక్ (చైల్డ్) ఎక్సెప్షన్లను పైభాగంలో, జెనెరిక్ Exception ను అందరికంటే చివర్లో ఉంచాలి!"

csharp · Multiple Catch Blocks in Correct Order
try
{
    string[] userInputs = { "100", "0", "యాభై" };
    int num1 = int.Parse(userInputs[0]);
    int num2 = int.Parse(userInputs[2]); // FormatException ఇక్కడ వస్తుంది!
    int result = num1 / num2;
}
catch (IndexOutOfRangeException ex)
{
    Console.WriteLine($"❌ అర్రే పరిమితి దాటిపోయింది: {ex.Message}");
}
catch (DivideByZeroException ex)
{
    Console.WriteLine($"❌ సున్నాతో భాగించకూడదు: {ex.Message}");
}
catch (FormatException ex)
{
    Console.WriteLine($"❌ నంబర్ ఫార్మాట్ తప్పుగా ఉంది: {ex.Message}");
}
catch (Exception ex) // అల్టిమేట్ సేఫ్టీ నెట్ - అందరికంటే చివర్లోనే ఉండాలి!
{
    Console.WriteLine($"❌ ఇతర తెలియని లోపం సంభవించింది: {ex.Message}");
}

5 🔍 C# 6+ ఎక్సెప్షన్ ఫిల్టర్లు (`when` కీవర్డ్)

గతంలో ఒక ఎక్సెప్షన్ వచ్చినప్పుడు క్యాచ్ బ్లాక్ లోపలికి వెళ్లి if-else రాయాల్సి వచ్చేది. కానీ C# 6 లో వచ్చిన when ఫిల్టర్ ద్వారా క్యాచ్ బ్లాక్ లోకి అడుగుపెట్టక ముందే షరతును తనిఖీ చేయవచ్చు:

csharp · Exception Filtering with 'when'
public class ServerException : Exception
{
    public int StatusCode { get; }
    public ServerException(int code, string msg) : base(msg) => StatusCode = code;
}

try
{
    // 404 ఎర్రర్ అనుకరిస్తున్నాం
    throw new ServerException(404, "అభ్యర్థించిన రిసోర్స్ సర్వర్‌లో దొరకలేదు");
}
catch (ServerException ex) when (ex.StatusCode == 404)
{
    Console.WriteLine($"🔍 [404 Not Found]: పేజీ దొరకలేదు, హోమ్‌పేజీకి దారి మళ్లిస్తున్నాం.");
}
catch (ServerException ex) when (ex.StatusCode == 500)
{
    Console.WriteLine($"🔥 [500 Server Error]: సర్వర్ క్రాష్ అయ్యింది, డెవలపర్ అలర్ట్ పంపుతున్నాం.");
}
catch (ServerException ex)
{
    Console.WriteLine($"⚠️ ఇతర సర్వర్ ఎర్రర్: కోడ్ {ex.StatusCode}");
}

⚡ Performance & Debugging Benefit: when షరతు తప్పు అయితే, CLR కాల్ స్టాక్‌ను అన్‌వైండ్ (Stack Unwinding) చేయదు! దీనివల్ల ఒరిజినల్ స్టాక్ ట్రేస్ మెమరీలో చెక్కుచెదరకుండా ఉంటుంది.

6 ⚠️ `throw;` vs `throw ex;` — కాల్ స్టాక్ నాశనమయ్యే తీవ్ర ప్రమాదం!

ఇది ప్రపంచవ్యాప్తంగా ప్రొడక్షన్ డెవలపర్లు చేసే అత్యంత ఘోరమైన తప్పు, మరియు ఇంటర్వ్యూలలో టాప్ ట్రిక్కీ ప్రశ్న:

రీ-త్రో సింటాక్స్ కాల్ స్టాక్ (Call Stack Trace) ఏమవుతుంది? తీర్పు
throw; (బేర్ త్రో) అసలైన ఎర్రర్ ఎక్కడ పుట్టిందో (లైన్ నంబర్, మెథడ్) ఆ ఒరిజినల్ స్టాక్ ట్రేస్‌ను 100% కాపాడుతుంది. ✅ Best Practice (ఎల్లప్పుడూ ఇదే వాడాలి)
throw ex; అసలైన స్టాక్ ట్రేస్‌ను పూర్తిగా చెరిపివేసి, ఈ ప్రస్తుత క్యాచ్ బ్లాక్ లైన్ నంబర్‌నే ఎర్రర్ మూలంగా రీసెట్ చేస్తుంది! ❌ Dangerous Antipattern (ఎప్పుడూ వాడకూడదు!)
csharp · throw vs throw ex Demonstration
void ProcessOrder()
{
    try
    {
        ExecuteDatabaseQuery(); // లైన్ 85 లో SQL ఎర్రర్ వచ్చింది అనుకుందాం
    }
    catch (Exception ex)
    {
        LogToAuditFile(ex.Message);

        // ❌ throw ex; // చెడ్డది! లైన్ 85 పోయి, ఈ క్యాచ్ బ్లాక్ లైనే కొత్త ఎర్రర్ గా రికార్డ్ అవుతుంది!
        throw; // ✅ అద్భుతమైనది! లైన్ 85 లోని ఒరిజినల్ రూట్ కాజ్ కాల్ స్టాక్‌ను కాపాడుతుంది!
    }
}

7 📦 ఇన్నర్ ఎక్సెప్షన్స్ (Inner Exceptions) & ఎక్సెప్షన్ ర్యాపింగ్

ఒక పెద్ద ఎంటర్‌ప్రైజ్ అప్లికేషన్‌లో యూజర్‌కు లో-లెవల్ టెక్నికల్ ఎర్రర్స్ (ఉదా: SqlException: Timeout expired on socket 192.168.1.1) చూపించడం మంచిది కాదు. దానికి బదులు అర్థవంతమైన బిజినెస్ ఎక్సెప్షన్ (ఉదా: OrderProcessingException) రూపంలో చూపించాలి. అదే సమయంలో డీబగ్గింగ్ కోసం అసలైన SQL ఎర్రర్‌ను లోపల దాచాలి. దీన్నే Exception Wrapping with Inner Exception అంటారు:

csharp · Inner Exception Wrapping
try
{
    // లో-లెవల్ ఆపరేషన్ విఫలమైంది అనుకుందాం
    throw new System.IO.FileNotFoundException("బ్యాంక్ కాన్ఫిగరేషన్ ఫైల్ కనబడలేదు!");
}
catch (Exception ioEx)
{
    // ioEx ని రెండవ పారామీటర్‌గా పంపి ర్యాప్ చేస్తున్నాం!
    throw new ApplicationException("బ్యాంకింగ్ సర్వీస్ ప్రారంభం కాలేదు", ioEx);
}

8 🛠️ కస్టమ్ ఎక్సెప్షన్స్ (Custom User-Defined Exceptions) రాయడం

మన డొమైన్ బిజినెస్ రూల్స్ ఉల్లంఘించినప్పుడు (ఉదాహరణకు బ్యాంక్ ఖాతాలో బ్యాలెన్స్ చాలకపోవడం, ఏటీఎం కార్డు బ్లాక్ అవ్వడం) మనం మన స్వంత కస్టమ్ ఎక్సెప్షన్ క్లాసులను రాయాలి.

కస్టమ్ ఎక్సెప్షన్ బెస్ట్ ప్రాక్టీస్ నియమాలు:

  • పేరు చివర తప్పనిసరిగా 'Exception' పదం ఉండాలి (ఉదా: InsufficientFundsException).
  • System.Exception క్లాస్ నుండి ఇన్‌హెరిట్ చేసుకోవాలి.
  • ప్రామాణికంగా 3 కన్‌స్ట్రక్టర్లను అందించాలి: డీఫాల్ట్, మెసేజ్ తో, మరియు ఇన్నర్ ఎక్సెప్షన్ తో.
  • అదనపు డొమైన్ వివరాలు (ఉదా: లోటు బ్యాలెన్స్, అకౌంట్ నంబర్) కోసం రీడ్-ఓన్లీ ప్రాపర్టీలను ఉంచవచ్చు.
csharp · Professional Custom Exception Implementation
public class InsufficientFundsException : Exception
{
    public decimal CurrentBalance { get; }
    public decimal RequestedAmount { get; }
    public decimal DeficitAmount => RequestedAmount - CurrentBalance;

    public InsufficientFundsException() : base("ఖాతాలో సరిపడా నిధులు లేవు.") { }

    public InsufficientFundsException(string message) : base(message) { }

    public InsufficientFundsException(string message, Exception inner) : base(message, inner) { }

    // డొమైన్ స్పెసిఫిక్ రిచ్ కన్‌స్ట్రక్టర్
    public InsufficientFundsException(decimal balance, decimal requested) 
        : base($"నిధులు సరిపోవు! (ప్రస్తుత బ్యాలెన్స్: ₹{balance:N2}, అభ్యర్థించినది: ₹{requested:N2})")
    {
        CurrentBalance = balance;
        RequestedAmount = requested;
    }
}

9 🧹 `IDisposable` ఇంటర్‌ఫేస్ & Modern `using` స్టేట్‌మెంట్ / డిక్లరేషన్

Garbage Collector కేవలం .NET మేనేజ్డ్ మెమరీని మాత్రమే క్లీన్ చేయగలదు. కానీ ఫైల్ హ్యాండిల్స్, డేటాబేస్ కనెక్షన్లు, నెట్‌వర్క్ సాకెట్లు వంటి అన్‌మేనేజ్డ్ రీసోర్సెస్ (Unmanaged Resources) ను డెవలపర్ తక్షణమే రిలీజ్ చేయాలి. దీనికోసం .NET లో IDisposable ఇంటర్‌ఫేస్ మరియు Dispose() మెథడ్ ఉంటాయి.

ఈ Dispose() ను మాన్యువల్‌గా finally లో పిలవడానికి బదులుగా C# అందించిన అత్యంత అందమైన సింటాక్స్ using:

csharp · Modern C# 8+ using Declaration
public class SecureFileLogger : IDisposable
{
    public string FileName { get; }

    public SecureFileLogger(string name)
    {
        FileName = name;
        Console.WriteLine($"📂 ఫైల్ ఓపెన్ చేయబడింది: {FileName}");
    }

    public void WriteLog(string msg) => Console.WriteLine($"   [LOG] {msg}");

    // IDisposable కాంట్రాక్ట్
    public void Dispose()
    {
        Console.WriteLine($"🔒 ఫైల్ సురక్షితంగా క్లోజ్ చేయబడింది (Disposed): {FileName}");
    }
}

// 🌟 మోడ్రన్ C# 8+ 'using declaration' - కర్లీ బ్రేసెస్ అవసరం లేదు!
void TestLogging()
{
    using var logger = new SecureFileLogger("audit_2026.log");
    logger.WriteLog("యూజర్ లాగిన్ విజయవంతం");
    logger.WriteLog("చెల్లింపు ప్రారంభమైంది");
    // మెథడ్ ముగియగానే (లేదా ఎర్రర్ వచ్చినా) Dispose() ఆటోమేటిక్‌గా రన్ అవుతుంది!
}

TestLogging();

10 🚫 ఎక్సెప్షన్ హ్యాండ్లింగ్ యాంటీ-ప్యాటర్న్స్ (Antipatterns to Avoid)

ఎక్సెప్షన్ హ్యాండ్లింగ్‌లో ప్రొఫెషనల్స్ ఎప్పుడూ చేయకూడని తప్పులు:

  • ❌ ఖాళీ క్యాచ్ బ్లాక్ (Swallowing Exceptions): catch (Exception) { } రాయడం అంటే ఇంట్లో మంటలు అంటుకున్నప్పుడు ఫైర్ అలారం స్విచ్ ఆఫ్ చేసి పడుకోవడం లాంటిది! ఎర్రర్ దాగిపోయి సైలెంట్‌గా డేటా కరప్ట్ అవుతుంది. కనీసం లాగ్ అయినా చేయాలి.
  • ❌ కంట్రోల్ ఫ్లో కోసం ఎక్సెప్షన్లు వాడటం: సాధారణ if-else లాజిక్ బదులు ఎక్సెప్షన్లను వాడకూడదు. ఎందుకంటే ఎక్సెప్షన్ త్రో అయినప్పుడు కాల్ స్టాక్ ఫ్రేమ్ తయారు చేయడం వల్ల సిస్టమ్ వేగం 100 రెట్లు నెమ్మదిస్తుంది. ఉదాహరణ: int.Parse లో క్యాచ్ చేయడం కంటే int.TryParse వాడటం వేల రెట్లు వేగవంతం!

11 🌐 గ్లోబల్ ఎక్సెప్షన్ హ్యాండ్లింగ్ & Structured Logging సూత్రాలు

ప్రతి ఒక్క మెథడ్‌లో వందల కొద్దీ try-catch లు రాసుకుంటూ వెళ్తే కోడ్ చదవడానికి చాలా కష్టమవుతుంది. ప్రొఫెషనల్ అప్లికేషన్లలో:

  • లోకల్‌గా పరిష్కరించగలిగే ఎర్రర్లను మాత్రమే లోకల్ try-catch లో హ్యాండిల్ చేయాలి.
  • మిగిలిన అన్నింటిని పైకి పాస్ చేసి, అప్లికేషన్ టాప్-లెవెల్ లో ఉండే Global Exception Middleware (ASP.NET Core లో) లేదా AppDomain.UnhandledException లో కేంద్రీకృతంగా లాగ్ చేయాలి.

12 🏧 రియల్-వరల్డ్ ప్రాజెక్ట్ — ఎంటర్‌ప్రైజ్ ఏటీఎం క్యాష్ విత్‌డ్రా & ఆడిట్ సిస్టమ్ (Resilient ATM Engine)

ఈ అధ్యాయంలో నేర్చుకున్న Custom Exceptions, Multiple Catches, when Filters, throw;, మరియు IDisposable క్లీనప్ అన్నింటినీ మేళవించి ఒక ఎంటర్‌ప్రైజ్ స్మార్ట్ ఏటీఎం ఇంజిన్ (Resilient ATM Engine v1.0) నిర్మిద్దాం.

csharp · Resilient ATM Cash Dispenser & Audit Engine
using System;

Console.OutputEncoding = System.Text.Encoding.UTF8;

Console.WriteLine("=================================================");
Console.WriteLine("🏧 మన ఏటీఎం - ఎంటర్‌ప్రైజ్ క్యాష్ డిస్పెన్సర్ ఇంజిన్ v1.0");
Console.WriteLine("=================================================\n");

// 1. డొమైన్ కస్టమ్ ఎక్సెప్షన్లు
public class InsufficientCashException(decimal balance, decimal requested) 
    : Exception($"ఖాతాలో నిధులు సరిపోవు! (బ్యాలెన్స్: ₹{balance:N2}, అభ్యర్థన: ₹{requested:N2})")
{
    public decimal Deficit => requested - balance;
}

public class DailyLimitExceededException(decimal limit, decimal requested)
    : Exception($"రోజువారీ ఏటీఎం విత్‌డ్రా పరిమితి ₹{limit:N2} దాటిపోయింది! (అభ్యర్థన: ₹{requested:N2})");

public class CardBlockedException(string cardNo, string reason)
    : Exception($"భద్రతా కారణాల వల్ల కార్డ్ {cardNo} బ్లాక్ చేయబడింది: {reason}");

// 2. IDisposable రీసోర్స్ సెషన్
public class AtmHardwareSession : IDisposable
{
    public string SessionId { get; } = "ATM-SESS-" + Guid.NewGuid().ToString().Substring(0, 6).ToUpper();

    public AtmHardwareSession()
    {
        Console.WriteLine($"🔌 [హార్డ్‌వేర్]: క్యాష్ డిస్పెన్సర్ షట్టర్ మరియు సెన్సార్లు ఆన్ అయ్యాయి ({SessionId})");
    }

    public void DispenseCurrencyNotes(decimal amount)
    {
        Console.WriteLine($"💵 [క్యాష్ షట్టర్ ఓపెన్]: ₹{amount:N2} కరెన్సీ నోట్లు బయటకు వచ్చాయి. దయచేసి నగదును తీసుకోండి.");
    }

    public void Dispose()
    {
        Console.WriteLine($"🔒 [హార్డ్‌వేర్]: క్యాష్ డిస్పెన్సర్ షట్టర్ సురక్షితంగా లాక్ చేయబడింది. సెషన్ ముగిసింది ({SessionId}).\n");
    }
}

// 3. ప్రధాన ఏటీఎం కంట్రోలర్
public class AtmController
{
    private decimal _accountBalance = 35000.00m;
    private const decimal DailyWithdrawLimit = 20000.00m;
    private bool _isCardActive = true;

    public void ProcessWithdrawal(string cardNo, decimal amount)
    {
        Console.WriteLine($"-------------------------------------------------");
        Console.WriteLine($"💳 కార్డ్ #{cardNo} ద్వారా నగదు విత్‌డ్రా అభ్యర్థన: ₹{amount:N2}");

        // using డిక్లరేషన్: ఎర్రర్ వచ్చినా హార్డ్‌వేర్ షట్టర్ 100% సేఫ్‌గా క్లోజ్ అవుతుంది!
        using var session = new AtmHardwareSession();

        try
        {
            if (!_isCardActive)
            {
                throw new CardBlockedException(cardNo, "3 సార్లు తప్పుడు పిన్ ఎంటర్ చేయబడింది");
            }
            if (amount <= 0 || amount % 100 != 0)
            {
                throw new ArgumentException("విత్‌డ్రా మొత్తం ₹100 గుణిజాల్లో మాత్రమే ఉండాలి!");
            }
            if (amount > DailyWithdrawLimit)
            {
                throw new DailyLimitExceededException(DailyWithdrawLimit, amount);
            }
            if (amount > _accountBalance)
            {
                throw new InsufficientCashException(_accountBalance, amount);
            }

            // లావాదేవీ విజయవంతం
            _accountBalance -= amount;
            session.DispenseCurrencyNotes(amount);
            Console.WriteLine($"✅ లావాదేవీ విజయవంతం! మిగిలిన ఖాతా బ్యాలెన్స్: ₹{_accountBalance:N2}");
        }
        catch (InsufficientCashException ex)
        {
            Console.WriteLine($"❌ [నిధుల లోపం]: {ex.Message} (లోటు మొత్తం: ₹{ex.Deficit:N2})");
        }
        catch (DailyLimitExceededException ex)
        {
            Console.WriteLine($"⚠️ [పరిమితి హెచ్చరిక]: {ex.Message}");
        }
        catch (CardBlockedException ex)
        {
            Console.WriteLine($"🚨 [సెక్యూరిటీ అలర్ట్]: {ex.Message}");
        }
        catch (ArgumentException ex)
        {
            Console.WriteLine($"❌ [చెల్లని ఇన్‌పుట్]: {ex.Message}");
        }
        catch (Exception ex)
        {
            Console.WriteLine($"🔥 [అనూహ్య లోపం]: సిస్టమ్ తాత్కాలికంగా పనిచేయడం లేదు. {ex.Message}");
        }
    }
}

// డ్రైవర్ కోడ్: వివిధ ఎక్సెప్షన్ దృశ్యాల సిమ్యులేషన్
AtmController atm = new AtmController();

// దృశ్యం 1: చెల్లుబాటు అయ్యే విత్‌డ్రా
atm.ProcessWithdrawal("4591-XXXX-1234", 5000m);

// దృశ్యం 2: ₹100 గుణిజం కాని మొత్తం
atm.ProcessWithdrawal("4591-XXXX-1234", 1250m);

// దృశ్యం 3: రోజువారీ పరిమితి దాటిన మొత్తం
atm.ProcessWithdrawal("4591-XXXX-1234", 25000m);

// దృశ్యం 4: బ్యాలెన్స్ కంటే ఎక్కువ మొత్తం
atm.ProcessWithdrawal("4591-XXXX-1234", 32000m);

Console.WriteLine("=================================================");

💻 ఈ ఏటీఎం ఇంజిన్‌ను లైవ్ కంపైలర్‌లో రన్ చేసి చూడండి!

కస్టమ్ ఎక్సెప్షన్లు, IDisposable హార్డ్‌వేర్ షట్టర్ ఆటో-క్లోజ్, మరియు వివిధ వైఫల్యాల నిర్వహణను ప్రత్యక్షంగా వీక్షించండి.

13 🎓 ఇంటర్వ్యూ ప్రశ్నలు, బెస్ట్ ప్రాక్టీసెస్ & 5 ఇంటరాక్టివ్ క్విజ్ ప్రశ్నలు

టాప్ ఇంటర్వ్యూ ప్రశ్నలు & సమాధానాలు:

Q1: throw; మరియు throw ex; ల మధ్య సాంకేతిక వ్యత్యాసం ఏమిటి?

జవాబు: throw; అసలైన ఎక్సెప్షన్ ఎక్కడ పుట్టిందో ఆ ఒరిజినల్ కాల్ స్టాక్ ట్రేస్‌ను యథాతథంగా భద్రపరుస్తుంది. కానీ throw ex; అసలైన కాల్ స్టాక్‌ను రీసెట్ చేసి, ప్రస్తుత క్యాచ్ బ్లాక్ లైన్ నంబర్‌నే ఎర్రర్ మూలంగా చూపిస్తుంది. దీనివల్ల ప్రొడక్షన్‌లో బగ్స్ ఎక్కడ వచ్చాయో కనిపెట్టడం అసాధ్యమవుతుంది.

Q2: finally బ్లాక్ ఎప్పుడైనా ఎగ్జిక్యూట్ కాకుండా ఆగిపోయే సందర్భం ఉందా?

జవాబు: సాధారణ కోడ్ ఎగ్జిక్యూషన్‌లో (రిటర్న్ స్టేట్‌మెంట్లు ఉన్నా సరే) finally ఖచ్చితంగా రన్ అవుతుంది. కానీ 1) Environment.FailFast() పిలిచినప్పుడు, 2) ఆపరేటింగ్ సిస్టమ్ ప్రాసెస్‌ను ఫోర్స్‌ఫుల్‌గా కిల్ చేసినప్పుడు (Task Manager End Task), 3) పవర్ కట్ లేదా హార్డ్‌వేర్ క్రాష్ అయినప్పుడు మాత్రమే finally రన్ అవ్వదు.

🧠 మీ నాలెడ్జ్ చెక్ చేసుకోండి — 5 ఇంటరాక్టివ్ క్విజ్ ప్రశ్నలు

❓ ప్రశ్న 1: try బ్లాక్ లోపల return 10; ఉంటే, finally బ్లాక్ రన్ అవుతుందా?
సమాధానం: ఖచ్చితంగా రన్ అవుతుంది. కంపైలర్ రిటర్న్ విలువను పక్కనపెట్టి, ముందుగా finally బ్లాక్ పూర్తి చేసిన తర్వాత మాత్రమే కాలర్‌కు రిటర్న్ చేస్తుంది.
❓ ప్రశ్న 2: బహుళ catch బ్లాకులలో catch (Exception ex) ను మొదటి స్థానంలో పెడితే ఏం జరుగుతుంది?
సమాధానం: కంపైల్-టైమ్ ఎర్రర్ వస్తుంది. ఎందుకంటే Exception అనేది అన్నింటికీ మూల క్లాస్ కాబట్టి అన్ని ఎర్రర్లను అదే పట్టుకుంటుంది, దాని కింద ఉన్న నిర్దిష్ట క్యాచ్ బ్లాకులు ఎప్పటికీ రీచ్ కాలేవు (Unreachable code).
❓ ప్రశ్న 3: C# 6 లో వచ్చిన ఎక్సెప్షన్ ఫిల్టర్ల కోసం ఏ కీవర్డ్ వాడతారు?
సమాధానం: when. ఉదాహరణ: catch (SqlException ex) when (ex.Number == 1205).
❓ ప్రశ్న 4: C# లో using స్టేట్‌మెంట్ అంతర్గతంగా ఏ బ్లాకులను ఉత్పత్తి చేస్తుంది?
సమాధానం: try { ... } finally { obj.Dispose(); }. ఎర్రర్ వచ్చినా సరే Dispose() రన్ అయ్యేలా చేస్తుంది.
❓ ప్రశ్న 5: ఖాళీ క్యాచ్ బ్లాక్ catch (Exception) { } రాయడం ఎందుకు తీవ్రమైన తప్పు?
సమాధానం: దీనిని "Swallowing Exceptions" అంటారు. ఎర్రర్ సమాచారం లాగ్ కాకుండా నిశ్శబ్దంగా దాగిపోతుంది, దీనివల్ల అప్లికేషన్‌లో బగ్‌లను గుర్తించడం అసాధ్యమవుతుంది.
← Previous: 16. ఇంటర్‌ఫేసెస్ & Records (Phase 04) Next: 18. డెలిగేట్స్, ఈవెంట్స్ & లాంబ్డా →
OC
Written by Our Compiler Technical Editorial Team
Reviewed for accuracy & tested on .NET 8 SDK / C# 12 runtime · 2026 Academic Edition