Search code examples
c#generalization

How can I make a function that loops over a list and takes which data member to access as input parameter


I have a datatype PlayerStats which contains a lot of different data members. I want to calculate a score which is different for each data member (the case below looks at statistics.nrOfGoals).

private double getScore()
{
    double strength = 0;
    foreach (PlayerStats statistics in this.statistics)
    {
        double dateDiff = Math.Abs(nowDate.Subtract(statistics.date).Days / (365.25 / 12));
        dateDiff = Math.Pow(dateDiff, Form1.historyFactor);

        strength += (statistics.nrOfGoals * ValueTable.PointsPerGoals   ) / dateDiff;
    }

    return strength;
}

How can I make this function general and accept which datamember to look at instead of creating a lot of similar looking functions?

Something like

private double getScore(Type type, Type type2)
{
    double strength = 0;
    foreach (PlayerStats statistics in this.statistics)
    {
        double dateDiff = Math.Abs(nowDate.Subtract(statistics.date).Days / (365.25 / 12));
        dateDiff = Math.Pow(dateDiff, Form1.historyFactor);

        strength += (statistics.type * ValueTable.type2) / dateDiff;
    }

    return strength;
}

Solution

  • You can give a function as a parameter with signature PlayerStats -> Double:

    private double getScore(Func<PlayerStats,double> type, double type2)
    {
        double strength = 0;
        foreach (PlayerStats statistics in this.statistics)
        {
            double dateDiff = Math.Abs(nowDate.Subtract(statistics.date).Days / (365.25 / 12));
            dateDiff = Math.Pow(dateDiff, Form1.historyFactor);
    
            strength += (type(statistics) * type2) / dateDiff;
        }
    
        return strength;
    }
    

    And then call it with:

    getScore(x => x.nrOfGoals,ValueTable.PointsPerGoals);
    

    x => x.nrOfGoals is a lambda-expression that defines some kind of function that (in this case) takes as input a PlayerStats instance and returns a double.

    In the code, you can then see type as a "function"/"method" and call it with type(y) (with y a PlayerStats instance).