2010-10-14 65 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; 
} 
相关问题