A method is a named block of code that takes inputs (parameters), does its work, and can hand back a result (the return value). In C#, every method lives inside a type; there are no free-standing functions.
Output:
Headphones 48.00
Cable 11.40
Anatomy of a Method
public static decimal PriceWithTax(decimal net, decimal taxRate)
{
return net * (1 + taxRate);
}
- Access modifier (
public,private, ...): who may call it. Omitted, a method isprivateto its type. static: the method belongs to the type, not to an object. More on this below.- Return type: the type of value it returns, or
voidfor none. - Name: PascalCase by convention, usually a verb (
Calculate,SendEmail,TryParse). - Parameter list: zero or more
type namepairs. Each parameter is a local variable initialized from the caller's argument. - Body: the statements between the braces.
The name plus the parameter types (and any ref, out or in modifiers) form the method's signature. The return type is not part of it, which matters for overloading.
Return Values and void
return ends the method immediately and hands a value back. A method with a return type must return a value of that type on every path through it:
static string Grade(int score)
{
if (score >= 50)
return "pass";
} // error CS0161: 'Program.Grade(int)': not all code paths return a value
The compiler checks every branch. Add the missing return "fail";, or a throw if reaching that point is a bug.
A void method returns nothing. It can still use a bare return; to leave early:
Output:
ana@mail.com: newsletter sent
ben@mail.com: not subscribed, skipped
False
True
Expression-Bodied Methods
When a method's body is a single expression, => replaces the braces and the return:
static decimal Discount(decimal price) => price * 0.1m;
static bool IsAdult(int age) => age >= 18;
static void Log(string message) => Console.WriteLine($"[log] {message}");
This is the same method, written shorter. It works for void methods too, as long as the body is one expression (a call, an assignment).
Parameters Are Copies
Arguments are passed by value by default: the parameter receives a copy of the argument. Assigning to the parameter inside the method does not affect the caller's variable:
Output:
inside: 42
after: 21
scores: 70, 85, 100
The List changed because for a reference type the copied value is the reference: the method and the caller point to the same list object. Reassigning scores = new List<int>() inside the method would not affect the caller. To let a method assign to the caller's variable, use ref or out; to give parameters default values and call them by name, use optional parameters and named arguments.
Returning Several Values with a Tuple
Since C# 7.0, a method can return a tuple with named elements, and the caller can deconstruct it into separate variables:
Output:
min 15, max 27, avg 21.0
range 12
_ discards the element you do not need. For results used in many places, a small class or record with named properties documents the shape better than a tuple.
Overloading
Several methods can share a name if their parameter lists differ in number, types or order of types. The compiler picks the best match for each call:
Output:
12.57
13.50
25
Area(5) picks the int version because it is an exact match; Area(2.0) picks the double one. Methods cannot differ only by return type: two Area(int) methods returning int and double are error CS0111, Type 'Program' already defines a member called 'Area' with the same parameter types, because a call like Area(5) could not tell them apart.
A call that no overload accepts fails at compile time too: Area(1, 2, 3) is CS1501, No overload for method 'Area' takes 3 arguments, and Area("big") is CS1503, Argument 1: cannot convert from 'string' to 'double'.
params: A Variable Number of Arguments
A params array parameter accepts any number of arguments, including none. The compiler builds the array for you:
Output:
empty cart: 0 item(s), 0
one item: 1 item(s), 9.99
three items: 3 item(s), 19.75
from array: 2 item(s), 50
Rules: params must be the last parameter (CS0231 otherwise), a method has at most one, and passing an existing array hands that array over as-is. Console.WriteLine("{0} and {1}", a, b) and string.Format are params object[] methods. C# 13 extended params to other collection types such as List<T> and ReadOnlySpan<T>; before that, only arrays were allowed.
Static and Instance Methods
A static method belongs to the type and is called on the type name: Math.Max(3, 7), Program.Total(...). An instance method belongs to an object and can use that object's fields:
Output:
12
Calling an instance method from a static one without an object is the most common beginner error in C#:
class Program
{
void Greet() => Console.WriteLine("hi");
static void Main()
{
Greet();
// error CS0120: An object reference is required for the non-static field, method, or property 'Program.Greet()'
}
}
Mark Greet as static, or create an object and call it on that: new Program().Greet();. The static page covers static members and static classes in more depth.
The Main Method
Main is where a program starts. It must be static, and these signatures are valid:
static void Main() { }
static void Main(string[] args) { } // command-line arguments
static int Main(string[] args) { return 0; } // exit code for the shell
static async Task Main() { } // C# 7.1 and later
The async Task Main form lets the entry point await directly (see async and await). Since C# 9, a file can instead contain top-level statements: code with no class or Main at all, as in a new dotnet new console project. The compiler generates the class and the Main method around it, so it is the same thing written shorter; args is still available.
Recursion
A method can call itself. Each call gets its own parameters and locals, and a base case must stop the chain:
Output:
120
2432902008176640000
35
Without a base case, or with input too deep, every call adds a stack frame until the program dies with StackOverflowException. That exception cannot be caught, so for input of unknown depth, rewrite the recursion as a loop.
Local Functions
C# 7.0 introduced local functions: methods declared inside another method, visible only there. They can use the enclosing method's variables:
// C# 7.0 and later
static int CountValid(string[] codes)
{
int count = 0;
foreach (string code in codes)
{
if (IsValid(code)) count++;
}
return count;
bool IsValid(string c) => c.Length == 6 && char.IsLetter(c[0]);
}
They keep a helper next to its only caller without exposing it to the rest of the class. Since C# 8 they can be marked static to forbid capturing outer variables. Where a local function is not available, a private static method in the same class does the same job, as in the other examples on this page.
Frequently Asked Questions
What is the difference between a method and a function in C#?
In C#, every function is declared inside a class, struct or record, and is called a method. There are no free-standing functions. Even top-level statements (C# 9) and local functions (C# 7) are compiled into methods of a generated or enclosing type. "Function" is used informally, and for lambdas and delegates.
What does params do in C#?
params lets a method take a variable number of arguments of one type: static int Sum(params int[] numbers) can be called as Sum(), Sum(4), Sum(4, 5, 6) or Sum(existingArray). The compiler packs the arguments into an array. The params parameter must be the last one, and a method can have only one.
What is the Main method in C#?
Main is the program's entry point: the method the runtime calls first. It must be static, can return void or int (the exit code), and can take string[] args for the command-line arguments. Since C# 7.1 it can also be async Task Main, and since C# 9 top-level statements let the compiler generate it for you.
How do I return multiple values from a C# method?
Return a tuple: static (int Min, int Max) Range(int[] values) and return (min, max);. The caller can read result.Min or deconstruct with var (lo, hi) = Range(values);. For values that travel together across your code, a small class or record is clearer; out parameters are the older alternative.
Why do I get "An object reference is required for the non-static field, method, or property"?
A static method such as Main called an instance method directly. Static methods belong to the type and have no object to call it on. Either mark the called method static, or create an object first: var app = new Program(); app.Greet();.
What does "not all code paths return a value" mean?
Error CS0161: a method with a return type has at least one path that reaches the closing brace without a return. Usually an if returns a value but there is no else or final return after it. Add a return (or throw) at the end of the method.