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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM