Можете ли вы связать результат одного делегата для ввода другого в C #? - PullRequest
3 голосов
/ 04 января 2012

Я ищу способ связать несколько делегатов, чтобы результат одного стал входом следующего.Я пытаюсь использовать это в программе решения уравнений, где порции делаются разными методами.Идея состоит в том, что когда вы строите уравнение, программа добавляет делегатов и объединяет их в определенном порядке, чтобы его можно было правильно решить.Если есть лучший способ решения проблемы, пожалуйста, поделитесь.

Ответы [ 5 ]

7 голосов
/ 04 января 2012

Это может помочь:

public static Func<T1, TResult> Compose<T1, T2, TResult>(Func<T1, T2> innerFunc, Func<T2, TResult> outerFunc) {
    return arg => outerFunc(innerFunc(arg));
}

Выполняет композицию функций , запускает innerFunc и передает результат в outerFunc, когда указан начальный аргумент:

Func<double, double> floor = Math.Floor;
Func<double, int> convertToInt = Convert.ToInt32;

Func<double, int> floorAndConvertToInt = Compose(floor, convertToInt);

int result = floorAndConvertToInt(5.62);

Func<double, int> floorThenConvertThenAddTen = Compose(floorAndConvertToInt, i => i + 10);

int result2 = floorThenConvertThenAddTen(64.142);
3 голосов
/ 04 января 2012

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

Многие LINQ построены таким образом, хотя вы можетехочу взглянуть на выражения .

0 голосов
/ 29 ноября 2012

Я сам работал над аналогичной проблемой, которая включала в себя последовательность делегатов и передачу вывода одного делегата следующему (и так далее ...), так что я подумал, что вас может заинтересоватьсм. код, который я разработал в качестве подтверждения концепции:

static class Program
{
    private static IList<Func<int, int>> delegateList = 
        new List<Func<int, int>>()
    {
        AddOne, AddOne, AddOne, AddOne, AddOne,
        AddOne, AddOne, AddOne, AddOne, AddOne,
    };

    static void Main(string[] args)
    {
        int number = 12;

        Console.WriteLine("Starting number: {0}", number);
        Console.WriteLine("Ending number: {0}", 
                          delegateList.InvokeChainDelegates(number));
        Console.ReadLine();
    }

    public static int AddOne(int num) { return num + 1; }

    public static T InvokeChainDelegates<T>(this IEnumerable<Func<T, T>> source, 
                                            T startValue)
    {
        T result = startValue;

        foreach (Func<T, T> function in source)
        {
            result = function(result);
        }

        return result;
    }
}

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

0 голосов
/ 04 января 2012

с помощью GetInvocationlist вы можете добиться этого.

 Delegate[] chain = chained.GetInvocationList();

        int res = 10;
        for( int i = 0; i < chain.Length; i++ ) 
          {
              //Call chain[i]
                res =  chain[i](res);
          }
0 голосов
/ 04 января 2012

Тип API, который вы описываете, называется Свободный API .Взгляните на предыдущую статью для хорошего учебника.

Что касается цепочки делегатов, взгляните на методы расширения LINQ в .NET 3.5, в частности, как лямбда-функции (делегаты), передаваемые в функцию, приводят к результату IEnumerable, который затем может быть связан с другим расширением.method + lambda.

В вашем конкретном случае вам может потребоваться создать класс под названием Functor, чтобы принимать делегат и возвращать другой Functor, который также может использоваться делегатами.

С уважением,

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...