如何使用c#generics重写这两个几乎相同的函数?

时间:2010-10-14 11:41:41

标签: c# generics

我有两个几乎相同的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;
    }

5 个答案:

答案 0 :(得分: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);

答案 1 :(得分: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; } }
}

然后我可以编写一个通用扩展方法来处理任何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;
}

答案 2 :(得分: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;
}

答案 3 :(得分:1)

这不容易实现。 UnitTemplates和QualTemplates需要实现相同的接口,或者具有暴露您正在使用的成员的相同基类,QualTemplate和UnitTemplate也是如此。即便如此,您还需要将工厂传递给方法(例如UnitTemplates作为参数),并且您需要在外部的单个调用中指定您使用的谓词(因为ID属性名称不同)。

答案 4 :(得分: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()));