AlgoMaster Logo

Methods Basics

Last Updated: May 17, 2026

12 min read

A method is a named block of code that runs when something calls it. Every C# program is made of methods, starting with the entry point and branching out. This chapter covers what a method actually is, how to declare one, how to call it, the parts that make up its definition, and the rules around where methods live and how they're named. The parameter and return-type details are kept light here; the _Method Parameters_ and _Return Types & Tuples_ lessons take those apart in depth.

Why Methods Exist

Before the syntax, the reason. Take a tiny program that prints the subtotal of three cart items:

The same three lines repeat three times. Variable names like price1, price2, price3 aren't really three different things, they're three instances of the same idea. If the formula has to change tomorrow (add a discount, format differently), you'd edit it in three places and probably miss one.

Now the same logic with a method:

Same result. The formula lives in one place. The name PrintSubtotal describes what's happening. Adding a fourth item is one line, not four.

That captures the three reasons methods exist:

  • Reuse. Write the logic once, call it as many times as you need.
  • Naming. A good method name explains what a block of code does, so the reader doesn't have to decode the body.
  • Testability. A named, self-contained block can be tested on its own. We'll get to testing later in the course, but the foundation is here: a method is the smallest unit of "a thing that does something."

Beyond these three, methods also let you hide complexity. A caller of PrintSubtotal doesn't need to know whether the price is multiplied by quantity, divided by some factor, or run through a discount table. They just say "print the subtotal for these inputs."

Anatomy of a Method

A method declaration in C# has a fixed shape. Here is the most common form, with each part labeled:

Reading left to right, the pieces are:

  • Modifiers (static here). Keywords that affect how the method behaves or who can call it.
  • Return type (void here). The kind of value the method gives back to its caller, or void if it returns nothing.
  • Name (PrintSubtotal). The identifier you use to call the method. PascalCase by convention.
  • Parameter list ((int itemNumber, decimal price, int quantity)). The inputs the method accepts. Each parameter has a type and a name, separated by commas. The parentheses are required even when the list is empty.
  • Body ({ ... }). The block of code that runs when the method is called.

The same picture as a diagram:

The first three pieces together (static void PrintSubtotal(int itemNumber, decimal price, int quantity)) are called the method signature. The body that follows is the method implementation. The signature is the contract: it tells callers what the method is called, what it expects, and what it returns. The body is how that contract is fulfilled.

Two methods can share the same name if their parameter lists differ. That's called overloading, and it's the topic of the _Method Overloading_ lesson. For now, treat each method as having a unique name in its file.

Declaring a Simple Method

The most basic method takes no input and returns nothing. It just does something when called.

Three things to notice. First, the method is declared after the call site. Order doesn't matter for top-level methods; the compiler reads the whole file before deciding what's valid. Second, the parentheses at the call site are required even though there are no arguments. PrintWelcome (without ()) is not a call, it's a reference to the method. Third, each call runs the body from start to finish, then returns to the line after the call.

Adding a parameter lets the caller customize what happens:

The parameter name is a local variable inside the method, populated with whatever string the caller passed in. The two calls pass different strings, so the same body produces different output. Parameters open up a whole topic of their own (value vs reference passing, defaults, named arguments), which is the _Method Parameters_ lesson.

A method can return a value. Use return to send it back:

The return type decimal says "this method gives back a decimal." The return statement specifies which value to give back. Once return runs, the method ends immediately, even if there are more statements after it. Return types get their own lesson (the _Return Types & Tuples_ lesson), including how to return multiple values at once using tuples.

A common pattern combines the two: take inputs, do a calculation, return the result. That's CalculateSubtotal. Another common pattern takes inputs, does something visible (print, save, send), and returns nothing. That's PrintWelcome and GreetCustomer.

void Methods

A method with no return value uses the return type void. The word is a keyword, not a regular type. It means "this method doesn't produce a value; calling it is a statement, not an expression."

You can still use return inside a void method, but with no value after it. It just ends the method early:

The early return lets the method exit when the discount is zero or negative, skipping the rest of the body. This is a common pattern called a guard clause: check the unwanted cases first and bail out, leaving the main flow clean.

What you can't do is assign the result of a void method to a variable:

Since void means "nothing," there's nothing to assign. The compiler stops you at build time. Use void for methods whose purpose is the side effect (printing, updating state, sending a message), not the answer.

Calling Methods

Calling a method runs its body and then resumes execution at the line after the call. The flow looks like this:

Two examples make this concrete. The first call returns a value; the second doesn't:

The runtime hits CalculateTotal(...), jumps into the body, runs the three statements, returns 53.98m, and the call site receives that value. Then the program continues with the next line.

Calls can be nested. A method's result can feed directly into another call:

C# evaluates the inner call first (CalculateTotal runs and returns 53.98m), then passes that to PrintTotal. Nesting reads inside-out: the deepest call runs first.

A method can call other methods. Calling another method is just another statement inside the body:

Three small methods, each with one job, composed by a fourth method that coordinates them. This is the everyday shape of C# code: lots of short methods that call each other, instead of one giant method that does everything.

Expression-Bodied Methods (=>)

When a method body is a single expression, C# offers a shorter syntax called an expression-bodied member. Instead of { return expr; }, you write => expr;. The two forms are equivalent.

The long form:

The expression-bodied form:

Both compile to the same code. Try them side by side:

Expression-bodied form works for void methods too, as long as the body is a single statement:

The single statement here is the Console.WriteLine call, which is a statement that doesn't produce a value. The => form treats it the same way the block form would.

Where the expression-bodied form doesn't fit:

  • When the body has more than one statement.
  • When you need a local variable.
  • When you need an early return or a conditional path.

A method like this can't use =>, because the body is two statements:

A reasonable rule of thumb: use => when the method is a true one-liner whose body is just a calculation or a delegation. Use the block form when there are multiple steps, local variables, or branching. The point of => is to reduce noise for the short cases, not to compress logic.

static Methods

The static keyword on a method means "this method is not tied to any specific object." You call it through the type that contains it, not through an instance.

In the examples so far, every method has been static. That's because top-level statement programs (the kind we've been writing) put their methods at the file level, and those methods are implicitly part of a generated class. Without static, the compiler couldn't call them from the top-level entry point, because there's no instance of that generated class to call them on.

The contrast becomes clearer once classes are involved (the _Classes & Objects_ lesson). For now, the rule that matters is: when you write small programs in a single file, with top-level statements as your entry point, declare every method `static`.

Without static, the compiler reports an error like CS0120: An object reference is required for the non-static field, method, or property 'CalculateOrderTotal(decimal, int)'.

Built-in methods you've already used follow the same pattern. Console.WriteLine is a static method on the Console class, which is why you call it as Console.WriteLine(...) rather than creating a Console object first. Math.Max, int.Parse, and string.IsNullOrEmpty are all static for the same reason: they don't need any object state to do their job, just the inputs you hand them.

Each of those calls follows the pattern TypeName.MethodName(arguments). Your own static methods declared in top-level statements work the same way, with the type name being supplied implicitly by the compiler.

A short summary of the rules at this stage:

ContextModifier to use
Method declared alongside top-level statementsstatic
Method inside a class, callable without an instancestatic
Method inside a class, operates on a specific instanceno static

For methods at this stage, treat static as a required keyword in the programs you write.

Where Methods Live

Every C# method ultimately lives inside a class (or another type like a struct, record, or interface). There is no such thing as a free-floating method that belongs to nothing. What's been happening in the examples is that top-level statements hide this fact: the compiler wraps your file in a generated class behind the scenes, and your static methods become members of that class.

Here is a top-level program:

And here is the equivalent classic form, where the class and entry point are written by hand:

Output (both forms):

Two things differ between the forms. First, the top-level version doesn't write the class Program wrapper or the static void Main() entry point; the compiler generates both. Second, the methods in the top-level version end up as members of that generated class. The behavior at runtime is identical.

For the rest of this section's chapters, you'll see both forms. Short examples use top-level statements because the boilerplate gets in the way. Examples that show multiple methods cooperating, or that mirror how production code is organized, sometimes show the explicit class form. Whichever form you read, remember that methods always live inside a type.

A diagram for the mental model:

One file, one class (in this simple case), many methods, with the entry point calling into the rest.

Method Naming Conventions

C# has a strong, widely followed convention for method names. Following it makes your code look like every other C# codebase, which matters more than you might think when working with teammates or reading docs.

The rules:

  • PascalCase. Every word starts with a capital letter, no underscores or hyphens. CalculateSubtotal, not calculateSubtotal or calculate_subtotal.
  • Verb or verb phrase. A method does something, so its name should read as an action. GetCustomer, SaveOrder, ApplyDiscount, IsAvailable. Avoid noun-only names like Customer or Order for methods; those are class names.
  • Boolean-returning methods start with `Is`, `Has`, `Can`, or `Should`. IsInStock, HasShipped, CanCancel. The name reads like a question, which matches how it'll be used in an if.
  • Avoid abbreviations unless they're universal in the domain (Id, Url). CalculateSub is worse than CalculateSubtotal.
  • Be specific. Process and Handle tell you nothing. ProcessOrder is a little better. PlaceOrder is even better.

A small gallery of names that follow the convention:

Method nameWhat it likely does
CalculateSubtotalReturns the sum of price times quantity
ApplyDiscountReduces a total by some discount
PlaceOrderCreates and records an order
IsInStockReturns a bool for whether stock is available
HasShippedReturns a bool for whether shipping has started
GetCustomerEmailLooks up an email by customer ID
TrySaveOrderTries to save and returns success without throwing
FormatPriceTurns a decimal into a display string

And a few that don't:

Bad nameWhy
calcLowercase start, abbreviated, vague
DoStuffTells you nothing about what it does
OrderLooks like a class name, not an action
process_orderWrong casing style for C#
CalcSubAndUpdtCartCrammed, abbreviated, does two things

The last one points at another rule that follows from the conventions: one job per method. If you find yourself wanting to put "And" in a name, that's usually a sign the method should be split into two. CalculateSubtotal and UpdateCart, called in sequence, are easier to read, test, and change than a single CalcSubAndUpdtCart.

Parameter names use camelCase: lowercase first letter, capital starts for subsequent words. productName, not ProductName or product_name. The casing makes them visually distinct from method and type names inside the body.

The method name is CalculateOrderTotal (PascalCase, verb-first, specific). The parameters are unitPrice, quantity, and discountRate (camelCase, descriptive). The local variables subtotal and discount also use camelCase, matching the parameter style.

Putting It Together

A worked example that uses every idea from this chapter. The program prints a small receipt for an order, breaking the work into named methods.

Look at what the example uses:

  • Six static methods, each with one job.
  • A mix of expression-bodied (=>) and block-bodied ({ ... }) forms, chosen by body length.
  • A mix of void and value-returning methods.
  • PascalCase method names that read as actions (PrintHeader, CalculateSubtotal, PrintFooter).
  • camelCase parameter names (unitPrice, qty, amount, rate, label, customer).
  • A top-level entry that orchestrates the work by calling the smaller methods in order.

If you wanted to change the formatting of every line, you'd edit PrintLine once and every line in the output would update. If you wanted to add tax, you'd add CalculateTax next to CalculateDiscount and adjust the orchestration at the top. That's the payoff for splitting code into methods: each piece is small, named, and changeable without disturbing the rest.

The pieces this chapter intentionally didn't cover:

  • How parameter passing actually works (by value, by reference, default values). The _Method Parameters_ lesson.
  • The ref, out, and in parameter modifiers. The _ref, out & in Parameters_ lesson.
  • Returning multiple values, tuples, and pattern-deconstruction of returns. The _Return Types & Tuples_ lesson.
  • Two methods sharing a name with different parameter lists (overloading). The _Method Overloading_ lesson.
  • Variable-length argument lists with params. The _params Keyword_ lesson.
  • Methods that call themselves (recursion). The _Recursion_ lesson.
  • Methods declared inside other methods (local functions). The _Local Functions_ lesson.

Each of those builds on what you've seen here. Methods at their core, declaration, calling, anatomy, naming, static, expression-bodied, and where they live, are everything in this chapter. The _Method Parameters_ lesson zooms in on the part inside the parentheses.

Summary

  • A method is a named block of code with a return type, a name, an optional parameter list, and a body. The first three together form the signature.
  • Calling a method runs its body and then resumes at the line after the call. Calls can be nested, and methods can call other methods.
  • A void method returns no value. Use return; with no value to exit early.
  • An expression-bodied method (=> expr;) is shorthand for a body that is a single expression or statement. The compiler emits identical IL for both forms.
  • When you declare a method next to top-level statements, mark it static. Without static, it becomes a local function instead of a class member.
  • Methods always live inside a type. Top-level statements hide this by generating a wrapper class behind the scenes, but the rule still holds.
  • Use PascalCase for method names (CalculateSubtotal), camelCase for parameter names (unitPrice), and prefer verb-first, specific names. Boolean methods read as questions (IsInStock, HasShipped).
  • Each method should do one job. If you find yourself wanting "And" in a name, split it into two.

The next chapter, Method Parameters, digs into the part inside the parentheses: how values are passed in, the difference between value-type and reference-type parameter behavior, default values, and named arguments.