← Назад к вопросам

В чём разница между передачей объектов разных типов в методы?

2.0 Middle🔥 201 комментариев
#Основы C# и .NET

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Разница между передачей объектов разных типов в методы в C#

В C# при передаче объектов в методы ключевое отличие заключается в том, как передаётся сам объект и его данные — по значению или по ссылке. Это напрямую зависит от типа параметра (значимый тип или ссылочный тип) и от способа передачи (по значению или по ссылке с использованием модификаторов). Разберём основные сценарии.

1. Передача значимых типов (Value Types) по значению

Значимые типы (int, double, struct, enum и т.д.) хранят данные непосредственно в своём экземпляре. При передаче в метод по значению (без модификаторов) создается полная копия данных. Изменения внутри метода не затрагивают оригинальный объект.

public void ModifyValue(int number) {
    number = 10; // Изменяется локальная копия
}

int original = 5;
ModifyValue(original);
Console.WriteLine(original); // Вывод: 5 (оригинал не изменён)

2. Передача ссылочных типов (Reference Types) по значению

Ссылочные типы (class, string, array, interface и т.д.) хранят данные в heap, а переменная содержит ссылку на эти данные. При передаче в метод по значению копируется сама ссылка, но не данные в heap. Таким образом, метод работает с тем же объектом в памяти, что и вызывающий код.

public void ModifyReference(List<int> list) {
    list.Add(100); // Изменяет оригинальный список
}

List<int> originalList = new List<int> { 1, 2 };
ModifyReference(originalList);
Console.WriteLine(originalList.Count); // Вывод: 3 (оригинал изменён)

Однако, если внутри метода мы присваиваем параметру новый объект, это изменение не отражается на оригинальной переменной вне метода, потому что мы меняем локальную копию ссылки.

public void ReassignReference(List<int> list) {
    list = new List<int> { 10, 20 }; // Локальная ссылка теперь указывает на новый объект
}

List<int> myList = new List<int> { 1, 2 };
ReassignReference(myList);
Console.WriteLine(myList.Count); // Вывод: 2 (оригинал не переприсвоен)

3. Передача параметров по ссылке с модификаторами ref и out

Модификаторы ref и out позволяют передавать параметры по ссылке, то методу передаётся сама исходная переменная (или ссылка на ссылочный тип), а не её копия.

  • ref: параметр должен быть инициализирован перед передачей. Метод может читать и изменять его, изменения отражаются на оригинале.
  • out: параметр не требует инициализации перед передачей, но метод обязан присвоить ему значение перед возвратом.
public void ModifyWithRef(ref int number) {
    number = 10; // Изменяет оригинальную переменную
}

int original = 5;
ModifyWithRef(ref original);
Console.WriteLine(original); // Вывод: 10

public void InitializeWithOut(out List<int> list) {
    list = new List<int> { 7, 8 }; // Обязательное присваивание
}

List<int> myList;
InitializeWithOut(out myList);
Console.WriteLine(myList.Count); // Вывод: 2

Для ссылочных типов ref позволяет менять не только содержимое объекта, но и саму ссылку (переприсваивать переменную).

public void ReassignRef(ref List<int> list) {
    list = new List<int> { 99 }; // Изменяется оригинальная ссылка
}

List<int> myList = new List<int> { 1 };
ReassignRef(ref myList);
Console.WriteLine(myList[0]); // Вывод: 99

4. Модификатор in для передачи по ссылке только для чтения

Модификатор in, появившийся в C# 7.2, передаёт параметр по ссылке, но запрещает его изменение внутри метода (для значимых типов это предотвращает копирование, для ссылочных — гарантирует, что ссылка не будет переприсвоена).

public void ProcessLargeStruct(in MyLargeStruct data) {
    // Можно читать data, но не изменять
    var value = data.Field;
}

MyLargeStruct bigStruct = new MyLargeStruct();
ProcessLargeStruct(in bigStruct);

Сравнительная таблица поведения

Тип параметраСпособ передачиЧто передаётся?Можно изменять объект?Можно переприсвоить ссылку?
Значимый типПо значениюКопия данныхНет (локальная копия)Нет
Значимый типref / outСсылка на переменнуюДа (оригинал)Да (саму переменную)
Ссылочный типПо значениюКопия ссылкиДа (объект в heap)Нет (локальная ссылка)
Ссылочный типref / outСсылка на ссылкуДа (объект в heap)Да (оригинальную ссылку)
Любой типinСсылка для чтенияНет (только чтение)Нет

Практические рекомендации

  • Используйте передачу по значению для значимых типов, когда изменения не требуются, чтобы избежать непреднамеренных изменений.
  • Для ссылочных типов передача по значению эффективна, так как копируется только ссылка (не весь объект).
  • Применяйте ref и out осторожно, они могут усложнить понимание кода и привести к ошибкам, если используются чрезмерно.
  • Модификатор in полезен для оптимизации при передаче больших структур (struct), чтобы избежать дорогостоящего копирования.

Понимание этих различий критично для написания корректного, эффективного и безопасного кода на C#, особенно в контексте многопоточности и работы с большими данными.

В чём разница между передачей объектов разных типов в методы? | PrepBro