Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I rewrite these two almost identical functions using c# generics?

Tags:

c#

generics

I have two almost identical c# functions. Because they're so similar I thought I'd try out generics, but I'm stumped on how to do it. Any suggestions, or am I barking up the wrong tree entirely?

    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;
    }
like image 684
centralscru Avatar asked Dec 02 '22 04:12

centralscru


1 Answers

The problem you have is that both methods use a property which the two types don’t have in common: QualTemplateID and UnitTemplateID. If you can make the following changes to the code structure:

  • Declare UnitTemplate and QualTemplate to derive from a common base type, Template

  • In that base type, declare a property TemplateID

  • Get rid of QualTemplateID and UnitTemplateID and use the inherited TemplateID property instead

then you can write the method generically:

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;
}

I’ve removed the if (selectedTemplate == null) because it would never fire anyway (unless the list is likely to contain nulls, but then the predicate you pass to Single would crash...).

The above works equally well if you make it an interface instead of a base type.

If you cannot make the changes to the code that I described, then your only option is to pass (as a parameter) a delegate that retrieves the 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);
like image 74
Timwi Avatar answered Dec 26 '22 12:12

Timwi