C# Методы
Метод — это блок кода, который организует набор связанных операторов вместе для выполнения конкретной задачи. Это реализация в C#повторного использования кодаиинкапсуляции логикиосновного механизма. Каждая программа на C# имеет по крайней мере одинMainМетод служит точкой входа в программу.
Использование метода требует двух шагов:Определение методаиВызов метода。
1. Определение методов
Базовый синтаксис определения метода в C# выглядит следующим образом:
<access modifier> <return type> <method name>(<parameter list>)
{
method body
}
Метод состоит из следующих элементов:
- Модификаторы доступа(Модификатор доступа): управляет видимостью метода, например
public、private、protected、internal。 - Тип возвращаемого значения(Тип возвращаемого значения): тип данных возвращаемого значения метода. Если метод не возвращает значение, используйте
void。 - имя метода(Имя метода): уникальный идентификатор метода, соответствующий соглашениям именования PascalCase (например,
FindMax、GetUserName)。 - Список параметров(Список параметров): входные данные, которые получает метод, заключенные в круглые скобки. Параметры необязательны; метод может не иметь параметров.
- тело метода(Тело метода): содержит код, реализующий функциональность, заключенный в фигурные скобки
{}Окружите.
На следующем рисунке показана полная структура метода:
1.1 Первый пример метода
Далее определяетсяFindMaxМетод, который принимает два целых числа и возвращает большее из них:
Пример
namespace MethodDemo
{
class NumberHelper
{
// Определите метод, который принимает два int и возвращает большее из них
public int FindMax(int num1, int num2)
{
if (num1 > num2)
return num1;
else
return num2;
}
static void Main(string[] args)
{
// Создать объект и вызвать метод
NumberHelper helper = new NumberHelper();
int result = helper.FindMax(100, 200);
Console.WriteLine($"Максимальное значение: {result}"); // Максимальное значение: 200
}
}
}
Процесс вызова метода:
Вызов из другого класса:Если метод объявлен как
public, то его можно вызвать из других классов, создав экземпляр. Это основа повторного использования кода в объектно-ориентированном программировании.
2. Способы передачи параметров
C# предоставляет три способа передачи параметров в методы. Их основное различие заключается втом, совместно ли используется память:
| Метод | Ключевые слова | Поведение | Типичные сценарии |
|---|---|---|---|
| Передача по значению | (нет) | Копирует значение параметра; изменения внутри метода не влияют на исходную переменную. | Большинство вызовов методов (по умолчанию) |
| Передача по ссылке | ref |
Передача ссылки на переменную; изменения внутри метода изменят исходную переменную. | Нужно изменять внешние переменные (например, обмен значениями) |
| Выходной параметр | out |
Похоже на ref, но метод должен присвоить значение, и переменную не нужно инициализировать перед вызовом. | Метод должен возвращать несколько значений |
2.1 Передача по значению (по умолчанию)
Передача по значению используется по умолчанию. Значение аргумента будетскопированои передано параметру; изменения параметра внутри метода не повлияют на исходную переменную:
Пример
namespace ParameterDemo
{
class Program
{
// Передача по значению: x и y — копии a и b
public void Swap(int x, int y)
{
int temp = x;
x = y;
y = temp;
Console.WriteLine($" Внутри метода: x={x}, y={y}"); // Обмен выполнен успешно
}
static void Main(string[] args)
{
var p = new Program();
int a = 100, b = 200;
Console.WriteLine($Перед вызовом: a={a}, b={b});
p.Swap(a, b);
Console.WriteLine($После вызова: a={a}, b={b}); // a, b не изменились!
}
}
}
调用前:a=100, b=200 方法内:x=200, y=100 调用后:a=100, b=200
2.2 Передача по ссылке (ref)
ИспользованиеrefКлючевое слово передаётссылкуна переменную (адрес в памяти); изменения параметра внутри метода напрямую повлияют на исходную переменную. Обратите внимание, что ключевое слово также нужно указать при вызове.ref:
Пример
namespace ParameterDemo
{
class Program
{
// Передача по ссылке: x и y напрямую ссылаются на память a、b
public void Swap(ref int x, ref int y)
{
int temp = x;
x = y;
y = temp;
}
static void Main(string[] args)
{
var p = new Program();
int a = 100, b = 200;
Console.WriteLine($Перед вызовом: a={a}, b={b});
p.Swap(ref a, ref b); // При вызове также нужно добавить ref
Console.WriteLine($После вызова: a={a}, b={b}); // Обмен выполнен успешно!
}
}
}
调用前:a=100, b=200 调用后:a=200, b=100
Разница между ref и out:
refТребует, чтобы переменная перед передачейбыла уже инициализирована;outТогда это не требуется, но внутри методаout-параметру должно быть присвоено значениепрежде чем его можно использовать.
2.3 Выходные параметры (out)
outПараметры позволяют методуВозвращать несколько значений. ИrefРазница в том, что переменную не нужно инициализировать перед вызовом, но метод должен присвоить ей значение:
Пример
namespace ParameterDemo
{
class Program
{
// out-параметр: метод отвечает за присваивание
public void GetValues(out int x, out int y)
{
Console.Write("Введите первое значение:");
x = Convert.ToInt32(Console.ReadLine());
Console.Write("Введите второе значение:");
y = Convert.ToInt32(Console.ReadLine());
// Примечание: Все out-параметры должны быть присвоены до завершения метода, иначе возникает ошибка компиляции.
}
// Практический пример: шаблон TryParse
public bool TryDivide(int a, int b, out double result)
{
if (b == 0)
{
result = 0;
return false; // Деление на ноль
}
result = (double)a / b;
return true;
}
static void Main(string[] args)
{
var p = new Program();
// параметры out не требуют инициализации
int a, b;
p.GetValues(out a, out b);
Console.WriteLine($"a={a}, b={b}");
// шаблон TryParse
if (p.TryDivide(10, 3, out double res))
Console.WriteLine($"10 / 3 = {res:F2}"); // 3.33
}
}
}
Начиная с C# 7.0, при вызове можно использоватьвстроенное объявлениеout-переменных, что делает код более кратким:
// C# 7.0+ 内联声明
if (int.TryParse("123", out int number))
Console.WriteLine($"解析成功:{number}");
3. Рекурсивные методы
Рекурсия — это методвызова самого себяКаждый рекурсивный метод требует двух элементов:
- Базовое условие(базовый случай): условие, которое завершает рекурсию, предотвращая бесконечную рекурсию.
- Рекурсивный шаг(рекурсивный шаг): разбивает задачу на более мелкие подзадачи.
Классический пример — вычисление факториала $$n! = n \times (n-1)!$$:
Пример
namespace RecursionDemo
{
class Program
{
// Рекурсивно вычислить факториал
public int Factorial(int n)
{
// Базовое условие: 0! = 1, 1! = 1
if (n <= 1)
return 1;
// Рекурсивный шаг: n! = n × (n-1)!
return n * Factorial(n - 1);
}
static void Main(string[] args)
{
var p = new Program();
Console.WriteLine($"6! = {p.Factorial(6)}"); // 720
Console.WriteLine($"7! = {p.Factorial(7)}"); // 5040
Console.WriteLine($"8! = {p.Factorial(8)}"); // 40320
}
}
}
6! = 720 7! = 5040 8! = 40320
Процесс развёртывания рекурсивных вызовов:
Factorial(4) = 4 × Factorial(3) = 4 × 3 × Factorial(2) = 4 × 3 × 2 × Factorial(1) = 4 × 3 × 2 × 1 = 24
Примечание:Когда глубина рекурсии слишком велика, это может вызвать
StackOverflowExceptionДля сценариев, чувствительных к производительности, рассмотрите использование цикла вместо этого.
4. Дополнительные возможности методов
4.1 Параметры по умолчанию и именованные параметры
C# позволяет задавать параметрамзначение по умолчанию, их можно опускать при вызове. В сочетании сименованными параметрамиможно также пропустить некоторые параметры и указать только следующие за ними:
Пример
namespace MethodFeatures
{
class Program
{
// Параметр по умолчанию: power по умолчанию равен 2
static double Power(double baseNum, int степень = 2)
{
double result = 1;
for (int i = 0; i < power; i++)
result *= baseNum;
return result;
}
// Несколько параметров по умолчанию
static void PrintInfo(string name, int age = 18, string city = "Unknown")
{
Console.WriteLine($"{name}, {age} years old, {city}");
}
static void Main(string[] args)
{
// Использование параметров по умолчанию
Console.WriteLine(Power(3)); // 9.0 (используется power=2 по умолчанию)
Console.WriteLine(Power(3, 3)); // 27.0
// Именованные аргументы: пропустить age, указать только city
PrintInfo(Xiaoming, city: "Beijing");
// Вывод: Xiaoming, 18 лет, Beijing
// Именованные аргументы могут быть в любом порядке
PrintInfo(city: "Shanghai", name: Xiaohong, age: 25);
// Вывод: Сяохун, 25 лет, Шанхай
}
}
}
4.2 Методы с телом-выражением
Когда тело метода содержит только один оператор, можно использовать=>Упрощённый синтаксис (C# 6.0+):
// 传统写法
public int Add(int a, int b)
{
return a + b;
}
// 表达式体写法(等价)
public int Add(int a, int b) => a + b;
4.3 Перегрузка методов (Overloading)
В одном и том же классе может бытьнесколько методов с одинаковым именем, если списки параметров различаются (разные типы, количество или порядок параметров):
Пример
namespace MethodFeatures
{
class Calculator
{
// Перегрузка 1: Add для двух int
public int Add(int a, int b) => a + b;
// Перегрузка 2: Add для трёх int
public int Add(int a, int b, int c) => a + b + c;
// Перегрузка 3: Add для двух double
public double Add(double a, double b) => a + b;
static void Main(string[] args)
{
var calc = new Calculator();
Console.WriteLine(calc.Add(1, 2)); // 3 (вызов перегрузки 1)
Console.WriteLine(calc.Add(1, 2, 3)); // 6 (вызов перегрузки 2)
Console.WriteLine(calc.Add(1.5, 2.5)); // 4.0 (вызов перегрузки 3)
}
}
}
Итог
| Особенности | Синтаксис | Описание |
|---|---|---|
| Определите метод | int Add(int a, int b) { ... } |
Укажите тип возвращаемого значения, имя метода и параметры |
| Нет возвращаемого значения | void DoSomething() { ... } |
voidУказывает, что значение не возвращается |
| Передача по значению | void Foo(int x) |
Метод по умолчанию; изменения параметров не влияют на аргументы |
| Передача по ссылке | void Foo(ref int x) |
Общая память; изменения отражаются в аргументах |
| Выходной параметр | void Foo(out int x) |
Должен быть присвоен внутри метода; может возвращать несколько значений |
| Параметр по умолчанию | void Foo(int x = 10) |
Можно опустить при вызове; используются значения по умолчанию |
| Именованные параметры | Foo(city: "北京") |
Указывайте параметры по имени, порядок можно изменить |
| Тело выражения | int Add(int a, int b) => a + b; |
Сокращённая запись для однострочных методов (C# 6.0+) |
| Перегрузка методов | Одинаковое имя, разные параметры | Компилятор автоматически выбирает на основе списка параметров |