Free Ebook cover C# Essentials: Building Console Apps with .NET

C# Essentials: Building Console Apps with .NET

New course

12 pages

Reading .NET API Documentation and Applying It in Code

Capítulo 11

Estimated reading time: 11 minutes

+ Exercise

Why API Documentation Matters When You’re Coding

In .NET, most of what you build depends on existing APIs: the Base Class Library (BCL), framework libraries, and package APIs. Official documentation helps you answer practical questions quickly: Which type should I use? What overload fits my scenario? What does a method return? What exceptions should I handle? What edge cases are called out in remarks? This chapter focuses on turning documentation into correct code decisions, not memorizing APIs.

1) Identifying the Right Type and Namespace

Documentation pages are organized around types (classes, structs, interfaces, enums, delegates) and their members. Your first job is to locate the correct type and ensure you’re using the correct namespace in code.

How to locate the correct type

  • Start from the task: “parse a date”, “generate a random number”, “encode text”, “make an HTTP request”, “work with JSON”, “measure elapsed time”.
  • Find the type page: search for the type name if you know it, or search by task keywords plus “.NET”.
  • Confirm the namespace: the docs show the namespace (for example, System, System.Text, System.Net.Http).
  • Confirm the assembly/package: docs often indicate which assembly contains the type. This helps you know whether it’s built-in or requires a package reference.

What to extract from the type page

  • Purpose summary: one or two lines describing what the type is for.
  • Common members: constructors, key methods, properties.
  • Thread-safety notes (if present): whether instances can be shared.
  • Platform notes: if something behaves differently on different OSes.

Guided task: find the right type and add the correct using

Task: You want to measure how long a piece of work takes in your console app.

  • In docs, locate the type used for timing: Stopwatch.
  • Confirm its namespace: System.Diagnostics.
  • In code, add using System.Diagnostics; and create a small timing block.
using System.Diagnostics;  // from the docs: Stopwatch lives here
var sw = Stopwatch.StartNew(); // docs show StartNew as a convenient factory method
// ... do work ...
sw.Stop();
Console.WriteLine($"Elapsed: {sw.ElapsedMilliseconds} ms");

2) Understanding Method Signatures and Overloads

Once you’re on the right type page, the next skill is reading member signatures. In .NET, many methods have multiple overloads: same name, different parameters. Documentation lists overloads and shows what each one accepts and returns.

How to read a signature

  • Method name: what you call.
  • Parameter list: types, names, optional parameters, default values.
  • Return type: what you get back (or void).
  • Static vs instance: static methods are called on the type; instance methods are called on an object.
  • Async patterns: methods returning Task/Task<T> are asynchronous; docs often mention cancellation tokens and timeouts.

Overload selection strategy

  • Prefer the overload that makes your intent explicit (for example, specifying a comparison rule rather than relying on defaults).
  • Prefer overloads that avoid ambiguous defaults (culture, encoding, case sensitivity, time zone assumptions).
  • Prefer overloads that let you handle failure without exceptions when available (for example, TryXxx patterns).

Guided task: choose an overload based on documented behavior

Task: Extend your app to accept a date from the user and parse it reliably. In docs, compare DateTime.Parse vs DateTime.TryParse and their overloads. Choose an overload that lets you detect invalid input without throwing exceptions.

Continue in our app.

You can listen to the audiobook with the screen off, receive a free certificate for this course, and also have access to 5,000 other free online courses.

Or continue reading below...
Download App

Download the app

What to look for in docs:

  • Overload list for DateTime.TryParse.
  • Parameter descriptions: input string, format provider, styles, and the out result.
  • Return value: true if parsing succeeded.
using System.Globalization;
Console.Write("Enter a date (e.g., 2026-01-16): ");
string? input = Console.ReadLine();
if (DateTime.TryParse(
        input,
        CultureInfo.InvariantCulture,
        DateTimeStyles.AssumeLocal,
        out var date))
{
    Console.WriteLine($"Parsed: {date:O}");
}
else
{
    Console.WriteLine("Could not parse that date.");
}

Why this is a documentation-driven choice: the docs for TryParse tell you it returns a boolean instead of throwing for common invalid inputs, and the overload documentation explains how culture and styles influence interpretation.

3) Reading Parameter and Return Descriptions

Parameter and return sections are where docs become actionable. They clarify what values mean, what ranges are allowed, how null is treated, and what the method promises.

What to look for in parameter descriptions

  • Nullability: whether null is allowed and what happens if it is passed.
  • Units: milliseconds vs seconds, bytes vs characters.
  • Valid ranges: minimum/maximum values.
  • Ownership and lifetime: whether the method stores a reference or copies data.
  • Encoding/culture rules: especially for parsing and formatting.

What to look for in return descriptions

  • Success/failure signals: boolean return, sentinel values, or exceptions.
  • What is returned on edge cases: empty input, not found, invalid format.
  • Whether a new object is created or an existing instance is returned.

Mini exercise: verify assumptions about a return value

Task: You need to find a substring and decide what to do if it’s not present. In docs, locate string.IndexOf and read what it returns when the value is not found. Then implement behavior based on that documented return.

Console.Write("Enter a sentence: ");
string text = Console.ReadLine() ?? "";
Console.Write("Enter a word to find: ");
string word = Console.ReadLine() ?? "";
int index = text.IndexOf(word, StringComparison.OrdinalIgnoreCase);
if (index >= 0)
{
    Console.WriteLine($"Found at index {index}.");
}
else
{
    Console.WriteLine("Not found.");
}

Documentation-driven detail: the return description tells you the “not found” value (commonly -1), so you can branch correctly without guessing.

4) Interpreting Exceptions and Remarks

Exception and remarks sections are where you learn how an API fails and what constraints exist. This is essential for writing robust console apps that behave predictably.

How to use the Exceptions section

  • Identify which exceptions are relevant to your inputs (for example, invalid format, out-of-range, null arguments).
  • Decide whether to prevent or handle: validate input first, or catch and recover.
  • Map exceptions to user-friendly messages: console apps should explain what went wrong and what to do next.

How to use the Remarks section

  • Look for default behaviors: comparison rules, culture usage, rounding, time zone assumptions.
  • Look for performance notes: allocations, complexity, recommended alternatives.
  • Look for security notes: cryptography APIs, randomness, input validation.

Guided task: handle documented exceptions by choosing a safer API

Task: Extend your app to ask the user for a number and compute a square root. In docs, compare int.Parse with int.TryParse. The exceptions section for Parse typically lists format and overflow exceptions. Choose TryParse to avoid those exceptions for user input, then confirm behavior by running the program with invalid and too-large values.

Console.Write("Enter a whole number: ");
string? raw = Console.ReadLine();
if (!int.TryParse(raw, out int n))
{
    Console.WriteLine("That was not a valid 32-bit integer.");
    return;
}
if (n < 0)
{
    Console.WriteLine("Square root is not defined for negative integers in real numbers.");
    return;
}
double result = Math.Sqrt(n);
Console.WriteLine($"sqrt({n}) = {result}");

Documentation-driven detail: the docs for TryParse describe the boolean return and the out parameter, while the docs for Parse list exceptions that you can avoid for interactive input.

Guided task: handle a documented exception explicitly

Task: Your app asks for a file path and reads all text. In docs for File.ReadAllText, review the exceptions section (common ones include invalid path, file not found, unauthorized access, directory not found). Implement a focused catch for a couple of likely exceptions and confirm behavior by testing with a missing file and a path you don’t have access to.

Console.Write("Enter a file path to read: ");
string path = Console.ReadLine() ?? "";
try
{
    string contents = File.ReadAllText(path);
    Console.WriteLine("File contents:");
    Console.WriteLine(contents);
}
catch (FileNotFoundException)
{
    Console.WriteLine("The file was not found. Check the path and try again.");
}
catch (UnauthorizedAccessException)
{
    Console.WriteLine("Access denied. Try a different file or run with appropriate permissions.");
}
catch (DirectoryNotFoundException)
{
    Console.WriteLine("The directory does not exist. Check the folder path.");
}

Documentation-driven detail: you’re not guessing which exceptions might occur; you’re using the list provided by the API docs to decide what to handle.

5) Spotting and Adapting Examples

Examples in official docs are valuable because they show intended usage patterns, typical parameter values, and common combinations of calls. The key skill is adapting examples to your app rather than copying blindly.

How to adapt examples safely

  • Identify the minimal pattern: what is essential (for example, create client, send request, read response).
  • Replace placeholders: URLs, file paths, formats, encodings.
  • Keep the same error-handling shape if the example demonstrates it.
  • Check remarks and exceptions to see what the example omits.

Guided task: use docs to pick an overload and confirm behavior

Task: Your app needs to write text to a file using a specific encoding. In docs for File.WriteAllText, find an overload that accepts an Encoding. Use it to write UTF-8 text and then read it back to confirm the result.

using System.Text;
Console.Write("Enter output file path: ");
string outPath = Console.ReadLine() ?? "output.txt";
Console.Write("Enter a line of text (include non-ASCII if you want): ");
string line = Console.ReadLine() ?? "";
// Docs show an overload that accepts Encoding
File.WriteAllText(outPath, line, new UTF8Encoding(encoderShouldEmitUTF8Identifier: false));
string roundTrip = File.ReadAllText(outPath, Encoding.UTF8);
Console.WriteLine($"Read back: {roundTrip}");

Documentation-driven detail: the overload list tells you which method accepts an Encoding, and the parameter descriptions clarify that the encoding affects how characters are written to bytes.

Workflow: Turning Docs Into Code Decisions

A repeatable 6-step workflow

  • 1. Identify the type: confirm it matches your task.
  • 2. Confirm namespace and availability: ensure you can reference it in your project.
  • 3. Read the overload list: pick the overload that matches your inputs and desired behavior.
  • 4. Read parameters and return value: clarify null handling, units, ranges, and failure signals.
  • 5. Read exceptions and remarks: decide what to validate and what to catch.
  • 6. Check examples: adopt the intended usage pattern, then adapt.

Hands-on Lab: Extend an App Using Documentation

This lab combines overload selection, exception handling, and behavior confirmation. You will implement a small “input to file” feature driven by documentation choices.

Lab goal

Ask the user for a file path, a maximum allowed character count, and a line of text. If the line is too long, trim it. Then write it to a file using a chosen encoding overload. Handle likely file exceptions based on documentation. Confirm behavior by running tests.

Step 1: Use docs to choose the right overloads

  • For parsing the maximum length: choose int.TryParse (docs: avoids exceptions for invalid input).
  • For writing: choose File.WriteAllText(path, contents, encoding) (docs: overload accepts encoding).
  • For trimming: use string.Substring and confirm in docs what exceptions occur if indexes are invalid; prevent them by checking length first.

Step 2: Implement the feature

using System.Text;
Console.Write("Enter output file path: ");
string path = Console.ReadLine() ?? "output.txt";
Console.Write("Enter max characters (e.g., 20): ");
string? maxRaw = Console.ReadLine();
if (!int.TryParse(maxRaw, out int maxChars) || maxChars < 0)
{
    Console.WriteLine("Max characters must be a non-negative integer.");
    return;
}
Console.Write("Enter a line of text: ");
string text = Console.ReadLine() ?? "";
if (text.Length > maxChars)
{
    text = text.Substring(0, maxChars);
}
try
{
    var utf8NoBom = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false);
    File.WriteAllText(path, text, utf8NoBom);
    Console.WriteLine("Saved.");
}
catch (UnauthorizedAccessException)
{
    Console.WriteLine("Access denied for that path.");
}
catch (DirectoryNotFoundException)
{
    Console.WriteLine("Directory not found. Check the folder path.");
}
catch (IOException ex)
{
    Console.WriteLine($"I/O error: {ex.Message}");
}

Step 3: Confirm behavior with quick experiments

  • Enter a non-integer for max characters and confirm the program does not crash (docs-driven: TryParse returns false).
  • Enter a very small max (like 3) and confirm the saved file contains only the first 3 characters (docs-driven: Substring(0, max) behavior).
  • Enter a path to a non-existent directory and confirm you hit the documented DirectoryNotFoundException catch.
  • Enter a path you cannot write to and confirm you hit the documented UnauthorizedAccessException catch.

Checklist: Validate Assumptions with Docs and Micro-Tests

  • Type check: Did I pick the correct type for the job, and is it in the expected namespace?
  • Overload check: Did I choose the overload that makes culture/encoding/comparison rules explicit?
  • Null and range check: Do parameter docs allow null? Are there valid ranges or special values?
  • Failure mode check: Does the API signal failure via return value, exception, or both?
  • Exception check: Which documented exceptions are realistic for my inputs and environment?
  • Remarks check: Are there default behaviors that could surprise users (culture, case sensitivity, time zones)?
  • Example check: Does the official example match my scenario, or do I need to adapt it?
  • Micro-test check: Can I write a 30-second experiment in the console to confirm the behavior I’m relying on?

Now answer the exercise about the content:

When accepting user input that might be invalid (like a date or whole number), which approach best follows the guidance for turning API documentation into safer code decisions?

You are right! Congratulations, now go to the next page

You missed! Try again.

Documentation often shows that TryXxx methods (like DateTime.TryParse and int.TryParse) return true/false and fill an out value, letting you handle invalid user input without exceptions.

Next chapter

Capstone: Build a Complete C# .NET Console Utility

Arrow Right Icon
Download the app to earn free Certification and listen to the courses in the background, even with the screen off.