C# Methods

Organise code into reusable methods, pass data in with parameters, return results, use optional and named arguments, overload methods, return several values with tuples and out, and write short expression-bodied methods.

Lesson 8 of 43Beginner18 min read

As programs grow, writing everything in one long block quickly becomes unmanageable. Methods let you package a piece of logic, give it a clear name, and reuse it wherever it's needed. Instead of repeating the code that calculates VAT in five places, you write CalculateVat(price) once and call it five times. If the VAT rate changes, you fix one method.

A method can take parameters (inputs) and return a result (output). You've already been calling methods: Console.WriteLine, Math.Round and int.TryParse are all methods written by the .NET team. Now you'll write your own.

C# methods have useful extras: optional parameters with default values, named arguments that make calls self-explanatory, overloading so one name can accept different inputs, and tuples for returning several values at once. In this lesson you'll use all of them, and see how small, well-named methods make code easier to read, test and change.

Declaring and calling methods

C#
static decimal AddVat(decimal price)
{
    return price * 1.2m;
}

static void PrintTitle(string text)
{
    Console.WriteLine(text.ToUpper());
}

decimal withVat = AddVat(50m);     // 60.0
PrintTitle("report");
  • The return type comes first: decimal, string, bool, or void when nothing is returned.
  • Parameters are listed in brackets with their types; the values you pass when calling are arguments.
  • return sends a value back and ends the method immediately.
  • Method names use PascalCase and usually start with a verb: CalculateTotal, SendEmail, IsValid.
  • In top-level programs, methods written in Program.cs are local functions; inside classes they're members, often marked static when they don't use an object's data.

Short methods, defaults and named arguments

A method whose body is a single expression can use =>:

C#
static double Area(double width, double height) => width * height;

Optional parameters have a default value and can be left out:

C#
static string Greet(string name, string greeting = "Hello") => $"{greeting}, {name}!";

Greet("Ada");                      // Hello, Ada!
Greet("Ada", "Welcome back");      // Welcome back, Ada!
Greet(greeting: "Hi", name: "Bo"); // named arguments, in any order

Named arguments make calls with several values readable: CreateUser("ada", isAdmin: true, sendEmail: false) is much clearer than CreateUser("ada", true, false).

Overloading and returning several values

Overloading means several methods share a name but take different parameters. C# picks the right one from the arguments:

C#
static int Max(int a, int b) => a > b ? a : b;
static int Max(int a, int b, int c) => Max(Max(a, b), c);

To return more than one value, use a tuple:

C#
static (int Min, int Max) Range(int[] values) => (values.Min(), values.Max());
var (low, high) = Range(new[] { 4, 9, 2 });

You'll also see out parameters, as in int.TryParse(text, out int n), which give back an extra value. ref lets a method change the caller's variable, and params int[] numbers accepts any number of arguments.

Methods that call themselves

A method can call itself, which is called recursion. It suits problems that contain smaller copies of themselves, such as folders inside folders or menus inside menus. A classic example is the factorial, where 5! is 5 × 4 × 3 × 2 × 1:

C#
static long Factorial(int n)
{
    if (n <= 1) return 1;          // base case: stop here
    return n * Factorial(n - 1);   // smaller version of the same problem
}

Console.WriteLine(Factorial(5));   // 120

Every recursive method needs a base case that returns without calling itself. Each call waits on the call stack until the call it made has finished, so a missing or unreachable base case keeps adding calls until the stack runs out. The result is a StackOverflowException, which ends the whole program and can't be caught with try/catch.

For simple counting jobs like this one, a loop is just as clear and uses less memory. Save recursion for tree-shaped data, where a loop would need you to manage your own stack of items.

C# Methods Syntax

Method forms

static int Square(int x) { return x * x; }
static int Cube(int x) => x * x * x;
static void Log(string msg, bool urgent = false) { }
Log("Saved", urgent: true);
static (string First, string Last) Split(string full) { ... }
var (first, last) = Split("Ada Lovelace");
static bool TryFind(int id, out string name) { ... }
static int Sum(params int[] nums) => nums.Sum();
Sum(1, 2, 3);

C# Methods Summary

  • Methods have a return type, a name, parameters and a body; void returns nothing.
  • return sends back a value and ends the method.
  • => writes single-expression methods; optional parameters have defaults.
  • Named arguments make calls clear and can be given in any order.
  • Overloads share a name with different parameters; tuples return several values.

C# Methods Examples

Each example shows the code, the output it produces and what each part does.

Example 1

A price calculator

C#
decimal LineTotal(decimal price, int quantity, decimal discount = 0)
{
    decimal total = price * quantity;
    return total - total * discount;
}

string Money(decimal amount) => $"£{amount:F2}";

Console.WriteLine(Money(LineTotal(4.50m, 3)));
Console.WriteLine(Money(LineTotal(4.50m, 3, 0.1m)));
Console.WriteLine(Money(LineTotal(quantity: 2, price: 19.99m)));
Output
£13.50
£12.15
£39.98
Line-by-line explanation
  1. Line 1discount is optional and defaults to 0.
  2. Line 4return sends the result back to the caller.
  3. Line 7An expression-bodied method formats money in one line.
  4. Line 9The default discount is used.
  5. Line 1010% off 13.50 is 12.15.
  6. Line 11Named arguments can be passed in any order.
Example 2

Overloads, tuples and params

C#
string Describe(int n) => $"int {n}";
string Describe(double d) => $"double {d}";
string Describe(string s) => $"text '{s}'";

Console.WriteLine(Describe(5));
Console.WriteLine(Describe(2.5));
Console.WriteLine(Describe("hi"));

(int Count, double Average) Stats(params int[] scores)
{
    double avg = scores.Length == 0 ? 0 : scores.Average();
    return (scores.Length, avg);
}

var result = Stats(70, 85, 90);
Console.WriteLine($"{result.Count} scores, average {result.Average:F1}");

var (count, average) = Stats();
Console.WriteLine($"{count} scores, average {average}");
Output
int 5
double 2.5
text 'hi'
3 scores, average 81.7
0 scores, average 0
Line-by-line explanation
  1. Lines 1 to 3Three overloads share a name; C# picks one from the argument's type.
  2. Line 9params lets callers pass any number of ints, or none.
  3. Line 12A tuple returns two named values together.
  4. Line 1570 + 85 + 90 = 245, and 245 / 3 is 81.67, shown as 81.7.
  5. Line 18Deconstruction unpacks the tuple into two variables.
Example 3

out and ref parameters

C#
bool TryGetDiscount(string code, out decimal percent)
{
    percent = code switch
    {
        "SAVE10" => 0.10m,
        "SAVE25" => 0.25m,
        _ => 0m
    };
    return percent > 0;
}

void AddPoints(ref int score, int points)
{
    score += points;
}

foreach (string code in new[] { "SAVE25", "HELLO" })
{
    if (TryGetDiscount(code, out decimal p))
        Console.WriteLine($"{code}: {p:P0} off");
    else
        Console.WriteLine($"{code}: not a valid code");
}

int myScore = 40;
AddPoints(ref myScore, 15);
Console.WriteLine(myScore);
Output
SAVE25: 25% off
HELLO: not a valid code
55
Line-by-line explanation
  1. Line 1An out parameter must be assigned before the method returns.
  2. Line 9The bool result says whether the out value is meaningful, the same pattern as int.TryParse.
  3. Line 12ref lets the method change the caller's own variable.
  4. Line 20:P0 formats 0.25 as a percentage with no decimals.
  5. Lines 26 to 27myScore itself becomes 55.

Common C# Methods Mistakes

Forgetting to return a value

Don't
int Double(int x)
{
    int result = x * 2;        // error CS0161: not all code paths return a value
}
Do
int Double(int x)
{
    return x * 2;
}

Ignoring a returned value

Don't
AddVat(price);                 // the result is thrown away
Console.WriteLine(price);
Do
decimal withVat = AddVat(price);
Console.WriteLine(withVat);

Unclear boolean arguments

Don't
SendInvoice(order, true, false);
Do
SendInvoice(order, includePdf: true, copyToManager: false);

C# Methods in Real Projects

Methods in professional code

Real codebases are made of thousands of small methods with clear names. A checkout service might have CalculateSubtotal, ApplyVoucher, CalculateShipping and ChargeCard, each a few lines long and each covered by unit tests. The TryX(out result) pattern appears throughout .NET, and tuple returns are common for small results that don't deserve their own class.

C# Methods FAQ

What is the difference between a parameter and an argument?

A parameter is the variable listed in the method declaration, such as price in AddVat(decimal price). An argument is the actual value you pass when you call the method, such as 50m in AddVat(50m). People often use the words loosely, but the distinction helps when reading error messages.

What is the difference between ref and out in C#?

Both let a method change a variable the caller owns. A ref argument must already have a value before the call, and the method may read it. An out argument doesn't need a value beforehand, but the method must assign it before returning, which is why TryParse uses out.

How do I return multiple values from a method in C#?

Return a tuple with named elements: static (int Min, int Max) Range(int[] values). The caller can use result.Min or deconstruct it with var (low, high) = Range(values);. For data that travels around your program, a small record or class with named properties is often clearer.

What does static mean on a method?

A static method belongs to the type rather than to a particular object, so you call it on the class, as in Math.Max(a, b), without creating an object first. Use static when the method only works with its parameters, not with an object's fields. You'll see instance methods, which use an object's data, in the classes lesson.

Can a C# method have default parameter values?

Yes. Give the parameter a value in the declaration, such as string greeting = "Hello", and callers can leave it out. Optional parameters must come after required ones, and the default must be a compile-time constant such as a number, string, null or default.

C# Methods Exercises

Answer each one and check it instantly. If you get stuck, open the hint before the answer.

Fill in the blankseasy

Complete the method so it returns the doubled value.

int Twice(int n)
{
     n * 2;
}
Predict the outputeasy

What does this print?

string Greet(string name = "friend") => $"Hi {name}";
Console.WriteLine(Greet());
Multiple choicemedium

What return type does a method that returns nothing have?

Predict the outputmedium

What does this print?

int Add(int a, int b) => a + b;
double Add(double a, double b) => a + b + 0.5;
Console.WriteLine(Add(1, 2));
Multiple choicehard

What must a method with an out parameter do?

C# Methods Quiz

5 questions to check what you learned.

  1. What are the values passed to a method called?

    • Parameters
    • Returns
    • Arguments
    • Variables
  2. What is method overloading?

    • Several methods with the same name but different parameters
    • Calling a method too often
    • A method that calls itself
    • A method with too many lines
  3. What does => mean in int Square(int x) => x * x;?

    • A comparison
    • A lambda stored in a variable
    • A pointer
    • The method body is a single expression whose value is returned
  4. How can a method return two values?

    • It can't
    • Use two return statements
    • Return a tuple such as (int, string), or use out parameters
    • Return void
  5. What does params allow?

    • Passing any number of arguments, which arrive as an array
    • Optional arguments only
    • Named arguments
    • Generic types