2011-03-22 101 views
3

最近我發現自己編寫的方法會連續調用其他方法,並根據哪個方法首先返回適當的值來設置某個值。我一直在做的是用一種方法設定數值,然後檢查數值,如果數值不好,我檢查下一個數值。這裏有一個最近的例子:返回工作的第一種方法,更優雅的方式?

private void InitContent() 
{ 
    if (!String.IsNullOrEmpty(Request.QueryString["id"])) 
    { 
     Content = GetContent(Convert.ToInt64(Request.QueryString["id"])); 
     ContentMode = ContentFrom.Query; 
    } 

    if (Content == null && DefaultId != null) 
    { 
     Content = GetContent(DefaultId); 
     ContentMode = ContentFrom.Default; 
    } 

    if (Content == null) ContentMode = ContentFrom.None; 
} 

這裏GetContent方法應該返回null如果id是不是在數據庫中。這是一個簡短的例子,但你可以想象如果有更多的選擇,這可能會變得笨重。有一個更好的方法嗎?

+0

爲什麼ContentMode類「內容」的不是財產?如果您將其作爲「內容」類的一部分,則代碼可能更短,更易讀。而且您不需要ContentFrom.None枚舉,因爲NULL內容對象將替換該枚舉的邏輯。 – SolutionYogi 2011-03-23 03:56:02

+0

因爲「內容」來自第三方API。我必須爲這個項目使用一個......我想我可以嘗試把它包裝起來,就像這裏的其他建議一樣。 – Andy 2011-03-24 15:53:22

回答

1

我建議你在這種情況下嘗試某種工廠設計模式。您可以通過註冊不同的創作者來抽象內容創建過程。此外,您可以爲每個創建者添加自己的邏輯偏好。此外,我建議您將與Content相關的所有數據封裝爲與其他帖子中的「ContentDefinition」類相似的內容。

一般來說,您需要知道靈活性和效率之間總是存在折衷。有時候你的第一個解決方案已經足夠好了:)

9

空合併運算符可能具有所需的語義。

q = W() ?? X() ?? Y() ?? Z(); 

這是本質一樣:

if ((temp = W()) == null && (temp = X()) == null && (temp == Y()) == null) 
    temp = Z(); 
q = temp; 

也就是說,Q是第一個非空W(),X(),Y()的,或者,如果所有的人都爲空,那麼Z()。

您可以儘可能多地鏈鎖。

確切的語義不像我勾勒出來;類型轉換規則很棘手。如果您需要確切的細節,請參閱規格。

2

就我個人而言,當我發現很多看起來不同的陳述時,是時候做出一些功能了。

private ContentMode GetContentMode(){ 
} 

private Content GetContent(int id){ 
} 

private Content GetContent(HttpRequest request){ 
    return GetContent(Convert.ToInt64(request.QueryString["id"])); 
} 

private void InitContent(){ 
    ContentMode mode = GetContentMode(); 
    Content = null; 
    switch(mode){ 
    case ContentMode.Query: 
     GetContent(Request); 
     break; 
    case ContentMode.Default: 
     GetContent(DefaultId); 
     break; 
    case ContentMode.None: 
     ... handle none case... 
     break; 

    } 
} 

這樣,你分開你的意圖 - 第一步,確定內容模式。然後,獲取內容。

+0

不幸的是,如果不先知道它的工作原理,我將無法確定ContentMode,否則我可能會這樣做。 – Andy 2011-03-22 23:51:14

0
private void InitContent() 
{ 
    Int64? id = !String.IsNullOrEmpty(Request.QueryString["id"]) 
       ? Convert.ToInt64(Request.QueryString["id"]) 
       : null; 

    if (id != null && (Content = GetContent(id)) != null) 
     ContentMode = ContentFrom.Query; 
    else if(DefaultId != null && (Content = GetContent(DefaultId)) != null) 
     ContentMode = ContentFrom.Default; 
    else 
     ContentMode = ContentFrom.None; 
} 
3

你也可以做一些稍微偷偷摸摸的,沿着這個線路:

private Int64? GetContentIdOrNull(string id) 
{ 
    return string.IsNullOrEmpty(id) ? null : (Int64?)Convert.ToInt64(id); 
} 

private Int64? GetContentIdOrNull(DefaultIdType id) 
{ 
    return id; 
} 

private void InitContent() 
{ 
    // Attempt to get content from multiple sources in order of preference 

    var contentSources = new Dictionary<ContentFrom, Func<Int64?>> { 
     { ContentFrom.Query, () => GetContentIdOrNull(Request.QueryString["id"]) }, 
     { ContentFrom.Default,() => GetContentIdOrNull(DefaultId) } 
    }; 

    foreach (var source in contentSources) { 
     var id = source.Value(); 
     if (!id.HasValue) { 
      continue; 
     } 

     Content = GetContent(id.Value); 
     ContentMode = source.Key; 

     if (Content != null) { 
      return; 
     } 
    } 

    // Default 
    ContentMode = ContentFrom.None; 
} 

,如果你有更多的資源,以增加複雜性爲代價這將有助於。

+0

除此之外,如果第一個方法不起作用,則不能解決需要嘗試其他方法的問題。 – Andy 2011-03-23 00:05:11

+0

@安迪:恩,是的,這就是整個問題。它以什麼方式不起作用? – Cameron 2011-03-23 00:14:55

+0

@安迪:*哦*我完全誤讀了您的示例代碼,對不起。讓我解決我的問題... – Cameron 2011-03-23 00:18:42

1

好的,因爲我注意到你實際上想要ContentFrom模式有點晚了,我盡了最大努力想出了你的示例在我的原始版本下的翻譯版本回答


在一般情況下,我使用下面的範例這樣的情況。搜索和替換這裏的具體方法和那裏:)

IEnumerable<T> ValueSources() 
{ 
    yield return _value?? _alternative; 
    yield return SimpleCalculationFromCache(); 
    yield return ComplexCalculation(); 
    yield return PromptUIInputFallback("Please help by entering a value for X:"); 
} 

T EffectiveValue { get { return ValueSources().FirstOrDefault(v => v!=null); } } 

注意你怎麼能現在做v!=null任意適合您的需要「有趣」。

注意評價怎麼也懶可以確保_alternative設置爲「有趣」的計算是從來沒有做過當_value或值


這是我在把你的樣品放入該模具的初步嘗試。注意:我如何加入了很多管道,以確保這實際上編譯成獨立的C#EXE:

using System.Collections.Generic; 
using System.Linq; 
using System; 
using T=System.String; 

namespace X { public class Y 
{ 
    public static void Main(string[]args) 
    { 
     var content = Sources().FirstOrDefault(c => c); // trick: uses operator bool() 
    } 

    internal protected struct Content 
    { 
     public T Value; 
     public ContentFrom Mode; 
     // 
     public static implicit operator bool(Content specimen) { return specimen.Mode!=ContentFrom.None && null!=specimen.Value; } 
    } 

    private static IEnumerable<Content> Sources() 
    { 
     // mock 
     var Request = new { QueryString = new [] {"id"}.ToDictionary(a => a) }; 

     if (!String.IsNullOrEmpty(Request.QueryString["id"])) 
      yield return new Content { Value = GetContent(Convert.ToInt64(Request.QueryString["id"])), Mode = ContentFrom.Query }; 
     if (DefaultId != null) 
      yield return new Content { Value = GetContent((long) DefaultId), Mode = ContentFrom.Default }; 
     yield return new Content(); 
    } 

    public enum ContentFrom { None, Query, Default }; 
    internal static T GetContent(long id) { return "dummy"; } 
    internal static readonly long? DefaultId = 42; 

} } 
相關問題