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

cen*_*cru 4 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;
    }
Run Code Online (Sandbox Code Playgroud)

Tim*_*mwi 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;
}
Run Code Online (Sandbox Code Playgroud)

我删除了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);
Run Code Online (Sandbox Code Playgroud)


Mar*_*ell 6

我会使用一个界面,如:

public interface ITemplate
{
    string TemplateId { get; }
}
Run Code Online (Sandbox Code Playgroud)

明确实施:

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; } }
}
Run Code Online (Sandbox Code Playgroud)

然后我可以写一个通用的扩展方法来处理任何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;
    }
}
Run Code Online (Sandbox Code Playgroud)

最后,代理这些方法:

public QualTemplate FindQualTemplate(string templateID)
{
    return QualTemplates.Find(templateID);
}
public UnitTemplate FindUnitTemplates(string templateID)
{
    return UnitTemplates.Find(templateID);
}
Run Code Online (Sandbox Code Playgroud)

如果要避免使用界面,可以使用选择器:

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;
}
Run Code Online (Sandbox Code Playgroud)