【问题标题】:How to write this LINQ for applying business logic?如何编写此 LINQ 以应用业务逻辑?
【发布时间】:2014-01-10 16:58:26
【问题描述】:

我正在尝试应用一些业务逻辑。
我关于在以下对象模型上使用 LINQ 以应用业务逻辑的问题。我相应地填充了以下对象:

public class Waiver
{
   public string Id { get; set; }
   public int Type { get; set; }
   public decimal Amount { get; set; }
}

要应用的业务逻辑:

1.) 应用订单项豁免
如果 LineItem Waiver [Type] 为 1111,则从单价中扣除 LineItem Waiver 金额
如果 LineItem Waiver [Type] 为 2222,则减去 LineItem WaiverAmount 作为单价的百分比
如果 LineItem Waiver [Type] 为 3333,则减去 LineItem Waiver 金额(行价格 = 数量 * 单价)
如果 LineItem Waiver [Type] 为 4444,则将 LineItem Waiver 金额作为离线价格的百分比扣除

2.) 申请订单豁免
如果订单豁免 [类型] 为 4444,则在应用订单项豁免后从总订单价格中扣除订单豁免金额
如果订单豁免 [类型] 为 8888,则在应用 LineItem 豁免后,将订单豁免金额作为订单价格的百分比扣除

实现这一目标的最佳方法是什么?

GetWaivedPrice(decimal unitPrice, int qty, IEnumerable<Waiver> waiver)

GetWaivedPrice 可以写成单个 LINQ 方法,并为所有折扣类型提供适当的映射吗?

这就是我想要实现的目标,最好是编写良好的 LINQ 方法:

private decimal GetWaivedPrice(decimal unitPrice, int qty, 
                                           IEnumerable<Waiver> waiver)
        {
            //Pseudo code shown for clarifying intent
            decimal waivedLineItemAmount = 0m;

            if waiver.Select(d => d.Type == 1111)
            //then apply the business logic on the unit price accordingly        
            if waiver.Select(d => d.Type == 2222)
            //then apply the business logic on the unit price accordingly  
            if waiver.Select(d => d.Type == 3333)
            //then apply the business logic on the unit price accordingly  

            return waivedLineItemAmount;

        }

【问题讨论】:

  • 你能更具体一点你有什么问题吗?为什么 JSON 是关于对数据进行一些(看似微不足道的)操作的问题的一部分?对于这种情况,您对“更好”的定义是什么(可读性、代码大小、行数……)?
  • 我的问题是编写 GetWaivedPrice 方法以应用行级豁免的最佳方式。 JSON 只是作为输入外观的示例格式。
  • 我已删除所有不相关的 JSON 代码、构造函数和空格 - 如有必要,请随时改进。请展示您对实现GetWaivedPrice 的尝试 - 当前方法签名表明您不太可能尝试编写一个...此外,您仍然需要添加“更好”的标准...
  • 投票重新开放... 旁注:我知道大多数人一次不能阅读超过一份声明(我就是其中之一:)。因此,让我们尝试单一陈述:请提供您选择“最佳方式”的标准——在您的情况下,什么是“更好”?

标签: c# linq c#-4.0


【解决方案1】:

我在这里看不到 LINQ 的情况。只需依次申请每个Waver

    private decimal GetWaivedPrice(decimal unitPrice, int qty, 
                                       IEnumerable<Waiver> waiver)
    {
        //Pseudo code shown for clarifying intent
        decimal waivedLineItemAmount = 0m;

        //apply all waivers
        foreach (var w in waiver) {
         switch (w.Type) { 
          case 1111:
           waivedLineItemAmout += someComputation();
           break;
          case 2222:
           waivedLineItemAmout += someComputation();
           break;
          case 3333:
           waivedLineItemAmout += someComputation();
           break;
         }
        }

        return waivedLineItemAmount;
    }

如果您坚持使用 LINQ 和纯函数式风格,您可以使用 Enumerable.Aggregate 来表述这一点,但在这里一个简单的循环似乎就可以了。

【讨论】:

  • 如何使用 Enumerable.Aggregate?
  • waivers.Aggregate(0m, (currentWaivedLineItemAmount, w) =&gt; computeNewAmount(currentWaivedLineItemAmount, w))。当你完全写出来时,它是相同的代码,只是不太容易理解。
【解决方案2】:

我没有看到对 linq 本身的需求,但可能是面向对象的设计。

我会改为让豁免处理方法调用中的业务逻辑,例如您现在拥有的。

public class Waiver
{
   public string Id { get; set; }
   public int Type { get; set; }
   public decimal Amount { get; set; }

   public decimal GetWaivedPrice(decimal unitPrice, int qty) { ... }

}

这样做可以促进任何未来的 linq 预测或操作,例如这种分组,当然还可以集中业务逻辑以供将来维护。

var groupedResult = myWaivers.Select(wv => new
    {
       Type = wv.Type,
       WaivedPrice = wv.GetWaivedPrice( unitPrice, qty)
    } )
                             .GroupBy(wv => wv.Type);

【讨论】:

    【解决方案3】:

    怎么样:

    private static Dictionary<int, Func<decimal, int, Waiver, decimal>> _logic
        = new Dictionary<int, Func<decimal, int, Waiver, decimal>>() {
            { 2222, (a, q, w) => a + w.Amount },
            { 3333, (a, q, w) => a + w.Amount },
            { 3333, (a, q, w) => a + w.Amount }
        };
    
    private static decimal GetWaivedPrice(decimal unitPrice, int qty, 
                                       IEnumerable<Waiver> waiver)
    {
        return waiver.Aggregate(0m, (a, s) => _logic[s.Type](a, qty, s), a => a);
    }
    

    当然,您必须使用折扣逻辑更新 _logic 字典才能使其正常工作。

    【讨论】:

      【解决方案4】:

      业务规则被隔离到单独的关注点(推导和策略)中,现在它非常类似于 LINQ!

      // Create a data structure to model the deductions themselves
      public class LineItemDeduction
      {
          public decimal UnitPriceAmount { get; set; }
          public decimal UnitPricePercentage { get; set; }
          public decimal LinePriceAmount { get; set; }
          public decimal LinePricePercentage { get; set; }
      
          // Assumed that waivers are distinct and are not composed together, only applied on the listed price.
          public decimal CalculateWaivedPrice(decimal unitPrice, int qty)
          {
              return ((unitPrice - UnitPriceAmount - (unitPrice * UnitPricePercentage)) * qty) - LinePriceAmount - (unitPrice * qty * LinePricePercentage);
          }
      }
      
      // Calculate the deductions
      private LineItemDeduction CalculateLineItemDeductionStrategy(LineItemDeduction deduction, Waiver waiver)
      {
          switch (waiver.Type) { 
            case 1111:
             deduction.UnitPriceAmount += waiver.Amount;
             break;
            case 2222:
             deduction.UnitPricePercentage += waiver.Amount;
             break;
            case 3333:
             deduction.LinePriceAmount += waiver.Amount;
             break;
            case 4444:
             deduction.LinePricePercentage += waiver.Amount;
             break;
           }
      
           return deduction;
      }
      
      // Extension method only for LineItem but it's the same principle for order waivers
      public static decimal GetWaivedPrice(this IEnumerable<Waiver> waivers, decimal unitPrice, int qty, Func<LineItemDeduction, Waiver, LineItemDeduction> deductionStrategy)
      {
          return waivers.Aggregate(
              new LineItemDeduction(),
              deductionStrategy,
              d => d.CalculateWaivedPrice(unitPrice, qty)
          );
      }
      
      // Now to get the waived price
      var waivedPrice = waivers.GetWaivedPrice(unitPrice, qty, CalculateLineItemDeductionStrategy);
      

      【讨论】:

        猜你喜欢
        • 2021-04-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-11-10
        • 1970-01-01
        相关资源
        最近更新 更多