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

Что такое делегаты?

1.0 Junior🔥 211 комментариев
#C# и ООП

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

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

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

Делегаты в C#

Делегат это типобезопасная ссылка на метод. Это позволяет передавать методы как параметры, сохранять их в переменных и вызывать их позже. Делегаты это основа для событий, коллбеков и функционального программирования в C#.

Базовое понимание

Что такое делегат?

Делегат это класс, который может хранить ссылку на метод с определённой сигнатурой.

// Объявляем делегат
public delegate void MyCallback(string message);

// Метод с совместимой сигнатурой
public void PrintMessage(string message) {
    Debug.Log(message);
}

// Создаём переменную делегата и присваиваем метод
MyCallback callback = PrintMessage;

// Вызываем делегат
callback("Привет"); // Выведет: Привет

Зачем нужны делегаты?

1. Передача методов как параметров

public delegate void ProcessAction(int value);

public class DataProcessor {
    public void ProcessData(int[] data, ProcessAction action) {
        foreach (var item in data) {
            action(item); // Вызываем переданный метод
        }
    }
}

// Использование
var processor = new DataProcessor();
int[] numbers = { 1, 2, 3, 4, 5 };

processor.ProcessData(numbers, (x) => Debug.Log("Число: " + x));
processor.ProcessData(numbers, (x) => Debug.Log("Квадрат: " + (x * x)));

2. Асинхронные операции и коллбеки

public delegate void OperationComplete(bool success);

public class NetworkManager {
    public void FetchData(string url, OperationComplete onComplete) {
        StartCoroutine(FetchDataCoroutine(url, onComplete));
    }
    
    private IEnumerator FetchDataCoroutine(string url, OperationComplete onComplete) {
        using (var www = new WWW(url)) {
            yield return www;
            onComplete(www.error == null); // Коллбек когда готово
        }
    }
}

// Использование
var network = new NetworkManager();
network.FetchData("https://api.example.com", (success) => {
    if (success) {
        Debug.Log("Данные загружены");
    } else {
        Debug.Log("Ошибка загрузки");
    }
});

Встроенные делегаты

Action — делегат без возвращаемого значения

// Action с параметром
Action<string> printAction = (message) => Debug.Log(message);
printAction("Hello");

// Action с несколькими параметрами
Action<int, int> addAction = (a, b) => Debug.Log(a + b);
addAction(5, 3); // Выведет: 8

// Action без параметров
Action greet = () => Debug.Log("Привет!");
greet();

Func — делегат с возвращаемым значением

// Func<параметры, возвращаемый тип>
Func<int, int, int> multiply = (a, b) => a * b;
int result = multiply(4, 5); // result = 20

Func<string, bool> isLong = (text) => text.Length > 5;
bool check = isLong("Hello World"); // true

События (Events)

События это безопасная обёртка над делегатами. Позволяют подписываться и отписываться.

public class Enemy {
    // Делегат для события
    public delegate void DeathEventHandler(Enemy enemy);
    
    // Событие на основе делегата
    public event DeathEventHandler OnDeath;
    
    public void Die() {
        Debug.Log("Enemy died");
        OnDeath?.Invoke(this); // Вызываем всех подписчиков
    }
}

// Использование
var enemy = new Enemy();
enemy.OnDeath += (deadEnemy) => Debug.Log("Враг повержен!");
enemy.OnDeath += (deadEnemy) => DropLoot();
enemy.Die(); // Выведет обе подписки

// Отписка
enemy.OnDeath -= (deadEnemy) => Debug.Log("Враг повержен!");

Практические примеры

1. Система событий игры

public class GameEvents {
    public static event Action<int> OnScoreChanged;
    public static event Action<float> OnHealthChanged;
    public static event Action OnGameOver;
    
    public static void RaiseScoreChanged(int newScore) {
        OnScoreChanged?.Invoke(newScore);
    }
    
    public static void RaiseHealthChanged(float health) {
        OnHealthChanged?.Invoke(health);
    }
    
    public static void RaiseGameOver() {
        OnGameOver?.Invoke();
    }
}

// Подписка
public class UI : MonoBehaviour {
    private void OnEnable() {
        GameEvents.OnScoreChanged += UpdateScoreDisplay;
        GameEvents.OnHealthChanged += UpdateHealthBar;
    }
    
    private void OnDisable() {
        GameEvents.OnScoreChanged -= UpdateScoreDisplay;
        GameEvents.OnHealthChanged -= UpdateHealthBar;
    }
    
    private void UpdateScoreDisplay(int score) {
        scoreText.text = "Score: " + score;
    }
    
    private void UpdateHealthBar(float health) {
        healthBar.value = health;
    }
}

2. Система обработки урона

public delegate void DamageHandler(int damage, Vector3 position);

public class Character {
    public event DamageHandler OnTakeDamage;
    private int health = 100;
    
    public void TakeDamage(int damage, Vector3 position) {
        health -= damage;
        OnTakeDamage?.Invoke(damage, position);
    }
}

public class ParticleEffects : MonoBehaviour {
    public void PlayDamageEffect(int damage, Vector3 position) {
        Instantiate(damageParticle, position, Quaternion.identity);
    }
}

public class AudioManager : MonoBehaviour {
    public void PlayDamageSound(int damage, Vector3 position) {
        AudioSource.PlayClipAtPoint(damageSound, position);
    }
}

// Подключение к событиям
var character = GetComponent<Character>();
character.OnTakeDamage += particles.PlayDamageEffect;
character.OnTakeDamage += audioManager.PlayDamageSound;

3. Функции высокого порядка (Higher-Order Functions)

public class CollectionUtils {
    public static List<T> Filter<T>(List<T> items, Func<T, bool> predicate) {
        var result = new List<T>();
        foreach (var item in items) {
            if (predicate(item)) {
                result.Add(item);
            }
        }
        return result;
    }
    
    public static List<U> Map<T, U>(List<T> items, Func<T, U> transform) {
        var result = new List<U>();
        foreach (var item in items) {
            result.Add(transform(item));
        }
        return result;
    }
}

// Использование
var numbers = new List<int> { 1, 2, 3, 4, 5 };
var evenNumbers = CollectionUtils.Filter(numbers, (x) => x % 2 == 0);
var doubled = CollectionUtils.Map(numbers, (x) => x * 2);

Многие делегаты (Multicast Delegates)

public delegate void Callback();

Callback callback = null;
callback += () => Debug.Log("1");
callback += () => Debug.Log("2");
callback += () => Debug.Log("3");

callback?.Invoke();
// Выведет:
// 1
// 2
// 3

Выводы

  • Делегат это типобезопасная ссылка на метод
  • Action для методов без результата
  • Func для методов с результатом
  • События это безопасная обёртка над делегатами
  • Используй делегаты для архитектуры на основе событий
  • Всегда отписывайся от событий в OnDisable() чтобы избежать утечек памяти
  • Делегаты это основа для асинхронного кода и коллбеков в Unity
Что такое делегаты? | PrepBro