我有一个类,有十几个属性代表各种金融领域。我有另一个类需要分别对每个字段执行一些计算。这些计算方法中的代码是相同的,除了它进行计算的字段。
有没有办法可以将属性名称作为参数传递,只有一个方法可以执行所有执行工作而不是每个属性的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等)。
我希望这能准确地描绘出我想要实现的目标。
答案 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;
}