C # Создание Fluent API для методов цепочки - PullRequest
0 голосов
/ 08 февраля 2019

В C # мы можем использовать типы Func<> и Action<> для хранения того, что по сути является управляемыми указателями на методы.Однако, по моему опыту, они должны быть явно напечатаны при определении: Func<int> someFunc = myObject.MyMethod;

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

public int IntMethodA( value ) { return value * 2; }
public int IntMethodB( value ) { return value * 4; }
public double DoubleMethod( value ) { return value / 0.5; }

public double ChainMethod( value )
{
  return IntMethodA( value )
            .Then( IntMethodB )
            .Then( DoubleMethod );
}

Это то, что поддерживается классом .NET Task<>.Однако в целях обучения я пытаюсь разработать что-то подобное с нуля, и у меня остались несколько вопросов:

  1. IntMethodA возвращает целое число.Чтобы достичь чего-то подобного, мне, вероятно, потребуется написать метод расширения для Func<> вместе со всеми возможными общими перегрузками. Это означает, что мне нужно привести исходный метод как Func, а затем вернуть объект построителя, который может принимать последующие методы. Есть ли способ, которым я могу избежать этого начального приведения, чтобы сохранить завершенностьбеглость?

  2. Есть ли способ автоматизации или создания универсальных методов построения, которые принимают функции и добавляют их в цепочку?

Например,, рассмотрим:

public int IntMultiply( int a, int b ) { return a * b; }

public Tuple<double, double> Factor( int value )
{
  /* Some code that finds a set of two numbers that multiply to equal 'value' */
}

Эти два метода имеют разные сигнатуры и возвращаемые типы.Однако, если я хочу связать IntMultiply().Then( Factor );, это должно сработать, потому что ввод Factor имеет тот же тип, что и вывод IntMultiply.

Тем не менее, создается универсальный свободный API, который может сделать этокажется проблемой.Мне нужно было бы иметь возможность каким-то образом принимать возвращаемый тип IntMultiply и ограничивать любые дополнительные методы, чтобы принимать только этот тип в качестве входных данных.Это вообще возможно сделать?

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

Ответы [ 2 ]

0 голосов
/ 09 февраля 2019

Вы могли бы реализовать что-то вроде этого:

public class Fluent<TIn, TOut>
{
    private readonly TIn _value;
    private readonly Func<TIn, TOut> _func;

    public Fluent(TIn value, Func<TIn, TOut> func)
    {
        _value = value;
        _func = func;
    }

    public Fluent<TIn, TNewOut> Then<TNewOut>(Func<TOut, TNewOut> func) 
        => new Fluent<TIn, TNewOut>(_value, x => func(_func(x)));

    private TOut Calc() => _func(_value);

    public static implicit operator TOut(Fluent<TIn, TOut> self) => self.Calc();
}

, затем вы могли бы связать несколько методов один за другим и возвращать то, что вы хотите:

double f = new Fluent<int, int>(2, x => 2 * x)
    .Then(x => 4 * x)
    .Then(x => x / 0.5);
Tuple<double, double> t = new Fluent<int, int>(2, x => 2 * x)
    .Then(x => new Tuple<double, double>(x,x));

nb Вы также можете удалить перегруженный неявный оператор приведения и сделать метод Calc общедоступным.В этом случае вы можете использовать var, потому что не будет никакой двусмысленности между Fluent<TIn, TOut> и TOut.

0 голосов
/ 08 февраля 2019

Звучит так, будто вы хотите что-то вроде

public static TOut Then<TIn, TOut>(this TIn input, Func<TIn, TOut> func)
{
    return func(input);
}

Тогда это будет работать

var result = Multiply(1, 2).Then(Factor);

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

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