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

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

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

此外,我确信这可以通过reflection来完成,但我已经在其他代码中看到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 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等)。

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

如果您的属性都是数字属性并且可以被均匀地视为单一类型,则不需要reflection – 让我们说decimal

像这样的东西应该做的伎俩:

 protected decimal ComputeFinancialSum( DateTime? beginDate, DateTime? endDate, Func 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 .... 

除了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); ... } } 

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

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

这看起来更安全,因为您的所有逻辑都在您的控制之下(没有人通过您执行的function)。

如果你需要用不同的金额实际做不同的事情,这可以进一步细分:

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

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