Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I pass a property of a class as a parameter of a method?

Tags:

c#

lambda

I have a class that has a dozen or so properties that represent various financial fields. I have another class that needs to perform some calculations on each of those fields separately. The code inside those calculation methods are identical except for the field that it does the calculation on.

Is there a way that I can pass a property name as a parameter and just have one method that does all of the performing work instead of the 12 methods for each property?

Also, I'm sure this can be accomplished via reflection, but I've seen in other code where lambdas are used in this same kind of fashion and was wondering if this is a candidate where this can be used.

As requested, here is an example:

public class FinancialInfo
{
    public virtual DateTime AuditDate { get; set; }
    public virtual decimal ReleasedFederalAmount { get; set; }
    public virtual decimal ReleasedNonFederalAmount { get; set; }
    public virtual decimal ReleasedStateAmount { get; set; }
    public virtual decimal ReleasedLocalAmount { get; set; }
    public virtual decimal ReleasedPrivateAmount { get; set; }
    // more fields like this
}

public class FinancialLedger()
{
    public virtual DateTime? BeginDate { get; set; }
    public virtual DateTime? EndDate { get; set; }
    public virtual IList<FinancialInfo> Financials { get; set; } //not actual implementation, but you get the idea
    public decimal GetTotalReleasedFederalAmountByDate()
    {
        if (BeginDate == null && EndDate == null)
            return 0;
        decimal total = 0;
        foreach (var fi in Financials)
        {
            if (someCondition)
                if (someSubCondition)
                    total += fi.ReleasedFederalAmount;
            else if (someOtherCondition)
                if (someOtherSubCondition)
                    total += fi.ReleasedFederalAmount;
            else if (anotherCondigion)
                total += fi.ReleasedFederalAmount;
        }
        return total;
    }
    public decimal GetTotalReleasedNonFederalAmountByDate()
    {
        // same logic as above method, 
        // but it accesses fi.ReleasedNonFederalAmount;
    }
    // More methods the same as the previous, just accessing different
    // members of FinancialInfo
}

My goal is to just make one method called GetTotalAmountByDate() and pass in a begin date, and end date and the name of the property (ReleasedFederalAmount or ReleasedLocalAmount, etc.) it needs to access.

I hope this depicts accurately what I'm trying to accomplish.

like image 212
Chris Conway Avatar asked Jul 24 '09 15:07

Chris Conway


People also ask

In what way can you pass parameters to a method?

Parameters can be passed to a method in following three ways : Value Parameters. Reference Parameters. Output Parameters.

How to pass parameter in C#?

In C#, arguments can be passed to parameters either by value or by reference. Remember that C# types can be either reference types ( class ) or value types ( struct ): Pass by value means passing a copy of the variable to the method. Pass by reference means passing access to the variable to the method.

What are parameters in a method?

Note: Parameters refers to the list of variables in a method declaration. Arguments are the actual values that are passed in when the method is invoked. When you invoke a method, the arguments used must match the declaration's parameters in type and order.

What does ref do in C#?

The ref keyword in C# is used for passing or returning references of values to or from Methods. Basically, it means that any change made to a value that is passed by reference will reflect this change since you are modifying the value at the address and not just the value.


1 Answers

You don't need reflection if your properties are all numeric and can be homogeneously treated as a single type - let's say a decimal.

Something like this should do the trick:

protected decimal ComputeFinancialSum( DateTime? beginDate, DateTime? endDate,
                                       Func<FinancialInfo,decimal> propertyToSum )
{
    if (beginDate == null && endDate == null)
        return 0;
    decimal total = 0;
    foreach (var fi in Financials)
    {
        if (someCondition)
            if (someSubCondition)
                total += propertyToSum(fi);
        else if (someOtherCondition)
            if (someOtherSubCondition)
                total += propertyToSum(fi);
        else if (anotherCondigion)
            total += propertyToSum(fi);
    }
    return total;
}

You can then provide appropriately named versions for all of your specific cases:

public decimal GetTotalReleasedFederalAmountByDate()
{
    return ComputeFinancialSum( BeginDate, EndDate, 
                                (x) => x.ReleasedFederalAmount );
}

public decimal GetTotalReleasedNonFederalAmountByDate()
{
    return ComputeFinancialSum( BeginDate, EndDate, 
                                (x) => x.ReleasedNonFederalAmount );
}

// other versions ....
like image 126
LBushkin Avatar answered Oct 20 '22 04:10

LBushkin