Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Виды делегатов в C#
Делегат — это типобезопасный указатель на функцию. Это один из краеугольных камней C# и позволяет передавать методы как параметры, реализовывать callback-и и события.
Основные концепции
1. Простые делегаты (Delegate)
Пользовательский делегат определяет сигнатуру метода:
// Определение делегата
public delegate void OnPlayerDeath(Player player);
public delegate int MathOperation(int a, int b);
public delegate string TextProcessor(string text);
public class GameManager : MonoBehaviour
{
// Экземпляр делегата
private OnPlayerDeath deathCallback;
private void Start()
{
// Присвоение метода делегату
deathCallback = PlayerDeadHandler;
deathCallback += LogDeath; // Добавление ещё одного метода
// Вызов делегата (вызывает все добавленные методы)
Player player = new Player();
deathCallback?.Invoke(player);
}
private void PlayerDeadHandler(Player player)
{
Debug.Log($"{player.name} is dead!");
}
private void LogDeath(Player player)
{
Debug.Log($"Logging death of {player.name}");
}
}
2. Action (встроенный делегат)
Action — это предопределённый делегат для методов, которые ничего не возвращают:
public class InputHandler : MonoBehaviour
{
// Action без параметров
public Action OnJumpPressed;
// Action с параметрами
public Action<string> OnPlayerDamaged;
public Action<int, Vector3> OnDamage;
private void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
OnJumpPressed?.Invoke(); // Вызов
}
if (Input.GetKeyDown(KeyCode.E))
{
OnPlayerDamaged?.Invoke("Fire");
OnDamage?.Invoke(10, transform.position);
}
}
}
// Использование
public class Player : MonoBehaviour
{
private void Start()
{
InputHandler input = GetComponent<InputHandler>();
input.OnJumpPressed += Jump;
input.OnPlayerDamaged += TakeDamage;
input.OnDamage += ApplyDamage;
}
private void Jump() => GetComponent<Rigidbody>().velocity += Vector3.up * 5f;
private void TakeDamage(string damageType) => Debug.Log($"Took {damageType} damage");
private void ApplyDamage(int amount, Vector3 position) => Debug.Log($"Damage: {amount} at {position}");
}
3. Func (делегат с возвращаемым значением)
Func используется для методов, которые возвращают значение:
public class Calculator : MonoBehaviour
{
// Func<параметры..., возвращаемый тип>
public Func<int, int, int> Operation;
public void Initialize()
{
// Присвоение методов
Operation = Add;
int result1 = Operation(5, 3); // 8
Operation = Multiply;
int result2 = Operation(5, 3); // 15
// Lambda выражение
Operation = (a, b) => a * a + b * b;
int result3 = Operation(3, 4); // 25
}
private int Add(int a, int b) => a + b;
private int Multiply(int a, int b) => a * b;
}
// Другие примеры Func
public class DataProcessor
{
private Func<string, int> StringToLength; // Один параметр
private Func<Player, bool> IsPlayerAlive; // Пользовательский тип
private Func<Vector3, Vector3, float> Distance; // Два параметра
private void Setup()
{
StringToLength = str => str.Length;
IsPlayerAlive = player => player.Health > 0;
Distance = (a, b) => Vector3.Distance(a, b);
}
}
4. Предикат (Predicate)
Predicate<T> — специальный Func, который возвращает bool (используется для фильтрации):
public class EnemyManager : MonoBehaviour
{
private List<Enemy> enemies = new List<Enemy>();
public void Setup()
{
// Predicate для фильтрации
Predicate<Enemy> isAlive = enemy => enemy.Health > 0;
Predicate<Enemy> isNearPlayer = enemy => Vector3.Distance(enemy.transform.position, transform.position) < 10f;
// Использование с List
List<Enemy> aliveEnemies = enemies.FindAll(isAlive);
List<Enemy> nearEnemies = enemies.FindAll(isNearPlayer);
// Или прямо
Enemy target = enemies.Find(e => e.Health > 0 && e.Level >= 5);
}
}
5. События (Event)
Event — это обёртка над делегатом для контролируемой подписки:
public class Player : MonoBehaviour
{
// Event с делегатом
public delegate void OnHealthChanged(float newHealth);
public event OnHealthChanged HealthChanged;
private float health = 100f;
public void TakeDamage(float damage)
{
health -= damage;
HealthChanged?.Invoke(health); // Вызов события
}
}
// Подписка на событие
public class HealthBar : MonoBehaviour
{
private void Start()
{
Player player = FindObjectOfType<Player>();
player.HealthChanged += UpdateHealthUI; // Подписка
}
private void UpdateHealthUI(float health)
{
Debug.Log($"Health: {health}");
}
}
Сравнение делегатов
Делегат vs Action:
// Делегат (пользовательский)
public delegate void MyDelegate(int value);
private MyDelegate callback; // Явное объявление
// Action (встроенный, проще)
private Action<int> callback; // Быстрее писать
Action vs Func:
// Action — ничего не возвращает
Action<int> logValue = x => Debug.Log(x);
// Func — возвращает значение
Func<int, int> square = x => x * x; // Возвращает int
int result = square(5); // 25
Лямбда выражения с делегатами
public class LambdaExamples : MonoBehaviour
{
private void Start()
{
// Без параметров
Action greet = () => Debug.Log("Hello!");
greet(); // Hello!
// Один параметр
Action<string> sayName = name => Debug.Log($"My name is {name}");
sayName("Alice"); // My name is Alice
// Несколько параметров
Func<int, int, int> add = (a, b) => a + b;
int sum = add(5, 3); // 8
// Многострочная лямбда
Action<int> calculate = x =>
{
int square = x * x;
int cube = x * x * x;
Debug.Log($"Square: {square}, Cube: {cube}");
};
calculate(3); // Square: 9, Cube: 27
}
}
Практический пример: система команд
public class CommandSystem : MonoBehaviour
{
// Хранилище команд
private Dictionary<string, Action> commands = new Dictionary<string, Action>();
private Dictionary<string, Func<string, string>> queries = new Dictionary<string, Func<string, string>>();
public void RegisterCommand(string name, Action command)
{
commands[name] = command;
}
public void RegisterQuery(string name, Func<string, string> query)
{
queries[name] = query;
}
public void ExecuteCommand(string name)
{
if (commands.TryGetValue(name, out Action command))
{
command.Invoke();
}
}
public string ExecuteQuery(string name, string param)
{
if (queries.TryGetValue(name, out Func<string, string> query))
{
return query.Invoke(param);
}
return null;
}
}
Итоги
| Тип | Назначение | Возврат | Пример |
|---|---|---|---|
| Delegate | Пользовательский указатель | Любой | delegate void MyDel(); |
| Action | Метод без возврата | void | Action<int> log = x => Debug.Log(x); |
| Func | Метод с возвратом | T | Func<int, int> square = x => x * x; |
| Predicate | Фильтрация (bool) | bool | Predicate<T> check = x => x > 0; |
| Event | Подписка на события | Зависит | event Action OnEvent; |
Делегаты — это основа для построения гибких и расширяемых систем в Unity!