2010-06-23 44 views
3

我從來沒有想過我需要這個東西(因爲宏是壞,對吧?)的功能,但事實證明,我做。宏狀結構== == OR如何分解出含有「迴歸」

,我發現自己在我的代碼一遍又一遍地重複以下模式再次,數十如果不是數百次:

object Function() { 
    this.Blah = this.Blah.Resolve(...); 
    if(this.Blah == null) 
     return null; 
    if(this.Blah.SomeFlag) 
     return this.OtherFunction(); 

    // otherwise, continue processing... 
} 

我想寫這樣的事情,而不是:

object Function() { 
    this.Blah = this.Blah.Resolve(...); 
    VerifyResolve(this.Blah); 

    // continue processing... 
} 

除了該模式包含條件return的事實意味着我不能分解出一個函數。我不得不巧妙地改變這個模式,因爲我不能做一個簡單的搜索,所以找到所有的實例是一件很痛苦的事情。

我怎樣才能避免重複自己不必要,並使這種模式更容易的任何未來的變化?

回答

1

你可以這樣說:

object Function() 
{ 
    this.Blah = this.Blah.Resolve(...); 
    object rc; 
    if (!VerifyResolve(out rc) 
     return rc; 

    // continue processing... 
} 

bool VerifyResolve(out object rc) 
{ 
    if(this.Blah == null)  
    { 
     rc = null; 
     return true; 
    } 
    if(this.Blah.SomeFlag)  
    { 
     rc = this.OtherFunction(); 
     return true; 
    } 
    rc = null; 
    return false; 
} 
+0

這是混亂,討厭,和冗長,但這是我不得不去的。可能沒有更好的方法。 – zildjohn01 2010-07-05 12:10:52

0

最好是同時能延長與VerifyResolve extantion方法布拉赫類。 如果您擁有Blah源碼,那麼創建一些IVerifyResolveble接口並讓Blah執行它可能會更好。

0
object Function() { 
    this.Blah = this.Blah.Resolve(...); 
    object result; 
    if (VerifyResolve(this.Blah, out result)) 
     return result; 

    // continue processing... 
} 
3

如果你經常發現你必須覈查null您可能需要使用Null Object Pattern。基本上,你創建一個表示空結果的對象。然後您可以返回此對象而不是null。然後您必須修改剩餘的代碼以包含null對象的行爲。這些方針的東西可能:

MyClass Function() 
{ 
    this.Blah = this.Blah.Resolve(...); 
    VerifyResolve(this.Blah); 

    // continue processing... 
} 

MyClass VerifyResolve(MyClass rc) 
{ 
    // ... 
    return rc.Blah.SomeFlag ? rc.OtherFunction() : rc; 
} 

NullMyClass : MyClass { 
    public override bool SomeFlag { get { return false; } } 
} 
+0

不錯的想法,但在這種情況下'null'是安全使用的,並且是'Resolve'設計的一部分。 – zildjohn01 2010-06-23 09:43:12

1

也許更簡潔:

if (!TryResolve(this.Blah)) return this.Blah; 

其中TryResolve設置this.Blah爲null或this.OtherFunction的值,並返回相應的布爾

+0

你不需要通過this.blah作爲ref或out參數,否則你只會設置傳遞給TryResolve的方法參數的引用,而不是this.Blah本身... – 2010-06-23 09:29:53

+0

是的,一點點愚蠢 – Yellowfog 2010-06-23 09:33:11

+0

非常好,除了我不想'this.Blah'覆蓋,當我想要返回。儘管如此,你還是爲了簡單而去+1。我厭倦了這些20行C#解決方案,它們在其他語言中都是2或3行...... – zildjohn01 2010-06-23 09:55:09

1

沒有進攻但有幾個代碼的氣味在那裏:

this.Blah = this.Blah.Resolve(...); 

這條線特別拉爾會讓我開始重新思考的過程。

我有問題的主要問題是對象返回類型和屬性,以通過調用該屬性的方法返回一個值的分配。這些都讓人覺得你在某個地方弄糟了繼承,最終導致了一個嚴重的狀態系統,這個系統既是一個測試者,也是一個需要維護的痛苦。

也許最好是重新思考,而不是試圖用黑客和技巧來回避這個問題:我通常會發現,如果我試圖用像宏一樣的功能來濫用語言,那麼我的設計需要工作!

編輯

好了,添加了信息也許這與其說是臭的,但我還是建議如下:

class ExampleExpr{ 
    StatefulData data ... // some variables that contain the state data 
    BladhyBlah Blah { get; set; } 

    object Function(params) { 
     this.Blah = this.Blah.Resolve(params); 
     .... 
    } 
} 

此代碼是令人擔憂的,因爲它迫使完全基於狀態的方法,產出取決於事先發生的情況,因此需要採取特定步驟進行復制。這是一個很難測試的問題。另外,如果你調用Function()兩次,不能保證Blah會發生什麼,而不知道它在什麼狀態。

class ExampleExpr{ 
    StatefulData data ... // some variables that contain the state data 

    object Function(params) { 
     BlahdyBlah blah = BlahdyBlah.Resolve(params, statefulData); 
    } 
} 

如果我們使用後廠式的方法,而不是,返回與每當我們都帶有一組特定的參數的特定信息的新實例,我們已經消除了一個地方,使用狀態數據(即BladhyBlah實例現在每次調用時都會重新創建一個特定的參數集)。

這意味着我們可以在測試中複製任何功能,只需使用特定的Setup()函數調用Function(params)來創建statefulData和一組特定的參數。

從理論上講,這樣做效率不高(因爲每個工廠調用都會創建一個新的BlahdyBlah),但可以使用特定數據緩存BlahdyBlah的實例並在工廠調用之間共享它們(假設它們沒有其他影響他們的內部狀態)。但是,它更加易於維護,從測試的角度來看,它完全支持有狀態數據的流氓行爲。

這也有助於消除原來的問題,因爲當我們不依賴於內部實例變量我們都可以解決(參數,可以statefulData)從外部功能(PARAMS),根本不叫如果任一功能(PARAMS) blah == null或blah.SomeFlag == SomeFlag.Whatever。因此,通過將這種方法移到外面,我們不再需要擔心收益。

希望這是在正確的場地的某個地方,很難確切地知道推薦給出一個小例子的建議,正如通常在這裏的困難/抽象問題的情況。

+0

有趣的想法......這就是我在做的事情。我正在編寫一個編譯器,並解析表達式。每個表達式都會返回自身,或者返回一個表達式來替換自己(或者出於性能原因,爲避免出現異常,則返回null)。例如,在'IdentifierExpr'上調用'Resolve'可能會導致'SymbolExpr'引用一個變量。你認爲這種設計是否有代碼味道? – zildjohn01 2010-06-23 09:46:57

+0

另外,實際的返回類型不是'object',我只是將它用於片段目的。真正的返回類型是「Expr」。 (如果可能的話,我總是避免像'瘟疫'這樣的對象') – zildjohn01 2010-06-23 09:51:55

+0

@ zildjohn01這兩個obj用於演示的目的和返回null的錯誤處理是有意義的(可能應該在Q中提及,但我的壞推斷)。我仍然認爲使用this.x = this.x.blah有點奇怪,就像手動修改對象訪問者風格的狀態一樣。也許某種靜態包裝,允許你通過分配一個局部變量去除重新分配,從設計的角度來看會更好?如果沒有關於其他代碼的好主意,我會厭惡提出任何具體的改進,但作爲一個規則,副作用=>不好。 – 2010-06-23 10:24:17

0

這是混亂,討厭,和詳細,但這是我不得不去與。可能沒有更好的方法。

另一種方法是製作一個結構,它的可空性很重要。

struct Rc 
{ 
    internal object object; 
    internal Rc(object object) { this.object = object; } 
} 

object Function() 
{ 
    this.Blah = this.Blah.Resolve(...); 
    Rc? rc = VerifyResolve(); 
    if (rc.HasValue) 
     return rc.Value.object; 

    // continue processing... 
} 

Rc? VerifyResolve() 
{ 
    if(this.Blah == null)  
    { 
     return new Rc(null); 
    } 
    if(this.Blah.SomeFlag)  
    { 
     return new Rc(this.OtherFunction()); 
    } 
    return null; 
}