C# 什么是fluent对象模型来实现这一点?
作为编写fluent API的实践,我认为我应该编译并运行以下内容:C# 什么是fluent对象模型来实现这一点?,c#,functional-programming,ienumerable,C#,Functional Programming,Ienumerable,作为编写fluent 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"))
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();
}
想法是。当测试枚举中的每个元素时,如果它通过谓词,则运行操作。如果谓词失败,则该项沿链传递
我得出的图表是:
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);
}
公共静态类EnumerableExtensions
{
公共静态IConditionalEnumerable When(此IEnumerable项、谓词测试、操作)
{
}
公共静态IResolvedEnumerable Then(此IConditionalEnumerable项、谓词测试、操作)
{
}
公共静态无效运行(此IEnumerable items)
{
foreach(项目中的var项目);
}
}
公共接口IConditionalEnumerable:IEnumerable
{
IResolvedEnumerable Then(i条件可枚举项、操作);
}
公共接口IResolvedEnumerable:IEnumerable
{
i否则可数(动作行为);
}
我遇到了一个问题--当
不能foreach/yield return
在它里面时,因为返回类型不是直接的IEnumerable
(尽管它继承自它)。这给齿轮带来了精神上的冲击。扩展方法的实现是什么样子的?下面是我的尝试。我重新命名了接口,只是为了我的理解,我把它拼凑在一起
public interface IWhen<T> {
IThen<T> Then(Action<T> action);
}
public interface IThen<T> : IRun {
IWhen<T> When(Func<T, bool> test);
IRun Otherwise(Action<T> action);
}
public interface IRun {
void Run();
}
public interface IRule<T> {
Func<T, bool> Predicate { get; }
Action<T> Invoke { get; }
}
产生
1
2
fizz
4
buzz
fizz
7
8
fizz
buzz
不要担心序列。只要根据价值观来做就行了
您完全可以使用扩展方法来实现这一点。事情是这样的:
- 不知何故,
否则
需要知道之前的是否执行过李>
- 因此,在某种程度上,每一个
的时候都需要知道之前的是否都执行了
- 然后,每个
都需要知道前一个时的是真是假
这是骨架:
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) { ... }
等等
一旦你实现了它,那么就很容易将操作提升到序列。我们有一个将价值观转化为行动的装置;什么是将一系列值转换为一系列动作的装置?它内置于以下语言中:foreach(items中的var项)item.Begin()…
类似地,很容易将操作提升到任何其他monad。比如说,可以为空。我们有一个将价值转化为行动的装置。什么是将可空值转换为动作或不动作的设备?它内置于以下语言中:x?.Begin()…
假设您希望将操作应用于任务
;什么是将未来价值转化为未来行动的装置<代码>异步任务DoIt(任务任务){(等待任务).Begin()…
依此类推。对值执行操作,而不是对提升值执行操作。使用该语言的内置提升操作将操作应用于提升值以生成提升操作。提示:您能否构建不对序列而对单个值执行操作的相同fluent API?也就是说,您可以编写不是对IEnumerable
的扩展,而是简单地扩展到,比如说int
,这样您就可以对单个整数发出嘶嘶声了?如果是这样,那么将其扩展到序列(或可等待项,或可空项,或其他任何内容)是一个简单的过程。当您这样做时,您会发现问题与它是一个序列这一事实无关。问题是否则不知何故需要知道的数量是否为零或非零,然后子句是否已经执行。您可以尝试的下一个练习是:现在尝试编写一个相当于“开关”的流畅API例如,假设我们有switch(value).Case(v=>someBool)。然后(v=>someVal)。Case(v=>someBool)。然后(v=>someVal)。否则(v=>someVal)
wherevalue
和someVal
可以是不同的类型。你能实现它吗?然后你能提升它来处理一系列的值,并产生一系列的结果吗?这当(…)。然后(…)
-当
时,是否可以从返回IEnumerable
,然后仅在布尔值为真时应用,
我们的目标是生成序列1,2,fizz,4,buzz,fizz,7,8,9,buzz,11,fizz,13,14,fizzbuzz…
这是本网站创始人之一对本文的参考。请参阅我对原始问题的评论;如果不按顺序执行,这个问题更容易解决。我们已经有了一种在v上提升动作的机制将值转换为一系列值上的一系列操作;称为“foreach”。我真的很喜欢这个。它正是我想要的:)我喜欢避免为IEnumerable
实现这类事情的想法,因为这样做只会添加一个foreach
循环。我得看看我的IEnumerable
扩展,看看有没有类似的东西需要简化。@Sahuagin:你可能会问:如果我认为我们应该对值而不是提升值进行操作,为什么我们有Select、Where和SelectMany对序列而不是值进行操作。SelectMany的签名应该清楚地说明为什么它不能对值进行操作;操作的前提是它从序列中提取值,将它们转换为其他序列nces.和Select以及Where只是SelectMany的特殊版本,它们有自己的方法以方便使用。
public class Program {
public static void Main() {
Enumerable.Range(1, 10)
.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();
}
}
1
2
fizz
4
buzz
fizz
7
8
fizz
buzz
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) { ... }
3.Begin().When(x => x % 3 == 0).Then( ... )