2009-07-24 5 views
5

У меня есть класс, который имеет дюжину или около того свойств, которые представляют различные финансовые поля. У меня есть другой класс, который должен выполнять некоторые вычисления по каждому из этих полей отдельно. Код внутри этих методов расчета идентичен, кроме поля, в котором он вычисляет.Как передать свойство класса в качестве параметра метода?

Есть ли способ, которым я могу передать имя свойства в качестве параметра и только один метод, который выполняет всю выполняющую работу вместо 12 методов для каждого свойства?

Кроме того, я уверен, что это может быть достигнуто с помощью отражения, но я видел в другом коде, где лямбды используются таким же образом и было интересно, является ли это кандидатом, где это можно использовать.

В соответствии с просьбой, вот пример:

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

будет легче ответить, если вы можете поделиться пример такой функции и представление о свойствах класса. –

+2

Мне любопытно, почему ваш метод расчета не может принимать, скажем, экземпляр класса финансовых полей и значение (т. Е. Значение свойства, которое вы хотите выполнить вычисление) в качестве параметров. Можете ли вы опубликовать некоторый код заглушки, чтобы осветить ваш вопрос? –

+0

используют тот же тип в функции defination, который вы использовали в свойстве класса. –

ответ

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 .... 
+0

Это именно то, что я искал, спасибо! –

0

Помимо хорошего предложения на основе lamba от Jon Skeet, вы можете попробовать что-то вроде этого. (Конечно, это может изменить способ некоторые из вашего кода работает.)

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

Это, вероятно, самый низкий технический ответ здесь, но почему бы просто не использовать переключатель и объединить несколько «GetTotal ... Сумма "функции?

// 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; 
    } 
Смежные вопросы