2010-10-14 110 views
4

我有兩個幾乎完全相同的c#函數。因爲他們非常相似,所以我想我會試用泛型,但我很難理解如何去做。任何建議,還是我完全吠叫錯誤的樹?如何使用c#泛型重寫這兩個幾乎相同的函數?

public IList<UnitTemplate> UnitTemplates { get; set; } 
    public IList<QualTemplate> QualTemplates { get; set; } 

    public QualTemplate FindQualTemplate(string templateID) 
    { 
     QualTemplate selectedQualTemplate; 
     if (QualTemplates.Count == 0) 
      throw new CreatioException("This user's brand has no QualTemplates. There must be at least one available."); 
     if (QualTemplates.Count == 1 || String.IsNullOrEmpty(templateID)) 
      selectedQualTemplate = QualTemplates.First(); 
     else 
      selectedQualTemplate = QualTemplates.Single(x => x.QualTemplateID.ToLower() == templateID.ToLower()); 
     if (selectedQualTemplate == null) 
      throw new CreatioException(String.Format("No QualTemplate with the id {0} could be found for this user's brand.", templateID)); 
     return selectedQualTemplate; 
    } 

    public UnitTemplate FindUnitTemplates(string templateID) 
    { 
     UnitTemplate selectedTemplate; 
     if (UnitTemplates.Count == 0) 
      throw new CreatioException("This user's brand has no UnitTemplates. There must be at least one available."); 
     if (UnitTemplates.Count == 1 || String.IsNullOrEmpty(templateID)) 
      selectedTemplate = UnitTemplates.First(); 
     else 
      selectedTemplate = UnitTemplates.Single(x => x.UnitTemplateID.ToLower() == templateID.ToLower()); 
     if (selectedTemplate == null) 
      throw new CreatioException(String.Format("No UnitTemplate with the id {0} could be found for this user's brand.", templateID)); 
     return selectedTemplate; 
    } 
+3

與你的問題無關,但我認爲你應該使用'x.QualTemplateID.Equals(templateID,StringComparison.OrdinalIgnoreCase)'而不是'ToLower'。 – Timwi 2010-10-14 12:01:52

+0

感謝提示,Timwi! – centralscru 2010-10-14 13:13:33

回答

8

您遇到的問題是兩種方法都使用兩種類型不具有的屬性:QualTemplateIDUnitTemplateID。如果你可以進行以下修改的代碼結構:

  • 申報UnitTemplateQualTemplate從公共基類派生,Template

  • 在這種基本類型,聲明屬性TemplateID

  • 擺脫QualTemplateIDUnitTemplateID並使用繼承的TemplateID屬性代替

那麼你可以寫一般的方法:

public TTemplate FindTemplates<TTemplate>(
    IList<TTemplate> templates, string templateID) 
    where TTemplate : Template 
{ 
    TTemplate selectedTemplate; 
    if (templates.Count == 0) 
     throw new CreatioException("This user's brand has no template. There must be at least one available."); 
    if (templates.Count == 1 || String.IsNullOrEmpty(templateID)) 
     selectedTemplate = templates.First(); 
    else 
     selectedTemplate = templates.Single(x => x.TemplateID.ToLower() == templateID.ToLower()); 
    return selectedTemplate; 
} 

我已經刪除了if (selectedTemplate == null),因爲它永遠不會無論如何火(除非列出的是可能包含空值,但隨後的謂詞傳遞給Single會崩潰了...)。

上述方法同樣適用,如果您將其設置爲接口而不是基本類型。

如果無法進行更改,我描述的代碼,那麼你唯一的選擇是通過(作爲一個參數)檢索ID的委託:

public TTemplate FindTemplates<TTemplate>(
    IList<TTemplate> templates, string templateID, 
    Func<TTemplate, string> templateIdGetter) 
{ 
    TTemplate selectedTemplate; 
    if (templates.Count == 0) 
     throw new CreatioException("This user's brand has no template. There must be at least one available."); 
    if (templates.Count == 1 || String.IsNullOrEmpty(templateID)) 
     selectedTemplate = templates.First(); 
    else 
     selectedTemplate = templates.Single(x => templateIdGetter(x).ToLower() == templateID.ToLower()); 
    return selectedTemplate; 
} 

var qTempl = FindTemplates(QualTemplates, "myTemplateId", q => q.QualTemplateID); 
var uTempl = FindTemplates(UnitTemplates, "myTemplateId", u => u.UnitTemplateID); 
+0

非常棒的答案,Timwi。非常感謝!我可以改變代碼,看起來很整潔。 – centralscru 2010-10-14 13:12:10

1

這並不容易。 UnitTemplates和QualTemplates需要實現相同的接口,或者使用相同的基類來公開正在使用的成員,並且QualTemplate和UnitTemplate也是如此。即使如此,您仍然需要通過工廠才能使用該方法(例如UnitTemplates作爲參數),並且您需要在外部調用Single調用時指定您使用的謂詞(因爲ID屬性名稱不同)。

6

我會用一個接口,像:

public interface ITemplate 
{ 
    string TemplateId { get; } 
} 

有明確的執行:

public class UnitTemplate : ITemplate { 
    public string UnitTemplateID { get; set; } 
    string ITemplate.TemplateId { get { return UnitTemplateID; } } 
} 
public class QualTemplate : ITemplate 
{ 
    public string QualTemplateID { get; set; } 
    string ITemplate.TemplateId { get { return QualTemplateID; } } 
} 

然後,我可以寫一個根兒IC擴展方法來處理這對於任何T

public static class TemplateExtensions 
{ 
    public static T Find<T>(this ICollection<T> templates, string templateID) where T : ITemplate 
    { 
     T selectedTemplate; 
     if (templates.Count == 0) 
      throw new CreatioException("This user's brand has no templates. There must be at least one available."); 
     if (templates.Count == 1 || String.IsNullOrEmpty(templateID)) 
      selectedTemplate = templates.First(); 
     else 
      selectedTemplate = templates.Single(x => x.TemplateId.ToLower() == templateID.ToLower()); 
     if (selectedTemplate == null) 
      throw new CreatioException(String.Format("No template with the id {0} could be found for this user's brand.", templateID)); 
     return selectedTemplate; 
    } 
} 

最後,代理這些方法:

public QualTemplate FindQualTemplate(string templateID) 
{ 
    return QualTemplates.Find(templateID); 
} 
public UnitTemplate FindUnitTemplates(string templateID) 
{ 
    return UnitTemplates.Find(templateID); 
} 

如果你想避免的界面,你可以使用一個選擇,而不是:

public QualTemplate FindQualTemplate(string templateID) 
{ 
    return Find(QualTemplates, templateID, x => x.QualTemplateID); 
} 
public UnitTemplate FindUnitTemplates(string templateID) 
{ 
    return Find(UnitTemplates, templateID, x => x.UnitTemplateID); 
} 
static T Find<T>(ICollection<T> templates, string templateID, Func<T, string> selector) 
{ 
    T selectedTemplate; 
    if (templates.Count == 0) 
     throw new CreatioException("This user's brand has no templates. There must be at least one available."); 
    if (templates.Count == 1 || String.IsNullOrEmpty(templateID)) 
     selectedTemplate = templates.First(); 
    else 
     selectedTemplate = templates.Single(x => selector(x).ToLower() == templateID.ToLower()); 
    if (selectedTemplate == null) 
     throw new CreatioException(String.Format("No template with the id {0} could be found for this user's brand.", templateID)); 
    return selectedTemplate; 
} 
+0

非常感謝您的詳細解答 - 確實非常有幫助。 – centralscru 2010-10-14 13:12:36

0

這將是我可以看到的最簡單的解決方案,如果您願意,甚至可以將其作爲擴展方法來執行想。 (如果你不只是消除靜電和這片)

public static class Extension { 

    public static T FindTemplates<T>(this IList<T> list, string templateID, Func<string,T> selector) 
     { 
     T selectedTemplate; 
     if (list.Count == 0){ 
      throw new CreationException("This user's brand has no UnitTemplates. There must be at least one available."); 
     } 
     if (list.Count == 1 || String.IsNullOrEmpty(templateID)){ 
      selectedTemplate = list.First(); 
     } 
     else{ 
      selectedTemplate = selector(templateID); 
     } 
     if (selectedTemplate == null){ 
      throw new CreationException(String.Format("No UnitTemplate with the id {0} could be found for this user's brand.", templateID)); 
     } 
     return selectedTemplate; 
    } 
    } 

然後用法是這樣的:

IList<UnitTemplate> test = new List<UnitTemplate>(); 
UnitTemplate t = test.FindTemplates("id", (string x) => test.Single(y => y.UnitTemplateID.ToLower() == x.ToLower())); 
+1

請解釋什麼是錯的...因爲它的工作原理。 – Nix 2010-10-14 12:06:56

+0

我同意最好的方法是提取一個像@Timwi提到的基類型。但是,這是一種不需要改變任何東西的替代方法。 – Nix 2010-10-14 12:52:05

3

您可以使用FUNC:

public IList<UnitTemplate> UnitTemplates { get; set; } 
public IList<QualTemplate> QualTemplates { get; set; } 

public QualTemplate FindQualTemplate(string templateID) 
{ 
    return FindTemplatesImpl(templateID, x => x.QualTemplateID, QualTemplates); 
} 

public UnitTemplate FindUnitTemplates(string templateID) 
{ 
    return FindTemplatesImpl(templateID, x => x.UnitTemplateID, UnitTemplates); 
} 

public T FindTemplatesImpl<T>(string templateID, Func<T, string> expr, IList<T> templates) 
{ 
    T selectedTemplate; 
    if (templates.Count == 0) 
     throw new CreatioException("This user's brand has no Templates. There must be at least one available."); 

    if (templates.Count == 1 || String.IsNullOrEmpty(templateID)) 
     selectedTemplate = templates.First(); 
    else 
     selectedTemplate = templates.Single(x => expr(x).ToLower() == templateID.ToLower()); 

    if (selectedTemplate == null) 
     throw new CreatioException(String.Format("No UnitTemplate with the id {0} could be found for this user's brand.", templateID)); 

    return selectedTemplate; 
} 
相關問題