none
ㄧ種字串組合語法 RRS feed

  • 問題

  • 各位前輩

    小弟目前想要做一個字串的組合寫法

    主要用於下"命令" 控制設備用

    一方面也希望後面的同事能比較輕鬆寫程式~不用把Table表放旁邊看


    例如 我的命令規劃如下

    A="我"
    B="你"
    C="他"

    AA="去醫院"
    BB="去學校"
    CC="去商店"


    AAA="探病"
    BBB="讀書"
    CCC="購物"


    那我之後的同事命令組合能使用以下寫法直接寫

    例如命令為 我 去醫院 探病
    那就直接寫 A.AA.AAA 的方式

    例如命令為 我 去學校 探病
    那就直接寫 A.BB.AAA 的方式

    例如命令為 我 去醫院   <== 命令到第2層就結束也可以
    那就直接寫 A.AA 的方式


    例如命令為 我    <== 命令到第1層就結束也可以
    那就直接寫 A 的方式


    我有試過用CLASS寫~但感覺怪怪的有點不達理想~所以上來問一下比較懂的各位前輩

    我這種想法能否實現?

    若可以~請給我一些方向~並指導~感謝~

    2015年5月6日 上午 01:50

解答

  • 你的類別要做到兩件事:

    1. 方法要回傳你的類別。

    2. 方法內要更新 "現在" 這個物件的狀態,並回傳 "現在" 這個物件 (VB 就是 Return Me, C# 是 return this;)。

    這樣連續呼叫時才都會是作用在同一個物件。


    強力監督SQL Injection問題!!

      • 小朱的技術隨手寫:http://www.dotblogs.com.tw/regionbbs/
      • 雲端學堂Facebook: http://www.facebook.com/studyazure

    • 已標示為解答 魚骨頭 2015年5月6日 上午 10:09
    • 已取消標示為解答 魚骨頭 2015年5月6日 上午 10:12
    • 已標示為解答 魚骨頭 2015年5月7日 上午 05:29
    2015年5月6日 上午 08:31
    版主
  • 感謝 Coding Kid Peter Chang 與 小朱 2位前輩的指導

    針對Coding Kid Peter Chang的第一個建議

    最近站上看到幾篇擴充方法

    我簡單的試寫了一下~

    ....

    因為你的方法 沒有回傳自己的型別

    Imports System.Runtime.CompilerServices
    
    Module Module1
    
        Sub Main()
            Dim str As String = ""
            str.I().GoSchool().Study()
    
        End Sub
    
    End Module
    
    Module StringExtension
        <Extension()> 
        Public Function I(ByVal str As String) As String
            Return str & "I"
        End Function
    
        <Extension()> 
        Public Function GoSchool(ByVal str As String) As String
            Return str & "GoSchool"
        End Function
    
        <Extension()> 
        Public Function Study(ByVal str As String) As String
            Return str & "Study"
        End Function
    
    End Module

    • 已標示為解答 魚骨頭 2015年5月6日 上午 10:09
    • 已取消標示為解答 魚骨頭 2015年5月6日 上午 10:12
    • 已標示為解答 魚骨頭 2015年5月7日 上午 05:28
    2015年5月6日 上午 09:05
  • 是有一種很奇怪的方法可以弄出你要的效果, 前提是, 如果你的 Command 的呼叫層級不會改變 (比方三層突然又變成四層), 不會有命令更換層級的問題 (比方 AA 本來是第二層, 又換到第三層). 這個詭異的方式是可以解決你的問題 (如果是 C# 會有兩種詭異的方式)

    這個方式的基底類別有個唯讀的 Result 屬性, 用來取得最後的結果. 以下繼承的每個類別內的方法回傳型別為該類別的父代, 就會有你要的結果. (但真的很怪 .....)

    Public Class CommandResult
        Sub New()
            _result = String.Empty
        End Sub
    
        Protected _result As String
    
        Public ReadOnly Property Result As String
            Get
                Return _result
            End Get
    
        End Property
    
    End Class
    
    Public Class CommandLevel3
        Inherits CommandResult
        Public Function AAA() As CommandResult 
            _result &= "探病"
            Return DirectCast(Me, CommandResult)
        End Function
        Public Function BBB() As CommandResult
            _result &= "讀書"
            Return DirectCast(Me, CommandResult)
        End Function
        Public Function CCC() As CommandResult
            _result &= "購物"
            Return DirectCast(Me, CommandResult)
        End Function
    End Class
    
    Public Class CommandLevel2
        Inherits CommandLevel3
    
    
        Public Function AA() As CommandLevel3
            _result &= "去醫院"
            Return DirectCast(Me, CommandLevel3)
        End Function
        Public Function BB() As CommandLevel3
            _result &= "去學校"
            Return DirectCast(Me, CommandLevel3)
        End Function
        Public Function CC() As CommandLevel3
            _result &= "去商店"
            Return DirectCast(Me, CommandLevel3)
        End Function
    End Class
    
    
    Public Class CommandLevel1
        Inherits CommandLevel2
    
    
        Public Function A() As CommandLevel2
            _result &= "我"
            Return DirectCast(Me, CommandLevel2)
        End Function
        Public Function B() As CommandLevel2
            _result &= "你"
            Return DirectCast(Me, CommandLevel2)
        End Function
        Public Function C() As CommandLevel2
            _result &= "他"
            Return DirectCast(Me, CommandLevel2)
        End Function
    End Class


    在現實生活中,你和誰在一起的確很重要,甚至能改變你的成長軌跡,決定你的人生成敗。 和什麼樣的人在一起,就會有什麼樣的人生。 和勤奮的人在一起,你不會懶惰; 和積極的人在一起,你不會消沈; 與智者同行,你會不同凡響; 與高人為伍,你能登上巔峰。


    2015年5月7日 上午 09:03
    版主

所有回覆

  • 以你的CASE來說,用Class是做得出來的,可是不建議這樣做

    你可以用擴充方法,把你要的動作(方法)全部定義在 object上,

    然後該方法回傳直都是 object這樣就可以滿足你的需求了。

    C# code

        public class Person
        {
     
        }
    
    
        public static class exObj
        {
            public static object GoHospital(this object person)
            {
                //do something...
                return person;
            }
    
            public static object GoSchool(this object person)
            {
                //do something...
                return person;
            }
    
            public static object GoShop(this object person)
            {
                //do something...
                return person;
            }
    
            public static object VisitPatient(this object person)
            {
                //do something...
                return person;
            }
    
            public static object Study(this object person)
            {
                //do something...
                return person;
            }
    
            public static object Shopping(this object person)
            {
                //do something...
                return person;
            }
        }

    你就可以使用了

                Person i = new Person();
    
                i.GoHospital().Shopping();
    
                Person you = new Person();
    
                you.GoSchool().Study();
    
                Person he = new Person();
    
                he.GoShop().VisitPatient();

    2015年5月6日 上午 04:44
  • 還有另外一種寫法,當然我也是不建議啦!

    不建議的原因是 我只是告訴你可以這樣寫,我也覺得可讀性高,可是我還真的沒有在實際的專案這樣寫過,

    因為實際上寫的時候 有時候邏輯更複雜,有些東西很抽象,

    而且為了做到這樣串聯,方法的回傳值一定要是自己的型別,如果你要取得回傳值,可能用要ref

    這是我自已的看法拉!

        public class Person
        {
            public Person Go(string where)
            {
                /// do something
                return this;
            }
    
            public Person Do(string what)
            {
                /// do something
                return this;
            }
        }

    實際上在用的時候

                Person i = new Person();
    
                i.Go("醫院").Do("探病");
    
                Person you = new Person();
    
                you.Go("學校").Do("看書");
    
                Person he = new Person();
    
                he.Go("商店").Do("購物");




    2015年5月6日 上午 04:59
  • http://www.dotblogs.com.tw/regionbbs/archive/2012/01/12/fluent.interface.in.net.aspx

    強力監督SQL Injection問題!!

      • 小朱的技術隨手寫:http://www.dotblogs.com.tw/regionbbs/
      • 雲端學堂Facebook: http://www.facebook.com/studyazure

    2015年5月6日 上午 05:36
    版主
  • 感謝 Coding Kid Peter Chang 與 小朱 2位前輩的指導

    針對Coding Kid Peter Chang的第一個建議

    最近站上看到幾篇擴充方法

    我簡單的試寫了一下~

    Imports System.Runtime.CompilerServices
    
    
    <Extension()>
    Module yy
    
        <Extension()>
        Public Function I(ByVal yy As String)
    
            Return (yy & "I")
        End Function
        <Extension()>
        Public Function You(ByVal yy As String)
    
            Return (yy & "You")
        End Function
    
    
        <Extension()>
        Public Function GoSchool(ByVal yy As String)
    
            Return (yy & "GoSchool")
        End Function
    
        <Extension()>
        Public Function GoHospital(ByVal yy As String)
    
            Return (yy & "GoHospital")
        End Function
    
        <Extension()>
        Public Function VisitPatient(ByVal yy As String)
    
            Return (yy & "VisitPatient")
        End Function
        <Extension()>
        Public Function Study(ByVal yy As String)
            Return (yy & "Studyt")
        End Function
    
    
    End Module
    
     
    
    Public Class Form1
    
    
        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
            Dim command As String = ""
            Label1.Text = command.I   '<== 重點  
                                                    '沒辦法寫成想要的command.I.GoSchool.Study
                                                    '有什方法可以一直下去?
                                                    '試驗一下vb.net 的.ToString  可以一直下去耶!
                                                    '即使想要寫成command.I.I.I.I也不行
                                                    '擴充方法~有辦法一直下去嗎?就如官方的.ToString
    
        End Sub
    
       
    End Class
    

     

    小朱前輩給的~雖然最後面看他用的方式很像我需要的!

    但~我不是用VB.NET的~不知怎麼改C#的語法~Orz

    我ㄧ開始沒說清楚~抱歉

     

     

     

    2015年5月6日 上午 07:48
  • 你的類別要做到兩件事:

    1. 方法要回傳你的類別。

    2. 方法內要更新 "現在" 這個物件的狀態,並回傳 "現在" 這個物件 (VB 就是 Return Me, C# 是 return this;)。

    這樣連續呼叫時才都會是作用在同一個物件。


    強力監督SQL Injection問題!!

      • 小朱的技術隨手寫:http://www.dotblogs.com.tw/regionbbs/
      • 雲端學堂Facebook: http://www.facebook.com/studyazure

    • 已標示為解答 魚骨頭 2015年5月6日 上午 10:09
    • 已取消標示為解答 魚骨頭 2015年5月6日 上午 10:12
    • 已標示為解答 魚骨頭 2015年5月7日 上午 05:29
    2015年5月6日 上午 08:31
    版主
  • 感謝 Coding Kid Peter Chang 與 小朱 2位前輩的指導

    針對Coding Kid Peter Chang的第一個建議

    最近站上看到幾篇擴充方法

    我簡單的試寫了一下~

    ....

    因為你的方法 沒有回傳自己的型別

    Imports System.Runtime.CompilerServices
    
    Module Module1
    
        Sub Main()
            Dim str As String = ""
            str.I().GoSchool().Study()
    
        End Sub
    
    End Module
    
    Module StringExtension
        <Extension()> 
        Public Function I(ByVal str As String) As String
            Return str & "I"
        End Function
    
        <Extension()> 
        Public Function GoSchool(ByVal str As String) As String
            Return str & "GoSchool"
        End Function
    
        <Extension()> 
        Public Function Study(ByVal str As String) As String
            Return str & "Study"
        End Function
    
    End Module

    • 已標示為解答 魚骨頭 2015年5月6日 上午 10:09
    • 已取消標示為解答 魚骨頭 2015年5月6日 上午 10:12
    • 已標示為解答 魚骨頭 2015年5月7日 上午 05:28
    2015年5月6日 上午 09:05
  • 看完小朱前輩的訊息~

    整個腦袋就打結了~=.=|||~對ME這個字的用法~略懂而已~

    所以~小朱前輩的回覆~看完我是整個無法思考~不知如何下手

     

    還好Coding Kid Peter Chang 前輩出手救援了!

    但看完寫的CODE~卻發現沒什差別阿!但為什會有我想要效果!!!

    只好認真一行一行對~

    恩~果然是看出問題了~

    原來 Public Function I(ByVal str As String) As String

    以這行來說~就是少了最後的 As String

    Orz~(我找個藉口~把錯推給IDE好了~~哈~居然沒幫我找出錯誤!

     

    最後~想再問一下~我看最上方C# code 是真的有用到this

    所以~可改成vb.net 用me的方式嗎?

    如果可以~請前輩再麻煩幫我處理一下了~

    今天學到很多~感謝大家~^^ 

     

     

    我忘記了一個很重要的問題~= =!

    這命令組合 是有方向性的~

    意思是  只能由第一層 (我)  接第2層(去學校) 或直接接第3層(學習)

    所以~是否有辦法 選完第一層 後 就看不到第一層的了~只會出現第2  3層的命令

    當然~選完第2層的命令後~一樣不能再選第2層的了~

    可以這用嗎?


    本來標完解答的~我又先行取消了~抱歉

    • 已編輯 魚骨頭 2015年5月6日 上午 10:18
    2015年5月6日 上午 10:09
  • ....

     

    我忘記了一個很重要的問題~= =!

    這命令組合 是有方向性的~

    意思是  只能由第一層 (我)  接第2層(去學校) 或直接接第3層(學習)

    所以~是否有辦法 選完第一層 後 就看不到第一層的了~只會出現第2  3層的命令

    當然~選完第2層的命令後~一樣不能再選第2層的了~

    可以這用嗎?


    本來標完解答的~我又先行取消了~抱歉

    其實你仔細想想為什麼可以點出東西,他就只是回傳值物件的方法而已。

    至於順序性,我認為用string本身是弄不出來的,可能要建不同的類別,外加繼承,才有機會滿足順序性的需求。

    2015年5月6日 下午 01:28
  • 感謝 Coding Kid Peter Chang 前輩您的回覆

    我想~對於這個 擴充方法 的寫法~得再練熟一點

    而你提到的 建不同的類別,外加繼承,才有機會滿足順序性的需求

    看到這頭就痛了~因為不是很熟這區!

    總之~這問題就先到這了~

    感謝Coding Kid Peter Chang 與 小朱 前輩

    2015年5月7日 上午 05:28
  • 個人意見, 硬要做成這樣, 可能會有類別擴張的問題. 也就是你的第一層命令, 第二層命令, 第三層命令是否為有限 ? 或是日後可能會大量擴張其數量 ? 如果為有限, 類別擴張就比較不會構成日後開發的問題.

    不過因為沒法了解你專案的全貌, 利弊得失你得自己衡量.


    在現實生活中,你和誰在一起的確很重要,甚至能改變你的成長軌跡,決定你的人生成敗。 和什麼樣的人在一起,就會有什麼樣的人生。 和勤奮的人在一起,你不會懶惰; 和積極的人在一起,你不會消沈; 與智者同行,你會不同凡響; 與高人為伍,你能登上巔峰。

    2015年5月7日 上午 05:34
    版主
  • 感謝Bill前輩的回覆

    對於我的問題

    立意上是希望後面的同事維護時或是寫程式時~可以方便寫

    而不用把"命令表"放在旁邊看來寫

    而我會想用這樣的寫法~是因為覺得很方便~直接用選的~一方面預防止字串輸入錯誤

    而一方面也可以不用拿命令表出來看~很直覺得選擇 挑選 就可以了

    我記得我的另一個很類似的寫法~是用字串陣列

    然後把索引直用 Enum 重新定義後~來組的

    例如

    Command1(COMINDEX1.I)+Command2(COMINDEX2.GoSchool)+Command3(COMINDEX3.Study)

    而最近~就在想說~是否能有更容易寫的方式~

    就想到 若能寫成   I.GoSchool.Study 這樣的方式~根本直覺又完美阿^^


    至於思考可能遇到的問題!我只能說~並不是不怕~而是自己根本不知道這樣做會發生什問題!

    懂了人~真的一眼就能知道可能會發生的問題

    而像我~功力還很不足~根本看不出問題(汗顏


    所以~類別擴張~意思是原本的類別在日後可會會增加其他方法或函數~這樣的意思吧?

    那~跟我現在的做法~會發生什呢?

    另外~我並沒有硬要這樣做啦~

    我只是在找一個可以直覺寫程式的方法而以~

    可以的話~煩請Bill前輩再指教了~

    謝謝~

     

     

     

    2015年5月7日 上午 07:03
  • 是有一種很奇怪的方法可以弄出你要的效果, 前提是, 如果你的 Command 的呼叫層級不會改變 (比方三層突然又變成四層), 不會有命令更換層級的問題 (比方 AA 本來是第二層, 又換到第三層). 這個詭異的方式是可以解決你的問題 (如果是 C# 會有兩種詭異的方式)

    這個方式的基底類別有個唯讀的 Result 屬性, 用來取得最後的結果. 以下繼承的每個類別內的方法回傳型別為該類別的父代, 就會有你要的結果. (但真的很怪 .....)

    Public Class CommandResult
        Sub New()
            _result = String.Empty
        End Sub
    
        Protected _result As String
    
        Public ReadOnly Property Result As String
            Get
                Return _result
            End Get
    
        End Property
    
    End Class
    
    Public Class CommandLevel3
        Inherits CommandResult
        Public Function AAA() As CommandResult 
            _result &= "探病"
            Return DirectCast(Me, CommandResult)
        End Function
        Public Function BBB() As CommandResult
            _result &= "讀書"
            Return DirectCast(Me, CommandResult)
        End Function
        Public Function CCC() As CommandResult
            _result &= "購物"
            Return DirectCast(Me, CommandResult)
        End Function
    End Class
    
    Public Class CommandLevel2
        Inherits CommandLevel3
    
    
        Public Function AA() As CommandLevel3
            _result &= "去醫院"
            Return DirectCast(Me, CommandLevel3)
        End Function
        Public Function BB() As CommandLevel3
            _result &= "去學校"
            Return DirectCast(Me, CommandLevel3)
        End Function
        Public Function CC() As CommandLevel3
            _result &= "去商店"
            Return DirectCast(Me, CommandLevel3)
        End Function
    End Class
    
    
    Public Class CommandLevel1
        Inherits CommandLevel2
    
    
        Public Function A() As CommandLevel2
            _result &= "我"
            Return DirectCast(Me, CommandLevel2)
        End Function
        Public Function B() As CommandLevel2
            _result &= "你"
            Return DirectCast(Me, CommandLevel2)
        End Function
        Public Function C() As CommandLevel2
            _result &= "他"
            Return DirectCast(Me, CommandLevel2)
        End Function
    End Class


    在現實生活中,你和誰在一起的確很重要,甚至能改變你的成長軌跡,決定你的人生成敗。 和什麼樣的人在一起,就會有什麼樣的人生。 和勤奮的人在一起,你不會懶惰; 和積極的人在一起,你不會消沈; 與智者同行,你會不同凡響; 與高人為伍,你能登上巔峰。


    2015年5月7日 上午 09:03
    版主
  • 最後在客戶端呼叫的方式, (因為我貼在上一篇一直出包, 只好另外貼一篇)
      Dim x As New CommandLevel1()
      Dim result As String = x.A().AA().CCC().Result
       Console.WriteLine(result)
       Console.ReadLine()


    在現實生活中,你和誰在一起的確很重要,甚至能改變你的成長軌跡,決定你的人生成敗。 和什麼樣的人在一起,就會有什麼樣的人生。 和勤奮的人在一起,你不會懶惰; 和積極的人在一起,你不會消沈; 與智者同行,你會不同凡響; 與高人為伍,你能登上巔峰。

    2015年5月7日 上午 09:04
    版主
  • 看了一下Bill前輩的回覆~

    並試了一下~發現幾點問題

    1.功能很完美~因為選完第一層後,繼續選第二層時已經看不到第一層的命令了
      讚~^^

    2.我發現怪怪的寫法,是因為需達成上面的隱藏效果所以才必須"倒著"寫嗎?
      我會說倒著是因為以我來說,我一定會想先規劃好第一層的,然後第2層的再繼承
      我一定是這樣思考啦,因為命令的順序就是這樣,而看到Bill前輩的寫法,
      確是先規劃最後一層,之後再讓前一層繼承,倒著思考!
      妙,沒陷在命令順序的圈套中.所以,是因為要達成"屏蔽"前一層的命令才這樣規劃嗎?
     
    3.對於空字串的定義  String.Empty
      有查一下跟我慣用 "" 的差異
      對方也是建議使用  String.Empty,因為比起"" 更直白了~

      http://www.dotblogs.com.tw/larrynung/archive/2009/03/13/7461.aspx
      http://www.dotblogs.com.tw/larrynung/archive/2009/12/22/12615.aspx


    後續是我的問題了,許多不足的地方必須補好 例如 繼承 這塊~
    光看到Bill前輩這樣用就讓我嚇到了,

    總之,非常感謝各位指導的前輩願意撥空回覆訊息~^^

     

     

    2015年5月8日 上午 12:55
  • (1) 倒著寫的原因是基於繼承鏈的道理一定是基底類別的職責最少, 然後往衍生類別的增加 (所以衍生類別的公開職責會等於或大於其基底類別) . 

    (2) 繼承是件很可怕的事. 通常剛寫 OOP 的人會很愛用繼承, 最後就會濫用, 一般情形一定是優先考慮組合(聚合).

    (3) 我說怪的原因並不是倒過來, 而是這個寫法其實違反了 "倚賴倒置原則 DIP" . 雖然沒規定原則一定不能違反 (事實上有些設計模式還是會違反某些原則), 只是我自己看來還是怪怪的, 但你的情境不得不如此寫.  


    在現實生活中,你和誰在一起的確很重要,甚至能改變你的成長軌跡,決定你的人生成敗。 和什麼樣的人在一起,就會有什麼樣的人生。 和勤奮的人在一起,你不會懶惰; 和積極的人在一起,你不會消沈; 與智者同行,你會不同凡響; 與高人為伍,你能登上巔峰。

    2015年5月8日 上午 04:12
    版主
  • 我自己的最簡易繼承觀念

    「父類別無法使用子類別的方法,子類別可以使用/覆寫(override)父類別的方法」

    所以若由上而下Level1 -> Level2 -> Level3就無法隱藏父類別的東西

    由下而上

    Level3(所有可見)->Level2(無法使用Level3)->Level1(無法使用Level2 & Level3)

    才可以做到隱藏你不想要的方法

    2015年5月8日 上午 06:18
  • 我想起來忘了講一件事

    那個 Return  DirectCast(Me, ...) 其實可以直接寫成 Return Me , 因為方法的回傳型別已經限制住了, 所以用 Return  Me 會隱含轉型.

    只是我有個喜歡自己寫清楚這一段的毛病. 算是某種強迫症.


    在現實生活中,你和誰在一起的確很重要,甚至能改變你的成長軌跡,決定你的人生成敗。 和什麼樣的人在一起,就會有什麼樣的人生。 和勤奮的人在一起,你不會懶惰; 和積極的人在一起,你不會消沈; 與智者同行,你會不同凡響; 與高人為伍,你能登上巔峰。



    2015年5月8日 上午 11:17
    版主