【问题标题】:Select one of two different methods in a method chain in C#在 C# 的方法链中选择两种不同方法之一
【发布时间】:2014-07-19 09:32:35
【问题描述】:

考虑以下代码:

decimal userPrice = product.Status == ProductStatusEnum.Presale
   ? pricingHelper.GetUserPresalePricing(sku, user).UserCustomPrice
   : pricingHelper.GetUserProductPricing(sku, user).UserCustomPrice;

是否有某种方法可以将决定使用哪种方法的表达式放置在方法链中,而不必使用两个完整的方法链?我的想法是使用委托或使用反射调用名称,但这些都不是合理的解决方案(尤其是名称调用)。

我意识到在这种情况下方法链并不长(之后只有一个属性),但想象一个方法链更长的场景。我喜欢方法链而不是创建很多变量,但是,为了清楚起见,在像这样的方法使用不同的长方法链中,我会选择在变量中临时存储而不是重复自己。但一定要这样吗?

在 javascript 中这很简单:

var userPrice = pricingHelper[
   product.Status === ProductStatusEnum.Presale
   ? GetUserPresalePricing
   : GetUserProductPricing
](sku, user).UserCustomPrice;

另外,也许将这两种方法之一放入一个变量中,然后使用该变量,如(错误的伪代码):

SomeDelegate = product.Status == ProductStatusEnum.Presale
   ? pricingHelper.GetUserPresalePricing
   : pricingHelper.GetUserProductPricing;

decimal userPrice = SomeDelegate(sku, user).UserCustomPrice;

鉴于 C# 可以做函数式语言可以做的大部分事情,因此必须有一种方法(不是说它一定比上面的起始代码更好,只是想知道)。

也欢迎您就这样的构造是否有用或比原始代码更清晰。

又想到了一个想法,那就是在pricingHelper 类中,我可以创建一个GetUserPricing 方法,该方法接受一个参数来指示是获取预售价格还是产品定价。嗯……

【问题讨论】:

  • 我喜欢最后一个用于一长串属性,但这将是非常基于意见的。也许这在 CodeReview 上更好?
  • 关于方法链 - Train Wreck Anti Pattern。对这样的代码进行单元测试也是地狱
  • @SergeyBerezovskiy 或也称为Fluent Interface,如果您想要“这是个好主意”版本而不是“这是一个坏主意”版本
  • @ScottChamberlain 很好的说明 :) 但是方法链只是一种用于实现流畅接口的技术。正如 Martin Fowler 所写,真正的流利程度远不止于此。
  • 回复:由于“基于意见”而投票结束。也许关于这种结构是否有用的部分是基于意见的,但你真的认为“如何不重复整个表达”的主要问题没有客观答案吗?

标签: c# delegation


【解决方案1】:
var f = product.Status == ProductStatusEnum.Presale
   ? new Func<Sku, User, CustomPrice>(pricingHelper.GetUserPresalePricing)
   : pricingHelper.GetUserProductPricing;

decimal userPrice = f(user, price).UserCustomPrice;

【讨论】:

  • 您不必将冒号后面的部分也放在new Func 中吗?
  • @ErikE - 我不这么认为 - 应该有从方法组到给定 Func 类型的隐式转换。
  • 您已按要求回答了问题——谢谢!最终,在我的特定代码库中要做的正确事情是将逻辑移动到它所属的定价 Web 服务中。
【解决方案2】:

您的代码中有重复 - 获取 UserCustomPrice(或任何您“链接”的内容)。为什么会发生这种情况?因为您的方法的业务逻辑听起来像获取任何产品定价的自定义用户价格。如果您将在代码中写下相同的要求,它将看起来像

var productPricing = GetProductPricing(product, user, sku);
decimal userPrice = productPricing.UserCustomPrice;

随着产品定价转移到单独的方法:

private IProductPricing GetProductPricing(Product product, User user, int sku)
{
    if (product.Status == ProductStatusEnum.Presale)
        return pricingHelper.GetUserPresalePricing(sku, user);

    return pricingHelper.GetUserProductPricing(sku, user);
}

现在意图很清楚了,尤其是与 JavaScript 版本相比。

注意:未来的重构可能导致将 GetProductPricing 方法移动到 pricingHelper

【讨论】:

  • 这是一个很好的观察,如果产品确定了哪个价格,则将其作为参数传入。但是,sku 完全暗示了产品,因此可能会有更多的重构可能。感谢您的意见!
  • 最终,在我的特定代码库中正确的做法是将逻辑移到它所属的定价 Web 服务中。我们现在可能会容忍这种丑陋(不是创建您建议的方法),但您的反馈有助于指出真正的潜在问题。
猜你喜欢
  • 1970-01-01
  • 2011-04-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-17
  • 2018-08-05
相关资源
最近更新 更多