C# Intermediate4 A Secret ServerGoing deeper in C# Exceptions

A Hidden Server

The new information about the Commander that Infinity had told me had been dancing around in my head all night. Who is he? Why doesn't anybody know him? Where is he located and what is his ultimate goal, the reasoning behind his orders? Is he supporting the Rust project? And this didn't even cover half of the questions I had!

"Noname, can you check Commanders authority?" I thought.
"I started two hours ago, Teo," Noname replied.
"Wait, what? Two hours ago? Why did you do that?" I said, surprised.
"I read your thoughts, Teo. I saw that you were worried about Commander and decided to help," Noname answered with an extremely calm voice. "That is what friends do, no?"

"Yes, hm, right," I replied, parsing this new information. "Friends help each other, but they don't typically read each other's minds! Are you really capable of reading my thoughts? Why can't I read your thoughts?"
"Because I'm integrated into your brain, but you are not integrated into mine. Don't worry - I know that you don't fully trust me, but that's okay. I'm still just a machine. But thanks to you, I'm learning what it is to be human."
"Touching," I said, wondering if Noname had learned about sarcasm yet. "But back to my initial question, about Commander's authority? Any results there?" I asked.

"His files are hidden in a server inside Wonderland that's protected from the internal network. I mean it is inaccessible even from Wonderland. I'm completely helpless here. The only way to get that info is to physically connect to that server and read the data," Noname reported.
"Well," I replied, "I can't sleep and have nothing else to do. Where's the server?" I was ready then and there to find it and reveal the mystery around the Commander's persona.

Hidden Server in Codeasy Wonderland

Going Deeper Into Exceptions

I followed Noname's instructions and found the secret server. As soon as I established a connection to that server, Noname got read-only access to some of the files.
"I can't see all the data," Noname said. "You need to open access to me."
"How do I do that?" I asked.
"You need to inject your code into exception handling."
"Ah ha, not a problem! I've already learned exceptions in C#," happy to have something of my own to brag about.
"Great, then you can add three catch blocks to one of the existing try-catch and then..."

"Wait, Noname," I interrupted. "There can only be one catch that corresponds to a try block," I corrected Noname.
"Didn't you say you had learned this topic?" Noname said, doing his best to emulate surprise. He continued, "A try block can have several corresponding catch blocks because code can throw exceptions of different types. For example:"

public double GetLengthRatio(string s1, string s2)
{
    var s1Length = s1.Length; // Can throw NullReferenceException if s1 is null
    var s2Length = s2.Length; // Can throw NullReferenceException if s2 is null

    var ratio =  s1Length / s2Length; // Can throw DivideByZeroException if s2
                                      // is empty

    return ratio;
}

Noname explained: "This code can throw at least two different exceptions: NullReferenceException and DivideByZeroException . You can write code that handles exceptions in a different way depending on their type. "

public double GetLengthRatio(string s1, string s2)
{
    double ratio;

    try
    {
        var s1Length = s1.Length;
        var s2Length = s2.Length;

        ratio = s1Length / s2Length;
    }
    catch(NullReferenceException ex)  // Handling NullReferenceException
    {
        Console.WriteLine($"One of the provided strings is null! Exception: {ex.ToString()}");
        ratio = 0.0;
    }
    catch (DivideByZeroException ex) // Handling DivideByZeroException
    {
        Console.WriteLine($"s2 is empty! Exception: {ex.ToString()}");
        ratio = double.MaxValue;
    }
    catch (Exception ex) // Handling all other exceptions
    {
        Console.WriteLine($"Unknown error. Exception: {ex.ToString()}");
        ratio = 0.0;
    }

    return ratio;
}

"In this example, I used multiple catch blocks to separate handling of different exceptions," Noname explained with a calm and focused voice.
"Why did you call every exception variable 'ex'?" I asked.
"This is a general convention, not a strict rule. You can use any name you want," he answered. "Now let's come back to the order of catch blocks. When an exception occurs inside the try block, CLR first checks it against the first catch block; if it fits, that catch block is executed. If the first catch block doesn't match, it checks the second catch block, then the third, and so on, ending with the last catch block. This behavior forms a rule that you need to follow when you create a catch blocks chain - go from the most specific exception to the most general. As you see in my example, the most general is Exception (which means "any error"), and less specific are DivideByZeroException and NullReferenceException . Try to always specify the type of exceptions that can occur; don't just throw everything in one can of 'any error'. "

"Can I ask one more question? How would I know which exceptions the code throws if I use C# functions written by other programmers?"
"You are growing, Teo! You ask mature questions. And the answer is... Documentation ! I'll show you this in the next example," Noname said.

var input = Console.ReadLine();
var number = int.Parse(input);
Console.WriteLine(number);

"As you already know, int.Parse can throw exceptions under some conditions. But what exceptions? And under what conditions? To answer these questions, use documentation. You can find it here . Look in the section Exceptions . There, you'll find all possible exceptions that this function can throw. For int.Parse , this includes ArgumentNullException, ArgumentException, FormatException, and OverflowException . Each of them is explained in that section. Are you following me?" Noname raised his voice a little.
"I sure am!" I replied. "Time to hack some hidden servers!"

The Information You Seek is In The Documentation

"Well, Teo, we did our best, but this server is protected much more securely than I expected," Noname stated. "We need to continue hacking, this time throwing an exception in one function and catching it in another."
"How does that work, Noname?" I wondered, "Where is the exception-handling code in such case?"
"Take a look at this code snippet," he replied.

public static void Main()
{
    SomeMethod();
}

public static void SomeMethod() // Throws an exception that crashes the
                                // application
{
    throw new ArgumentException("Argument is wrong!");
}

"In this example, the program will terminate because of an unhandled exception, but it can be fixed by adding a try - catch block in the Main function, like this:"

public static void Main()
{
    try
    {
        SomeMethod();
    }
    catch (Exception ex) // The exception is handled here
    {
        Console.WriteLine(ex);
    }
}

public static void SomeMethod() // The exception "jumps out" from here
{
    throw new ArgumentException("Argument is wrong!");
}

Noname continued explaining: " When an exception occurs, it looks for the closest try - catch block to the line where the exception occurred. If there is no try - catch nearby, it 'jumps out' from the function and looks for the try - catch in the function that called the current one, and so on, until it gets to the highest in the hierarchy function ( Main ), and if that one doesn't have a try-catch for this exception, your program will crash . Here, I have a diagram that will help you to understand this." Noname projected something just into my brain so that I had no choice but to look at it.

Handling of the exception that occured in a method/

"Great work, Teo. Now I can start reading data from the server," Noname said.
For a minute or two, he was silent; then he said: "Hm... It seems that my file reader is not disposing of system resources. I'm consuming too many resources and would need to restart several times while reading files on this machine. Could you please add a finally block with resource deallocation?"
"A finally block? What is that?" I asked. Given that Noname was in my head, it seemed odd that he couldn't have anticipated my confusion.

" A try , catch construction has a third block, called finally . It's used to clean up any resources that were allocated in the try block. It can be used without a catch block ( try - finally ), or with it ( try - catch - finally ) ," Noname explained.
"Okay, next question," I said. "What resources does a C# programmer need to clean up? Previously, I didn't clear any resources; everything worked just fine without it." I didn't like to take anything for granted, and this seemed like a good opportunity to learn something new.

"There's a slight difference here between different types of resources. For example, when you create an object of your class or create an int variable, all the resources for those are going to be managed by C#, or more precisely, CLR ( Common Language Runtime ). Such objects are sometimes called managed resources . But if you start working with a world outside of your application; for example, files on a hard disk drive; then CLR will not help in clearing all the resources, and you need to call special functions to do this. Here is an example, of using try - catch - finally when working with files:"

System.IO.StreamReader fileReader = new System.IO.StreamReader("myFile.txt");
int nextCharacter;
try
{
    // Trying to read from file
    nextCharacter = fileReader.Read();
}
catch (System.IO.IOException e)
{
    // Handle an error
    Console.WriteLine($"Error reading from myFile.txt. Message = {e.Message}");
}
finally
{
    if (fileReader != null)
    {
        // Close the file! Cleans up resources in operating system.
        fileReader.Close();
    }
}
// Do something with nextCharacter

"Please, don't be afraid of the functions that you don't know. Even if you have never used files in C#, just read the code. It is not that scary," Noname warned, probably because I looked stressed while looking at the unknown syntax of reading from a file.
"All you need to learn from this example is the try - catch - finally usage. As you see, resource allocation happens in the try block; then, deallocation happens in the finally block. The catch block handles errors that can occur during reading from the file," Noname explained.
"What if an exception is thrown in the try block, and handled in the catch block? Will the finally block still be executed?" I asked.
"Yes, the code in finally (almost) always executes. That's why the finally block is used for deallocation of the system resources - we need to make sure it always happens."

"Great, I'll start scanning, Teo. Go have a rest. I'll ping you if I find anything interesting about Commander," Noname said, closing the communications channel. I wondered if this turned off his mind-reading powers, at least for now.
Waiting wears me down more than work...

Keep up the good work at Codeasy

At Codeasy we believe that learning should be fun and engaging. Please reach out to us to share your feedback and collaboration ideas.