C#用链式方法表达循环嵌套

情节故事得有情节,不喜欢情节的朋友可看第1版代码,然后直接跳至“三.想要链式写法”

一.起缘

故事缘于一位朋友的一道题:

朋友四人玩LOL游戏。第一局,分别选择位置:中单,上单,ADC,辅助;第二局新加入的伙伴要选上单,四人可选位置变为:中单,打野,ADC,辅助;要求,第二局四人每人不得选择和第一局相同的位置,请问两局综合考虑有多少种位置选择方式?

对于像我这边不懂游戏的人来讲,看不懂。于是有了这个版本:

有4个人,4只椅子,第一局每人坐一只椅子,第二局去掉第2只椅子,增加第5只椅子,每人坐一只椅子,而且每个人不能与第一局坐相同的椅子。问两局综合考虑,共有多少种可能的情况?

我一开始的想法是这样的,4个人就叫ABCD:第1局可能数是4*3*2*1=24,如果A第1局选了第2张椅,则A有4种可能,否则A有3种可能。对B来讲,如果A选了B第一局的椅,则B有3种可能,否则B有2种可能(排队自己第一局和A第二局已选)……想到这里我就晕了,情况越分越多。

二.原始的for嵌套

本来是一道数学题,应该由知识算出来有多少种,但我突然有个想法,不如用计算机穷举出出来。一来可以为各种猜测提供一个正确的答案,二来或许可以从答案反推出(数学上的)计算方法。然后就写了第1版:

static Seat data = new Seat();
public static void Run()
{
    for (int a = 0; a < 4; a++)
    {
        if (data.IsSelected(0, a))  //第1局编号0。如果已经被人坐了。
            continue;
        data.Selected(0, a, "A");   //第1局编号0。A坐a椅。
        for (int b = 0; b < 4; b++)
        {
            if (data.IsSelected(0, b))
                continue;
            data.Selected(0, b, "B");
            for (int c = 0; c < 4; c++)
            {
                if (data.IsSelected(0, c))
                    continue;
                data.Selected(0, c, "C");
                for (int d = 0; d < 4; d++)
                {
                    if (data.IsSelected(0, d))
                        continue;
                    data.Selected(0, d, "D");
                    for (int a2 = 0; a2 < 5; a2++)
                    {
                        if (a2 == 1)
                            continue;
                        if (data.IsSelected(1, a2))     //第2局编号1
                            continue;
                        if (data.IsSelected(0, a2, "A"))    //如果第1局A坐了a2椅
                            continue;
                        data.Selected(1, a2, "A");
                        for (int b2 = 0; b2 < 5; b2++)
                        {
                            if (b2 == 1)
                                continue;
                            if (data.IsSelected(1, b2))
                                continue;
                            if (data.IsSelected(0, b2, "B"))
                                continue;
                            data.Selected(1, b2, "B");
                            for (int c2 = 0; c2 < 5; c2++)
                            {
                                if (c2 == 1)
                                    continue;
                                if (data.IsSelected(1, c2))
                                    continue;
                                if (data.IsSelected(0, c2, "C"))
                                    continue;
                                data.Selected(1, c2, "C");
                                for (int d2 = 0; d2 < 5; d2++)
                                {
                                    if (d2 == 1)
                                        continue;
                                    if (data.IsSelected(1, d2))
                                        continue;
                                    if (data.IsSelected(0, d2, "D"))
                                        continue;
                                    data.Selected(1, d2, "D");

                                    data.Count++;       //可能的情况数加1
                                    Console.WriteLine("{0,5} {1}", data.Count, data.Current);

                                    data.UnSelected(1, d2);
                                }
                                data.UnSelected(1, c2);
                            }
                            data.UnSelected(1, b2);
                        }
                        data.UnSelected(1, a2);
                    }
                    data.UnSelected(0, d);
                }
                data.UnSelected(0, c);
            }
            data.UnSelected(0, b);
        }
        data.UnSelected(0, a);  //A起身(释放坐椅)
    }
}

部分运行结果:

说明:
1.ABCD是人名
2.“.”代表没有人
3.位置是是座位
4.-左边是第1局,右边是第2局
5.数字是序号

1 A B C D .-B . A C D
2 A B C D .-C . A B D
3 A B C D .-D . A B C
4 A B C D .-D . A C B
5 A B C D .-B . D A C
6 A B C D .-C . B A D
7 A B C D .-D . B A C
8 A B C D .-C . D A B
9 A B C D .-B . D C A
10 A B C D .-D . B C A
11 A B C D .-C . D B A
12 A B D C .-B . A D C
...
262 D C B A .-B . C D A
263 D C B A .-B . D C A
264 D C B A .-C . D B A

算出来是264种。从答案上来看是每11种是一组,一组中第1局的坐法是相同的,也就是说对于第一局的每一种情况,第2局都是有11种不同的可能。而第一局的可能性是24,所以答案是24*11=264。而第2局为什么是11种可能,后面再说。

三.想要链式写法

主题来了,像刚才的第1版的写法太死板太麻烦了。
如果能像这样写代码就爽了:

obj.Try("A").Try("B").Try("C").Try("D").Try2("A").Try2("B").Try2("C").Try2("D").Write();

而这样的代码通常的逻辑是执行Try("A")方法,然后执行Try("A")它return的对象的Try("B")方法……,即是Try("B")方法只被执行1次,而我希望的是Try("B")方法被Try("A")内部循环调用n次,Try("C")方法又被Try("B")方法调用m次。想想第1版的for套for不难明白为什么要追求这样的效果。如果Try("A")执行完了,再去执行Try("B"),那么Try("B")肯定不会被调用多次,所以得延迟Try("A")的执行,同理也延迟所有Try和Try2的执行。由于lambda表达天生有延迟计算的特性,于是很快写出了第2版:

public static void Run2()
{
    Try("A",
        () => Try("B",
            () => Try("C",
                () => Try("D",
                    () => Try2("A",
                        () => Try2("B",
                            () => Try2("C",
                                () => Try2("D",
                                    null
                                )
                            )
                        )
                    )
                )
            )
        )
    );
}
public static void Try(string name, Action action)    //第1局
{
    for (int i = 0; i < 4; i++)
    {
        if (data.IsSelected(0, i))
            continue;
        data.Selected(0, i, name);
        if (action == null)
        {
            Console.WriteLine(data.Current);
        }
        else
        {
            action();
        }
        data.UnSelected(0, i);
    }
}
public static void Try2(string name, Action action)    //第2局
{
    for (int i = 0; i < 5; i++)
    {
        if (i == 1)
            continue;
        if (data.IsSelected(1, i))
            continue;
        if (data.IsSelected(0, i, name))
            continue;
        data.Selected(1, i, name);
        if (action == null)
        {
            data.Count++;
            Console.WriteLine("{0,5} {1}", data.Count, data.Current);
        }
        else
        {
            action();
        }
        data.UnSelected(1, i);
    }
}

结构更合理,逻辑更清晰,但是一堆lambda嵌套,太丑了,也不是我要的效果,我要的是类似这样的:

obj.Try("A").Try("B").Try("C").Try("D").Try2("A").Try2("B").Try2("C").Try2("D").Write();

四.继续向目标逼近。
由于要延迟,所以必须先把要被调用的方法的引用“告诉”上一级,当上一级执行for的时候,就能调用下一级的方法。于是我想到了一个“回调链”

所以,执行链式方法是在构造回调链,最后的方法再通过调用链头(Head)的某个方法启动真正要执行的整个逻辑。
延迟计算是从Linq借鉴和学习来的,构造Linq的过程并没有执行,等到了执行ToList, First等方法时才真正去执行。
我想构造回调链每一步都是一个固定的方法,这里随便起用了T这个极短名称,而每一步后期计算时要执行的方法可灵活指定。于是有了第3版:

static Seat data = new Seat();      //借用Seat保存数据
public Seat2(string name, Seat2 parent, Action<Seat2> method)
{
    this.Name = name;
    this.Parent = parent;
    if (parent != null)
        parent.Child = this;
    this.Method = method;
}
public static void Run()
{
    new Seat2("A", null, me => me.Try())
        .T("B", me => me.Try())
        .T("C", me => me.Try())
        .T("D", me => me.Try())
        .T("A", me => me.Try2())
        .T("B", me => me.Try2())
        .T("C", me => me.Try2())
        .T("D", me => me.Try2())
        .P().Start();
}
public Seat2 T(string name, Action<Seat2> method)
{
    return new Seat2(name, this, method);
}
public void Try()
{
    for (int i = 0; i < 4; i++)
    {
        if (data.IsSelected(0, i))
            continue;
        data.Selected(0, i, this.Name);
        if (this.Child != null)
        {
            this.Child.Method(this.Child);
        }
        data.UnSelected(0, i);
    }
}
public void Try2()
{
    for (int i = 0; i < 5; i++)
    {
        if (i == 1)
            continue;
        if (data.IsSelected(1, i))
            continue;
        if (data.IsSelected(0, i, this.Name))
            continue;
        data.Selected(1, i, this.Name);
        if (this.Child != null)
        {
            this.Child.Method(this.Child);
        }
        data.UnSelected(1, i);
    }
}

五.解耦
这种调用方式,是满意了。但是运算框架与具体的算法耦合在一起,如果能把运算框架提取出来,以后写具体的算法也方便许多。于是经过苦逼的提取,测试,踩坑,最终出现了第4版:

 1 //运算框架
 2 class ComputeLink<T> where T : ISeat3
 3 {
 4     ComputeLink<T> Parent { get; set; }     //父节点,即上一级节点
 5     ComputeLink<T> Child { get; set; }      //子节点,即下一级节点
 6     T Obj { get; set; }     //当前节点对应的算法对象,可以看作业务对象
 7     public ComputeLink(T obj, ComputeLink<T> parent, Action<T> method)
 8     {
 9         if (obj == null)
10             throw new ArgumentNullException("obj");
11         this.Obj = obj;
12         this.Obj.Method = x => method((T)x);
13         if (parent != null)
14         {
15             this.Parent = parent;
16             parent.Child = this;
17             parent.Obj.Child = this.Obj;
18         }
19     }
20     public static ComputeLink<T> New(T obj, Action<T> method)
21     {
22         return new ComputeLink<T>(obj, null, method);
23     }
24 
25     public ComputeLink<T> Do(T obj, Action<T> method)
26     {
27         return new ComputeLink<T>(obj, this, method);
28     }
29     public ComputeLink<T> Head      //链表的头
30     {
31         get
32         {
33             if (null != this.Parent)
34                 return this.Parent.Head;
35             return this;
36         }
37     }
38     public void Action()        //启动(延迟的)整个计算
39     {
40         var head = this.Head;
41         head.Obj.Method(head.Obj);
42     }
43 }
44 interface ISeat3
45 {
46     ISeat3 Child { get; set; }
47     Action<ISeat3> Method { get; set; }
48 }

p.s.为什么第4版是ISeat3而不是ISeat4呢,因为我本不把第1版当作1个版本,因为太原始了,出现第2版后,我就把第1版给删除了。为了写这篇文章才重新去写第1版。于是原本我当作第3版的ISeat3自然地排到了第4版。

具体的"算法"就很简单了:

class Seat3 : ISeat3
{
    static Seat data = new Seat();
    string Name { get; set; }
    public Seat3(string name)
    {
        this.Name = name;
    }
    /// <summary>
    /// 解耦的版本
    /// </summary>
    public static void Run()
    {
        var sql = ComputeLink<Seat3>
            .New(new Seat3("A"), m => m.Try())
            .Do(new Seat3("B"), m => m.Try())
            .Do(new Seat3("C"), m => m.Try())
            .Do(new Seat3("D"), m => m.Try())
            .Do(new Seat3("A"), m => m.Try2())
            .Do(new Seat3("B"), m => m.Try2())
            .Do(new Seat3("C"), m => m.Try2())
            .Do(new Seat3("D"), m => m.Try2())
            .Do(new Seat3(""), m => m.Print());
        sql.Action();
    }
    public Action<ISeat3> Method { get; set; }
    public ISeat3 Child { get; set; }
    public void Try()
    {
        for (int i = 0; i < 4; i++)
        {
            if (data.IsSelected(0, i))
                continue;
            data.Selected(0, i, this.Name);
            if (this.Child != null)
            {
                this.Child.Method(this.Child);
            }
            data.UnSelected(0, i);
        }
    }
    public void Try2()
    {
        for (int i = 0; i < 5; i++)
        {
            if (i == 1)
                continue;
            if (data.IsSelected(1, i))
                continue;
            if (data.IsSelected(0, i, this.Name))
                continue;
            data.Selected(1, i, this.Name);
            if (this.Child != null)
            {
                this.Child.Method(this.Child);
            }
            data.UnSelected(1, i);
        }
    }
    public void Print()
    {
        data.Count++;
        Console.WriteLine("{0,5} {1}", data.Count, data.Current);
    }
}

Seat3写起来简单,(Run方法内部)看起来舒服。通过链式写法达到嵌套循环的效果。对,这就是我要的!
它很像linq,所以我直接给变量命名为sql。

  • 对于Try和Try2来讲,要调用的方法最好从参数传来,但是这样就会增加Run方法中New和Do的参数复杂性,破坏了美感,所以经过权衡,Child和Method通过属性传入。这个我也不确定这样做好不好,请各位大侠指点。
  • 还有一个细节,就是ComputeLink构造方法中的(行号12的)代码 this.Obj.Method = x => method((T)x); 。我原来是这样写的 this.Obj.Method = method; 编译不通过,原因是不能把 Action<ISeat3> 转化为 Action<T> ,虽然T一定实现了ISeat3,强制转化也不行,想起以前看过的一篇文章里面提到希望C#以后的版本能拥有的一特性叫“协变”,很可能指的就是这个。既然这个 Action<ISeat3> 不能转化为 Action<T> 但是ISeat3是可以强制转化为T的,所以我包了一层薄薄的壳,成了 this.Obj.Method = x => method((T)x); ,如果有更好的办法请告诉我。

六.第2局为什么是11种可能
回过头来解决为什么对于一个确定的第1局,第2局有11种可能。
不妨假设第1局的选择是A选1号椅,B选2号椅,C选3号椅,D选4号椅。
第2局分为两大类情况:
如果B选了第5号椅
则只有2种可能:
A B C D .-D . A C B
A B C D .-C . D A B
如果B选了不是第5号椅,
则ACD都有可能选第5号椅,有3种可能。B有3种选的可能(1,3,4号椅),B一旦确定,A和C也只有一种可能
所以11 = 2 + 3 * 3
七.结论
由一道数学题牵引出多层循环嵌套,最终通过封装达到了我要的链式调用的效果,我是很满意的。这也是我第一次设计延迟计算,感觉强烈。如果新的场景需要用到延迟计算我想有了这次经验写起来会顺手许多。如果是需要多层for的算法题都可以比较方便的实现了。

你都看到这里了,为我点个赞吧,能说一下看法就更好了。

完整代码:

  1 using System;
  2 using System.Linq;
  3 using System.Diagnostics;
  4 
  5 namespace ConsoleApplication1
  6 {
  7     class Seat
  8     {
  9         static Seat data = new Seat();
 10         public static void Run()
 11         {
 12             //Seat2.Run();
 13             //return;
 14             for (int a = 0; a < 4; a++)
 15             {
 16                 if (data.IsSelected(0, a))  //第1局编号0。如果已经被人坐了。
 17                     continue;
 18                 data.Selected(0, a, "A");   //第1局编号0。A坐a椅。
 19                 for (int b = 0; b < 4; b++)
 20                 {
 21                     if (data.IsSelected(0, b))
 22                         continue;
 23                     data.Selected(0, b, "B");
 24                     for (int c = 0; c < 4; c++)
 25                     {
 26                         if (data.IsSelected(0, c))
 27                             continue;
 28                         data.Selected(0, c, "C");
 29                         for (int d = 0; d < 4; d++)
 30                         {
 31                             if (data.IsSelected(0, d))
 32                                 continue;
 33                             data.Selected(0, d, "D");
 34                             for (int a2 = 0; a2 < 5; a2++)
 35                             {
 36                                 if (a2 == 1)
 37                                     continue;
 38                                 if (data.IsSelected(1, a2))     //第2局编号1
 39                                     continue;
 40                                 if (data.IsSelected(0, a2, "A"))    //如果第1局A坐了a2椅
 41                                     continue;
 42                                 data.Selected(1, a2, "A");
 43                                 for (int b2 = 0; b2 < 5; b2++)
 44                                 {
 45                                     if (b2 == 1)
 46                                         continue;
 47                                     if (data.IsSelected(1, b2))
 48                                         continue;
 49                                     if (data.IsSelected(0, b2, "B"))
 50                                         continue;
 51                                     data.Selected(1, b2, "B");
 52                                     for (int c2 = 0; c2 < 5; c2++)
 53                                     {
 54                                         if (c2 == 1)
 55                                             continue;
 56                                         if (data.IsSelected(1, c2))
 57                                             continue;
 58                                         if (data.IsSelected(0, c2, "C"))
 59                                             continue;
 60                                         data.Selected(1, c2, "C");
 61                                         for (int d2 = 0; d2 < 5; d2++)
 62                                         {
 63                                             if (d2 == 1)
 64                                                 continue;
 65                                             if (data.IsSelected(1, d2))
 66                                                 continue;
 67                                             if (data.IsSelected(0, d2, "D"))
 68                                                 continue;
 69                                             data.Selected(1, d2, "D");
 70 
 71                                             data.Count++;       //可能的情况数加1
 72                                             Console.WriteLine("{0,5} {1}", data.Count, data.Current);
 73 
 74                                             data.UnSelected(1, d2);
 75                                         }
 76                                         data.UnSelected(1, c2);
 77                                     }
 78                                     data.UnSelected(1, b2);
 79                                 }
 80                                 data.UnSelected(1, a2);
 81                             }
 82                             data.UnSelected(0, d);
 83                         }
 84                         data.UnSelected(0, c);
 85                     }
 86                     data.UnSelected(0, b);
 87                 }
 88                 data.UnSelected(0, a);  //A起身(释放坐椅)
 89             }
 90         }
 91         public static void Run2()
 92         {
 93             Try("A",
 94                 () => Try("B",
 95                     () => Try("C",
 96                         () => Try("D",
 97                             () => Try2("A",
 98                                 () => Try2("B",
 99                                     () => Try2("C",
100                                         () => Try2("D",
101                                             null
102                                         )
103                                     )
104                                 )
105                             )
106                         )
107                     )
108                 )
109             );
110         }
111         public static void Try(string name, Action action)
112         {
113             for (int i = 0; i < 4; i++)
114             {
115                 if (data.IsSelected(0, i))
116                     continue;
117                 data.Selected(0, i, name);
118                 if (action == null)
119                 {
120                     Console.WriteLine(data.Current);
121                 }
122                 else
123                 {
124                     action();
125                 }
126                 data.UnSelected(0, i);
127             }
128         }
129 
130         public static void Try2(string name, Action action)
131         {
132             for (int i = 0; i < 5; i++)
133             {
134                 if (i == 1)
135                     continue;
136                 if (data.IsSelected(1, i))
137                     continue;
138                 if (data.IsSelected(0, i, name))
139                     continue;
140                 data.Selected(1, i, name);
141                 if (action == null)
142                 {
143                     data.Count++;
144                     Console.WriteLine("{0,5} {1}", data.Count, data.Current);
145                 }
146                 else
147                 {
148                     action();
149                 }
150                 data.UnSelected(1, i);
151             }
152         }
153         public Seat()
154         {
155             seats[0, 4] = ".";
156             seats[1, 1] = ".";
157         }
158         private string[,] seats = new string[2, 5];
159         public void UnSelected(int game, int i)
160         {
161             Debug.Assert(game == 0 && i != 4 || game == 1 && i != 1);
162             Debug.Assert(seats[game, i] != null);
163             seats[game, i] = null;
164         }
165         public void Selected(int game, int i, string name)
166         {
167             Debug.Assert(game == 0 && i != 4 || game == 1 && i != 1);
168             Debug.Assert(seats[game, i] == null);
169             seats[game, i] = name;
170         }
171         public bool IsSelected(int game, int a)
172         {
173             return seats[game, a] != null && seats[game, a] != ".";
174         }
175         public bool IsSelected(int game, int a, string name)
176         {
177             return seats[game, a] == name;
178         }
179         public string Current
180         {
181             get
182             {
183                 return string.Format("{0} {1} {2} {3} {4}-{5} {6} {7} {8} {9}",
184                     seats[0, 0], seats[0, 1], seats[0, 2], seats[0, 3], seats[0, 4],
185                     seats[1, 0], seats[1, 1], seats[1, 2], seats[1, 3], seats[1, 4]);
186             }
187         }
188 
189         public int Count { get; set; }
190     }
191 
192     class Seat2
193     {
194         static Seat data = new Seat();      //借用Seat保存法的数据
195         Seat2 Parent { get; set; }
196         Seat2 Child { get; set; }
197         string Name { get; set; }
198         Action<Seat2> Method { get; set; }
199         public Seat2(string name, Seat2 parent, Action<Seat2> method)
200         {
201             this.Name = name;
202             this.Parent = parent;
203             if (parent != null)
204                 parent.Child = this;
205             this.Method = method;
206         }
207         /// <summary>
208         /// 耦合的版本
209         /// </summary>
210         public static void Run()
211         {
212             new Seat2("A", null, me => me.Try())
213                 .T("B", me => me.Try())
214                 .T("C", me => me.Try())
215                 .T("D", me => me.Try())
216                 .T("A", me => me.Try2())
217                 .T("B", me => me.Try2())
218                 .T("C", me => me.Try2())
219                 .T("D", me => me.Try2())
220                 .P().Start();
221         }
222         public Seat2 T(string name, Action<Seat2> method)
223         {
224             return new Seat2(name, this, method);
225         }
226         public Seat2 P()
227         {
228             return new Seat2("Print", this, me => me.Print());
229         }
230         public void Start()
231         {
232             var head = this.Head;
233             head.Method(head);
234         }
235         public Seat2 Head
236         {
237             get
238             {
239                 if (null != this.Parent)
240                     return this.Parent.Head;
241                 return this;
242             }
243         }
244         public void Try()
245         {
246             for (int i = 0; i < 4; i++)
247             {
248                 if (data.IsSelected(0, i))
249                     continue;
250                 data.Selected(0, i, this.Name);
251                 if (this.Child != null)
252                 {
253                     this.Child.Method(this.Child);
254                 }
255                 data.UnSelected(0, i);
256             }
257         }
258         public void Try2()
259         {
260             for (int i = 0; i < 5; i++)
261             {
262                 if (i == 1)
263                     continue;
264                 if (data.IsSelected(1, i))
265                     continue;
266                 if (data.IsSelected(0, i, this.Name))
267                     continue;
268                 data.Selected(1, i, this.Name);
269                 if (this.Child != null)
270                 {
271                     this.Child.Method(this.Child);
272                 }
273                 data.UnSelected(1, i);
274             }
275         }
276         public void Print()
277         {
278             data.Count++;
279             Console.WriteLine("{0,5} {1}", data.Count, data.Current);
280         }
281 
282         public override string ToString()
283         {
284             return this.Name.ToString();
285         }
286     }
287 
288     class ComputeLink<T> where T : ISeat3
289     {
290         ComputeLink<T> Parent { get; set; }     //父节点,即上一级节点
291         ComputeLink<T> Child { get; set; }      //子节点,即下一级节点
292         T Obj { get; set; }     //当前节点对应的算法对象,可以看作业务对象
293         public ComputeLink(T obj, ComputeLink<T> parent, Action<T> method)
294         {
295             if (obj == null)
296                 throw new ArgumentNullException("obj");
297             this.Obj = obj;
298             this.Obj.Method = x => method((T)x);
299             if (parent != null)
300             {
301                 this.Parent = parent;
302                 parent.Child = this;
303                 parent.Obj.Child = this.Obj;
304             }
305         }
306         public static ComputeLink<T> New(T obj, Action<T> method)
307         {
308             return new ComputeLink<T>(obj, null, method);
309         }
310 
311         public ComputeLink<T> Do(T obj, Action<T> method)
312         {
313             return new ComputeLink<T>(obj, this, method);
314         }
315         public ComputeLink<T> Head      //链表的头
316         {
317             get
318             {
319                 if (null != this.Parent)
320                     return this.Parent.Head;
321                 return this;
322             }
323         }
324         public void Action()        //启动(延迟的)整个计算
325         {
326             var head = this.Head;
327             head.Obj.Method(head.Obj);
328         }
329     }
330     interface ISeat3
331     {
332         ISeat3 Child { get; set; }
333         Action<ISeat3> Method { get; set; }
334     }
335     class Seat3 : ISeat3
336     {
337         static Seat data = new Seat();
338         string Name { get; set; }
339         public Seat3(string name)
340         {
341             this.Name = name;
342         }
343         /// <summary>
344         /// 解耦的版本
345         /// </summary>
346         public static void Run()
347         {
348             var sql = ComputeLink<Seat3>
349                 .New(new Seat3("A"), m => m.Try())
350                 .Do(new Seat3("B"), m => m.Try())
351                 .Do(new Seat3("C"), m => m.Try())
352                 .Do(new Seat3("D"), m => m.Try())
353                 .Do(new Seat3("A"), m => m.Try2())
354                 .Do(new Seat3("B"), m => m.Try2())
355                 .Do(new Seat3("C"), m => m.Try2())
356                 .Do(new Seat3("D"), m => m.Try2())
357                 .Do(new Seat3(""), m => m.Print());
358             sql.Action();
359         }
360         public Action<ISeat3> Method { get; set; }
361         public ISeat3 Child { get; set; }
362         public void Try()
363         {
364             for (int i = 0; i < 4; i++)
365             {
366                 if (data.IsSelected(0, i))
367                     continue;
368                 data.Selected(0, i, this.Name);
369                 if (this.Child != null)
370                 {
371                     this.Child.Method(this.Child);
372                 }
373                 data.UnSelected(0, i);
374             }
375         }
376         public void Try2()
377         {
378             for (int i = 0; i < 5; i++)
379             {
380                 if (i == 1)
381                     continue;
382                 if (data.IsSelected(1, i))
383                     continue;
384                 if (data.IsSelected(0, i, this.Name))
385                     continue;
386                 data.Selected(1, i, this.Name);
387                 if (this.Child != null)
388                 {
389                     this.Child.Method(this.Child);
390                 }
391                 data.UnSelected(1, i);
392             }
393         }
394         public void Print()
395         {
396             data.Count++;
397             Console.WriteLine("{0,5} {1}", data.Count, data.Current);
398         }
399 
400         public override string ToString()
401         {
402             return this.Name.ToString();
403         }
404     }
405 }
View Code
原文地址:https://www.cnblogs.com/BillySir/p/5542104.html