Return. In C# programs, methods return only one value. A return statement is a jump statement. It transfers control unconditionally to the endpoint of the call site in the stack frame.
Keyword notes. When a method is declared "void," no return value is included after "return." Other methods must return the correct value.
An example. As a jump statement, return affects control flow. Control flow models the path of the execution engine when it manipulates evaluation stacks in methods.
Info Whenever an argument to a method is encountered, a token is pushed onto the stack and the new method is invoked.
Detail In the called method, 3 kinds of memory are allocated: the parameter slots, the local variable slots, and the evaluation stack.
Start MethodA loads the constant 100 and returns that value to the call site. MethodA is small so it is often inlined.
And The integer resulting from the expression is placed on the stack and this single 4-byte value is copied to the call site.
using System;
class Program
{
static void Main()
{
// Call four methods and store their return values.
int value1 = MethodA();
string value2 = MethodB(true);
string value3 = MethodB(false);
int value4 = MethodC(5, 2);
// Display the results.
Console.WriteLine(value1);
Console.WriteLine(value2);
Console.WriteLine(value3);
Console.WriteLine(value4);
// Invoke a void method.
MethodD();
}
static int MethodA()
{
// This method returns a constant integer.
return 100;
}
static string MethodB(bool flag)
{
// This method returns a string reference based on the flag.
return flag ?
"cat" :
"dog";
}
static int MethodC(int operand1, int operand2)
{
// This method returns an integer based on an expression.
return (operand1 * 10) + operand2;
}
static void MethodD()
{
// This method uses a return statement with no expression (void).
Console.WriteLine("MethodD executed");
return;
}
}100
cat
dog
52
MethodD executed
Expression-bodied methods. Some methods that return values do not use a return statement. The C# language supports expression-bodied methods.
Tip These methods are written more like lambda expressions. We use the lambda operator, and no "return" keyword is specified.
Detail The result of the expression is treated as a return value. So an invisible "return" is assumed by the C# compiler.
using System;
class Program
{
// An expression-bodied method.
static string FormatFancy(string name) => ("Name: " + name.ToUpper());
static void Main(string[] args)
{
// Call the FormatFancy method.
string result = FormatFancy("sam");
Console.WriteLine(result);
}
}Name: SAM
Nested local function. A function can be declared as a local function. It has access to the locals within the enclosing scope—it can read and write to them.
Here We introduce a local function called CreateString. It changes the value of "multiplier" on each call.
And The CreateString method returns a string created with string interpolation syntax.
Warning This syntax form may be useful, but often a top-level method in a class is more standard and will be easier for others to use.
using System;
class Program
{
static void Main()
{
int multiplier = 10;
// This is a local function.// ... It can access and change local variables in the surrounding scope.
string CreateString(int value)
{
// Use string interpolation.// ... Modify multiplier after accessing its value.
return $"STRING HAS VALUE: {value * multiplier++}";
}
// Call the local function.
Console.WriteLine(CreateString(5));
Console.WriteLine(CreateString(5));
}
}STRING HAS VALUE: 50
STRING HAS VALUE: 55
Return optimization. In algorithms we often have methods that return a single value. It is tempting to use a ref or out parameter in C# here.
Version 1 This version uses the out keyword. The "result" is set and made available to the calling code.
Version 2 This method uses the return statement. It is a more traditional, C-like method. It performs better.
Result The return-statement is faster. If we reorder the test so that Method2 precedes Method1, the result is similar.
using System;
using System.Diagnostics;
class Program
{
const int _max = 1000000;
static void Main()
{
int temp;
Method1("", out temp);
Method2("");
// Version 1: use out return parameter.
var s1 = Stopwatch.StartNew();
for (int i = 0; i < _max; i++)
{
int result;
Method1("cat", out result);
if (result != 6)
{
throw new Exception();
}
}
s1.Stop();
// Version 2: use single return value.
var s2 = Stopwatch.StartNew();
for (int i = 0; i < _max; i++)
{
int result = Method2("cat");
if (result != 6)
{
throw new Exception();
}
}
s2.Stop();
Console.WriteLine(((double)(s1.Elapsed.TotalMilliseconds * 1000000) / _max).ToString("0.00 ns"));
Console.WriteLine(((double)(s2.Elapsed.TotalMilliseconds * 1000000) / _max).ToString("0.00 ns"));
}
static void Method1(string test, out int result)
{
// Return value as an out parameter.
result = 0;
for (int i = 0; i < test.Length; i++)
{
result += 2;
}
}
static int Method2(string test)
{
// Return value with return statement.
int result = 0;
for (int i = 0; i < test.Length; i++)
{
result += 2;
}
return result;
}
}2.03 ns
1.25 ns
2.08 ns
1.25 ns
2.03 ns
1.25 ns
Averages:
2.05 ns Method, out
1.25 ns Method, return
Void. This keyword specifies that no specific value is returned from a method. We must use "void" in the method signature—this word was inherited from older C-like languages.
Expressions. You could specify if-statements to compute return values, but this approach is more verbose. Expressions can instead be used to condense high-level code.
Other returns. Many programs return string references of either constant form or newly-constructed strings. String is a reference type in the language that is special-cased by the runtime.
Tip Like all reference types, the string type is pushed to the stack and it is only 4 or 8 bytes on computers.
Important The string data is never copied when you assign a variable to the result of the method that returns a string.
Ret. This is the IL return instruction. Ret can be executed when there is one or zero items in the evaluation stack. The evaluation stack contains varying types of elements.
Note If the method returns one value, the evaluation stack should have one value of that type when the ret instruction is executed.
Ref return. We can return a ref to a struct or array element. This allows the returned value to be modified in a single statement. These changes are reflected in the current scope.
A summary. It is common to return values in methods. We discussed the concepts of "reachability" and endpoints, and how the execution engine processes ret instructions.
Dot Net Perls is a collection of tested code examples. Pages are continually updated to stay current, with code correctness a top priority.
Sam Allen is passionate about computer languages. In the past, his work has been recommended by Apple and Microsoft and he has studied computers at a selective university in the United States.
This page was last updated on Feb 19, 2023 (edit).