什么是流畅的对象模型来使这项工作?

Bry*_*her 15 c# ienumerable functional-programming

作为编写流畅API的实践,我想我会进行以下编译和运行:

static void Main(string[] args)
{
    Enumerable.Range(1, 100)
        .When(i => i % 3 == 0).Then(i => Console.WriteLine("fizz"))
        .When(i => i % 5 == 0).Then(i => Console.WriteLine("buzz"))
        .Otherwise(i => Console.WriteLine(i))
        .Run();

    Console.ReadLine();
}
Run Code Online (Sandbox Code Playgroud)

这个想法.When将测试枚举中的每个元素,如果它通过谓词,则运行该动作.如果谓词失败,则项目沿着链传递.

我想出的图是:

public static class EnumerableExtensions
{
    public static IConditionalEnumerable<T> When<T>(this IEnumerable<T> items, Predicate<T> test, Action<T> action)
    {
    }

    public static IResolvedEnumerable<T> Then<T>(this IConditionalEnumerable<T> items, Predicate<T> test, Action<T> action)
    {
    }

    public static void Run<T>(this IEnumerable<T> items)
    {
        foreach (var item in items) ;
    }
}

public interface IConditionalEnumerable<T> : IEnumerable<T>
{
    IResolvedEnumerable<T> Then<T>(IConditionalEnumerable<T> items, Action<T> action);
}

public interface IResolvedEnumerable<T> : IEnumerable<T>
{
    IEnumerable<T> Otherwise(Action<T> behavior);
}
Run Code Online (Sandbox Code Playgroud)

我遇到了一个问题 - When不能foreach / yield return在其中,因为返回类型不是直接的IEnumerable<T>(尽管它继承了它).这给齿轮带来了精神上的冲击.扩展方法的实现会是什么样的?

Eri*_*ert 13

不要担心序列.只是在价值观上做.

您可以使用扩展方法完全执行此操作.这是事情:

  • 不知何故Otherwise需要知道以前是否有任何Then执行.
  • 因此,不知怎的,每个人都When需要知道以前是否每次都Then
  • 每个人都Then需要知道前一个When是真还是假.

这是骨架:

static class X 
{
    public enum WhenState { DoIt, DoNot }
    public enum ThenState { DidIt, DidNot }
    public static (T, ThenState) Begin<T>(this T item) { ... }
    public static (T, WhenState, ThenState) When<T>(
      this (T item, ThenState then) tuple, 
      Func<T, bool> p) { ... }
    public static (T, ThenState) Then<T>(
      this (T item, WhenState when, ThenState then) tuple, 
      Action<T> a) { ... }
    public static void Otherwise<T>(
      this (T item, ThenState then) tuple, 
      Action<T> a) { ... }
Run Code Online (Sandbox Code Playgroud)

实现这些扩展方法后,您可以执行以下操作:

3.Begin().When(x => x % 3 == 0).Then( ... )
Run Code Online (Sandbox Code Playgroud)

等等.

一旦实现了这一点,就很容易将操作提升到序列.我们有一个将价值观转化为行动的装置; 什么是将一系列值转换为一系列动作的设备?它内置于语言中:foreach(var item in items) item.Begin()....

同样,很容易将操作提升到任何其他monad.说,可以为空.我们有一个将值转化为行动的设备.什么是将可以为空的值转换为动作或无动作的设备?它内置于语言中: x?.Begin()...

假设您希望将您的操作应用于Task<int>; 什么是将未来价值转化为未来行动的设备?async Task DoIt(Task<T> task) { (await task).Begin()....

等等.在价值上实施您的操作,而不是在提升的价值上实施 ; 使用语言的内置提升操作将您的操作应用于提升值以产生提升动作.