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

Что такое ссылочные типы?

1.0 Junior🔥 221 комментариев
#Основы C# и .NET

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

🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)

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

Что такое ссылочные типы?

Ссылочные типы — это типы данных в C#, которые хранят адрес памяти (ссылку) на объект, а не сами данные. Переменная ссылочного типа содержит указатель на область в управляемой памяти (heap), где находится реальный объект.

Отличие от значимых типов

// Значимый тип (struct, int, bool, etc.)
int a = 5;
int b = a;  // копируется VALUE: b = 5
a = 10;     // a меняется, b остаётся 5

Console.WriteLine($"a={a}, b={b}");  // a=10, b=5

// Ссылочный тип (class, string, array, delegate)
class Person
{
    public string Name { get; set; }
}

var person1 = new Person { Name = "Alice" };
var person2 = person1;  // копируется ССЫЛКА, не объект!

person1.Name = "Bob";
Console.WriteLine(person2.Name);  // Bob! (один и тот же объект)

Основные ссылочные типы в C#

  1. class — пользовательские классы
  2. string — строки (неизменяемый ссылочный тип)
  3. array — массивы
  4. interface — интерфейсы
  5. delegate — делегаты/функции
  6. object — базовый тип всех объектов
  7. dynamic — динамически типизированный тип

Размещение в памяти

public class Book
{
    public string Title { get; set; }
    public int Pages { get; set; }
}

static void Main()
{
    // Переменная book находится НА СТЕКЕ
    // Сам объект находится НА КУЧЕ (heap)
    Book book = new Book { Title = "C# Book", Pages = 500 };
    
    //  СТЕК             КУЧА
    //  book ────────→ [Book объект]
    //                 Title = "C# Book"
    //                 Pages = 500
}

На стеке: только переменная (4 или 8 байт — адрес) На куче: весь объект со всеми полями

Поведение при передаче в методы

public class Counter
{
    public int Value { get; set; }
}

static void ModifyReference(Counter counter)
{
    counter.Value = 100;  // изменяем сам объект
    counter = new Counter { Value = 999 };  // создаём новый объект
}

static void Main()
{
    var c = new Counter { Value = 10 };
    ModifyReference(c);
    
    Console.WriteLine(c.Value);  // 100, не 999!
    // Почему? Ссылка скопирована, но внутри метода создана новая переменная
}

Важно: когда ты передаёшь ссылочный тип, передаётся копия ссылки, а не сама ссылка. Поэтому переопределение ссылки внутри метода не влияет на исходную переменную.

null и ссылочные типы

Person person = null;  // допустимо

if (person != null)
{
    Console.WriteLine(person.Name);  // NullReferenceException если проверку пропустить
}

// С nullable reference types (C# 8.0+)
Person? nullablePerson = null;  // явно nullable

Сравнение ссылочных типов

var p1 = new Person { Name = "Alice" };
var p2 = new Person { Name = "Alice" };
var p3 = p1;

Console.WriteLine(p1 == p2);  // false (разные объекты в памяти)
Console.WriteLine(p1 == p3);  // true (одна ссылка)
Console.WriteLine(ReferenceEquals(p1, p2));  // false
Console.WriteLine(ReferenceEquals(p1, p3));  // true

Для сравнения содержимого переопредели Equals() и GetHashCode():

public class Person
{
    public string Name { get; set; }
    
    public override bool Equals(object obj)
    {
        return obj is Person p && p.Name == Name;
    }
    
    public override int GetHashCode() => Name.GetHashCode();
}

var p1 = new Person { Name = "Alice" };
var p2 = new Person { Name = "Alice" };

Console.WriteLine(p1 == p2);      // false (по ссылке)
Console.WriteLine(p1.Equals(p2)); // true (по содержимому)

Производительность

  • Ссылочные типы медленнее — требуют кучу и сборку мусора
  • Значимые типы быстрее — размещаются на стеке
  • Используй struct для малых, часто копируемых данных
  • Используй class для больших объектов с поведением