Section 6 of 10

Methods and Functions

🎯 What You'll Learn

  • What methods are and why they're essential for code organization
  • How to define and call methods
  • Working with parameters: value, ref, out, and params
  • Return values and the void keyword
  • Method overloading (same name, different parameters)
  • Optional parameters and named arguments
  • Expression-bodied methods for concise syntax
  • Local functions for encapsulating helper logic
  • Recursion: methods that call themselves
  • Best practices for writing clean, maintainable methods

What is a Method?

As your programs grow, you'll notice patterns—the same code appearing in multiple places, long sequences of related statements, complex logic that's hard to follow. Methods solve these problems by letting you group code into named, reusable blocks.

💡 Key Concept

A method is a named block of code that performs a specific task. You define it once and can call (execute) it from anywhere in your program, as many times as needed. Methods can accept input (parameters) and return output (return value).

Think of a method like a recipe. The recipe has a name ("Chocolate Cake"), takes ingredients (parameters), follows steps (the code inside), and produces a result (return value). You don't rewrite the recipe every time you bake—you just reference it by name. Methods work the same way.

Why Use Methods?

  • Reusability: Write once, use many times
  • Organization: Break complex problems into smaller, manageable pieces
  • Readability: CalculateTax() is clearer than 20 lines of tax logic
  • Maintainability: Fix a bug in one place, fixed everywhere
  • Testing: Small methods are easier to test than large code blocks

Defining and Calling Methods

Method Syntax

MethodSyntax.cs C#
// A simple method with no parameters and no return value
static void SayHello()
{
    Console.WriteLine("Hello, World!");
}

// Calling the method
SayHello();  // Output: Hello, World!
SayHello();  // Can call it multiple times
Part Example Description
Access Modifier static Who can access this method
Return Type void What the method gives back (void means nothing)
Method Name SayHello How you refer to the method (PascalCase)
Parameters () Input values the method accepts
Method Body { ... } The code that runs when called

Methods with Parameters

MethodsWithParameters.cs C#
// One parameter
static void Greet(string name)
{
    Console.WriteLine($"Hello, {name}!");
}

Greet("Akwasi");   // Output: Hello, Akwasi!

// Multiple parameters
static void DisplayProduct(string name, decimal price, int quantity)
{
    Console.WriteLine($"Product: {name}, Price: {price:C}, Qty: {quantity}");
}

DisplayProduct("Widget", 19.99m, 100);

Methods with Return Values

MethodsWithReturnValues.cs C#
// Method that returns an int
static int Add(int a, int b)
{
    return a + b;
}

int sum = Add(5, 3);  // sum = 8

// Method that returns a decimal
static decimal CalculateTotal(decimal price, int quantity)
{
    return price * quantity;
}

// Method that returns a bool
static bool IsAdult(int age)
{
    return age >= 18;
}

if (IsAdult(25))
{
    Console.WriteLine("Welcome!");
}

Parameter Passing: Value, ref, out

Pass by Value (Default)

By default, parameters are passed by value—the method receives a copy.

PassByValue.cs C#
static void Double(int number)
{
    number = number * 2;  // Modifies the copy only
}

int x = 10;
Double(x);
Console.WriteLine(x);  // Still 10! (unchanged)

Pass by Reference (ref)

PassByRef.cs C#
static void Double(ref int number)
{
    number = number * 2;  // Modifies the original!
}

int x = 10;
Double(ref x);  // Must use 'ref' when calling
Console.WriteLine(x);  // 20 (changed!)

Output Parameters (out)

OutParameters.cs C#
static void Divide(int dividend, int divisor, out int quotient, out int remainder)
{
    quotient = dividend / divisor;
    remainder = dividend % divisor;
}

Divide(17, 5, out int q, out int r);
Console.WriteLine($"17 ÷ 5 = {q} remainder {r}");  // 3 remainder 2

// You've already seen this with TryParse!
if (int.TryParse("42", out int result))
{
    Console.WriteLine(result);
}

params: Variable Number of Arguments

ParamsKeyword.cs C#
static int Sum(params int[] numbers)
{
    int total = 0;
    foreach (int num in numbers)
    {
        total += num;
    }
    return total;
}

Console.WriteLine(Sum(1, 2));              // 3
Console.WriteLine(Sum(1, 2, 3, 4, 5));   // 15
Console.WriteLine(Sum());                  // 0

Optional Parameters and Named Arguments

OptionalAndNamed.cs C#
// Optional parameters have default values
static decimal CalculatePrice(
    decimal basePrice,
    int quantity = 1,
    decimal taxRate = 0.125m,
    decimal discountPercent = 0m)
{
    decimal subtotal = basePrice * quantity;
    decimal discount = subtotal * (discountPercent / 100m);
    decimal afterDiscount = subtotal - discount;
    return afterDiscount * (1 + taxRate);
}

// Various ways to call
CalculatePrice(100m);                           // Just base price
CalculatePrice(100m, 5);                       // With quantity
CalculatePrice(100m, quantity: 5, discountPercent: 10m);  // Named args

Expression-Bodied Methods

ExpressionBodied.cs C#
// Traditional
static int Add(int a, int b)
{
    return a + b;
}

// Expression-bodied (same behavior, more concise)
static int Add(int a, int b) => a + b;

static bool IsPositive(int n) => n > 0;
static decimal CalculateTax(decimal amount) => amount * 0.125m;
static void Log(string msg) => Console.WriteLine($"[LOG] {msg}");

Method Overloading

MethodOverloading.cs C#
// Same name, different parameters
static int Add(int a, int b) => a + b;
static int Add(int a, int b, int c) => a + b + c;
static double Add(double a, double b) => a + b;

// Compiler picks the right one
Add(1, 2);           // int version
Add(1, 2, 3);       // 3-param version
Add(1.5, 2.5);      // double version

Local Functions

LocalFunctions.cs C#
static decimal CalculateOrderTotal(decimal[] prices, decimal discountPercent)
{
    // Local function - only visible inside this method
    decimal ApplyDiscount(decimal amount) => amount * (1 - discountPercent / 100m);
    
    decimal subtotal = 0m;
    foreach (decimal price in prices)
    {
        subtotal += price;
    }
    
    return ApplyDiscount(subtotal);
}

Recursion

Recursion.cs C#
// Factorial: n! = n × (n-1) × ... × 1
static int Factorial(int n)
{
    if (n <= 1) return 1;  // Base case
    return n * Factorial(n - 1);  // Recursive case
}

Console.WriteLine(Factorial(5));  // 120
⚠️ Recursion Pitfalls

Every recursive method needs a base case to stop. Without it, you'll get a StackOverflowException.

Best Practices

BestPractices.cs C#
// 1. Single Responsibility - each method does ONE thing
static bool ValidateOrder(Order order) { ... }
static decimal CalculateTotal(Order order) { ... }
static void SaveOrder(Order order) { ... }

// 2. Descriptive Names - use verbs, be specific
static bool IsUserActive(User user) { ... }  // Good
static bool Check(User u) { ... }           // Bad

// 3. Keep methods short (20-30 lines max)
// 4. Limit parameters (3-4 max, group into objects if more)

Key Takeaways

  • Methods are named, reusable blocks of code that perform specific tasks
  • Parameters pass data in; return values send data back
  • Default is pass-by-value; use ref or out for pass-by-reference
  • params allows variable number of arguments
  • Optional parameters have default values; named arguments improve clarity
  • Expression-bodied methods (=>) are concise for simple methods
  • Method overloading: same name, different parameters
  • Local functions encapsulate helper logic within a method
  • Recursion: methods calling themselves (always need a base case!)
  • Best practices: single responsibility, descriptive names, short methods, few parameters
🚀 Ready for Object-Oriented Programming!

You now understand how to organize code into reusable methods. In the next section, we'll take this further with classes and objects—the foundation of object-oriented programming.