如何将类的属性作为方法的参数传递?

时间:2009-07-24 15:55:56

标签: c# lambda

我有一个类,有十几个属性代表各种金融领域。我有另一个类需要分别对每个字段执行一些计算。这些计算方法中的代码是相同的,除了它进行计算的字段。

有没有办法可以将属性名称作为参数传递,只有一个方法可以执行所有执行工作而不是每个属性的12个方法?

另外,我确信这可以通过反射完成,但我已经在其他代码中看到lambda以同样的方式使用,并且想知道这是否是可以使用它的候选者。

根据要求,这是一个例子:

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
}

我的目标是创建一个名为GetTotalAmountByDate()的方法,并传入一个开始日期,结束日期以及它需要访问的属性名称(ReleasedFederalAmount或ReleasedLocalAmount等)。

我希望这能准确地描绘出我想要实现的目标。

3 个答案:

答案 0 :(得分:5)

如果您的属性都是数字属性并且可以作为单一类型被统一处理,则不需要反射 - 让我们说decimal

这样的事情可以解决问题:

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

然后,您可以为所有特定情况提供适当命名的版本:

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

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

// other versions ....

答案 1 :(得分:0)

除了Jon Skeet提出的基于lamba的好建议外,你可以尝试这样的事情。 (当然,它可能会改变您的一些代码的工作方式。)

public class ValueHolder
{
  object Value;
}

public class Main
{
  private ValueHolder value1 = new ValueHolder();
  private ValueHolder value2 = new ValueHolder();

  public Value1 { get { return value1.Value; } set { value1.Value = value; } }
  public Value2 { get { return value2.Value; } set { value2.Value = value; } }

  public ValueHolder CalculateOne(ValueHolder holder ...)
  {
    // Whatever you need to calculate.
  }

  public CalculateBoth()
  {
    var answer1 = CalculateOne(value1);
    var answer2 = CalculateOne(value2);
    ...
  }
}

答案 2 :(得分:0)

这可能是这里技术最低的答案,但为什么不使用开关并合并多个“GetTotal ... Amount”功能呢?

 // define some enum for your callers to use
 public enum AmountTypeEnum {
     ReleasedFederal = 1
 ,   ReleasedLocal = 2
 }

 public decimal GetTotalAmountByDate(AmountTypeEnum type)
    {
        if (BeginDate == null && EndDate == null)
            return 0;
        decimal total = 0;
        foreach (var fi in Financials)
        {
            // declare a variable that will hold the amount:
            decimal amount = 0;

            // here's the switch:
            switch(type) {
                case AmountTypeEnum.ReleasedFederal: 
                     amount = fi.ReleasedFederalAmount; break;
                case AmountTypeEnum.ReleasedLocal:
                     amount = fi.ReleasedLocalAmount; break;
                default: break;
            }

            // continue with your processing:
            if (someCondition)
                if (someSubCondition)
                    total += amount;
            else if (someOtherCondition)
                if (someOtherSubCondition)
                    total += amount;
            else if (anotherCondigion)
                total += amount;
        }
        return total;
    }

这似乎更安全,因为你的所有逻辑都在你的控制之下(没有人通过你的功能来执行)。

如果您需要以不同的金额实际执行不同的事情,可以进一步细分:

获取处理部分并将其转换为函数:

      private decimal ProcessNormal(decimal amount) {
           decimal total = 0;

           // continue with your processing:
            if (someCondition)
                if (someSubCondition)
                    total += amount;
            else if (someOtherCondition)
                if (someOtherSubCondition)
                    total += amount;
            else if (anotherCondition)
                total += amount;
          return total;
     }

 public decimal GetTotalAmountByDate(AmountTypeEnum type)
    {
        if (BeginDate == null && EndDate == null)
            return 0;
        decimal total = 0;
        foreach (var fi in Financials)
        {
            // declare a variable that will hold the amount:
            decimal amount = 0;

            // here's the switch:
            switch(type) {
                case AmountTypeEnum.ReleasedFederal: 
                     amount = fi.ReleasedFederalAmount; 
                     total = ProcessNormal(amount);
                     break;
                case AmountTypeEnum.ReleasedLocal: 
                     amount = fi.ReleasedLocalAmount; 
                     total = ProcessNormal(amount);
                     break;
                case AmountTypeEnum.NonReleasedOtherAmount:
                     amount = fi.NonReleasedOtherAmount; 
                     total = ProcessSlightlyDifferently(amount);  // for argument's sake
                     break;
                default: break;
            }
        }
        return total;
    }