Могу ли я иметь C# с функциональным стилем и внедрением зависимости? - PullRequest
0 голосов
/ 27 января 2020

Я хочу иметь несколько классов, которые предоставляют метод с

(а) с тем же именем, но с разными реализациями;

(б) Я также хочу, чтобы методы использовались в функционале / linq-extension style в C #;

(c) Я хочу объединить эти классы с другими с помощью внедрения зависимостей.

Кажется, что это невозможно, потому что stati c classes, требование (b) в C# не может реализовывать интерфейсы, необходимые для (a) или вводиться с использованием инжектора конструктора.

Я хотел бы иметь:

interface IAlgorithm { double MyFuncStyleMethod(double arg); }

public static class ClassAWithMyExtensionMethods : IAlgorithm
{
  public static double MyFuncStyleMethod(this arg1) { ... }
}

public static class ClassBWithMyExtensionMethods : IAlgorithm
{
  public static double MyFuncStyleMethod(this arg1) { ... }
}

private readonly IAlgorithm _service;
public class MyComposedClass(IAlgorithm service)
{
  _service = service; 
}
...
public double UseMethod(double x)
{
  // want to avoid awkward syntax _service.MyFuncStyleMethod(x);
  double answer = x.MyFuncStyleMethod();
}

Есть ли Как я могу получить все эти преимущества?

1 Ответ

1 голос
/ 05 февраля 2020

Да, вы можете. DI в функциональном мире делается с монадой Reader. Вот простая реализация

public delegate A Reader<A>(IAlgorithm env);

public static class Reader
{
    public static Reader<A> Pure<A>(A value) =>
        _ => value;

    public static Reader<B> Bind<A, B>(this Reader<A> ma, Func<A, Reader<B>> f) => env =>
        f(ma(env))(env);

    public static Reader<B> Map<A, B>(this Reader<A> ma, Func<A, B> f) =>
        Bind(ma, a => Pure(f(a)));

    public static Reader<B> Select<A, B>(this Reader<A> ma, Func<A, B> f) =>
        Map(ma, f);

    public static Reader<C> SelectMany<A, B, C>(this Reader<A> ma, Func<A, Reader<B>> bind, Func<A, B, C> project) =>
        Bind(ma, a => Map(bind(a), b => project(a, b)));

    public static Reader<IAlgorithm> Ask =>
        env => env;
}

. Она фиксирована к типу IAlgorithm (его можно обобщить, добавив параметр E generi c к Reader<A>

You Затем можно инкапсулировать вызовы методов в функции * * * * * * * * *. * * * 10 * * * * * * * * * * * * * * * * * * * * * * * * * *. Пример использования будет таким: Вызов:

var env1 = new ClassAWithMyExtensionMethods();
var env2 = new ClassBWithMyExtensionMethods();

var res1 = Test.UseMethod(100, 200)(env1);
var res2 = Test.UseMethod(100, 200)(env2);

Полнофункциональная Reader монада, включая мою language-ext библиотеку

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