Как передать метод в качестве параметра другому методу в C#?
Использование делегатов для передачи методов
В C# для передачи методов в качестве параметров используются делегаты. Это типобезопасные указатели на методы. Делегат определяет сигнатуру (возвращаемый тип и параметры) метода, который он может хранить.
В вашем случае, где метод принимает int и возвращает int, нужно объявить соответствующий делегат. Вот как это сделать:
1. Объявление делегата
Вы можете объявить свой собственный делегат или использовать встроенные:
// Собственный делегат
public delegate int IntOperation(int x);
// Встроенный делегат (рекомендуемый способ)
// Func<int, int> — принимает int, возвращает int
2. Реализация метода с делегатом
public void ProcessArray(int[] numbers, Func<int, int> operation)
{
for (int i = 0; i < numbers.Length; i++)
{
numbers[i] = operation(numbers[i]);
}
}
3. Использование
Теперь вы можете передавать разные методы:
// Методы, которые будем передавать
int Square(int x) => x * x;
int Double(int x) => x * 2;
int Increment(int x) => x + 1;
// Использование
int[] numbers = { 1, 2, 3, 4 };
ProcessArray(numbers, Square); // {1, 4, 9, 16}
ProcessArray(numbers, Double); // {2, 4, 6, 8}
ProcessArray(numbers, Increment); // {2, 3, 4, 5}
4. Лямбда-выражения (ещё проще)
В современном C# вы можете передавать методы "на лету" с помощью лямбда-выражений:
ProcessArray(numbers, x => x * x); // анонимная функция
ProcessArray(numbers, x => x + 10);
5. Передача методов с разным количеством параметров
Если метод принимает больше параметров, используйте соответствующие версии Func<> или Action<>:
Func<T1, T2, TResult>— метод с двумя параметрамиAction<T>— метод, который ничего не возвращает (void)Predicate<T>— метод, возвращающий bool
Пример с двумя параметрами:
public void ProcessWithIndex(int[] numbers, Func<int, int, int> operation)
{
for (int i = 0; i < numbers.Length; i++)
{
numbers[i] = operation(numbers[i], i);
}
}
// Использование
ProcessWithIndex(numbers, (value, index) => value + index);
6. Полный пример с разными операциями
using System;
class Program
{
static void Main()
{
int[] data = { 5, 10, 15 };
// Передача именованного метода
ProcessArray(data, MultiplyByTwo);
// Передача лямбды
ProcessArray(data, x => x / 2);
// Использование Action для void-методов
PrintArray(data, x => Console.WriteLine(x));
}
static int MultiplyByTwo(int x) => x * 2;
static void ProcessArray(int[] arr, Func<int, int> op)
{
for (int i = 0; i < arr.Length; i++)
arr[i] = op(arr[i]);
}
static void PrintArray(int[] arr, Action<int> printer)
{
foreach (var item in arr)
printer(item);
}
}
Важно: Всегда используйте встроенные делегаты Func<> (для методов с возвращаемым значением) и Action<> (для void-методов), если нет особой необходимости в кастомных делегатах. Это делает код более читаемым и стандартным.
Альтернативный подход: интерфейсы и стратегия
Хотя делегаты — самый популярный способ, в некоторых архитектурах (например, при работе с Dependency Injection или сложной бизнес-логикой) удобнее использовать паттерн "Стратегия" с интерфейсом.
public interface IOperation
{
int Apply(int x);
}
public class SquareOperation : IOperation
{
public int Apply(int x) => x * x;
}
public class DoubleOperation : IOperation
{
public int Apply(int x) => x * 2;
}
public class Processor
{
public void Process(int[] numbers, IOperation operation)
{
for (int i = 0; i < numbers.Length; i++)
{
numbers[i] = operation.Apply(numbers[i]);
}
}
}
// Использование
var processor = new Processor();
int[] data = { 1, 2, 3 };
processor.Process(data, new SquareOperation()); // {1, 4, 9}
processor.Process(data, new DoubleOperation()); // {2, 4, 6}
Когда это лучше делегатов?
- Когда операция требует дополнительного состояния (поля класса).
- Когда операция сложная и её логику нужно тестировать отдельно.
- Когда вы работаете с DI-контейнерами, где удобнее регистрировать интерфейсы.
Однако для простых случаев делегаты и лямбды остаются более лаконичным и идиоматичным для C# решением. Выбирайте подход под задачу: для быстрых фильтров/трансформаций — делегаты, для сложных алгоритмов — интерфейсы.