3

任何人都可以建议我,有没有更好的方法来使用 Swich 案例或任何方式编写以下代码(谢谢大家在这里提出宝贵的建议我在 Linq 查询中使用它,我观察到它包含不同的产品名称的一些修改)

    from p in l_list
    where ((LicenceType == "Full" && SystemType == "Single") && p.ProductName != "Full DoubleProduct ")
       || ((LicenceType == "Full" && SystemType == "Multiple") && p.ProductName != "Full SingleProduct")
       || ((LicenceType == "Partial" && SystemType == "Single") && p.ProductName != "Locked DoubleProduct") 
       || ((LicenceType == "Partial" && SystemSize == "Multiple") && p.ProductName != "Locked SingleProduct")
       || ((LicenceType == "Locked" && SystemSize == "Single") && p.ProductName != "Locked DoubleProduct") 
       || ((LicenceType == "Locked" && SystemType == "Multiple") && p.ProductName != "Locked SingleProduct")
4

5 回答 5

6

这种可怕的布尔条件描述了数据对象子集之间共享的一些共同质量。查明这种质量并给它一个描述性的名称。

然后,要么通过数据对象上的属性公开该数量的值,要么编写一个执行相同操作的扩展方法。最后,使用此访问器替换现有条件。

例如,如果质量的名称是“友好”,那么您可以这样做:

where model.IsFriendly // property

或这个:

where model.IsFriendly() // extension method BusinessRules.IsFriendly(Model m)
于 2013-02-15T13:19:27.453 回答
4

看起来您可以通过“分解”许可证类型来简化表达式,并观察条件归结为更简单

(
(SystemType == "Single"   && p.ProductName != "DoubleProduct") ||
(SystemType == "Multiple" && p.ProductName != "SingleProduct")
) &&
(
LicenceType == "Full"  ||
LicenceType == "Partial" ||
LicenceType == "NotApplicable"
)

如果没有"Full", "Partial", and以外的许可类型"NotApplicable",则可以丢弃第二个子句作为最终条件

(SystemType == "Single"   && p.ProductName != "DoubleProduct") ||
(SystemType == "Multiple" && p.ProductName != "SingleProduct")

编辑:一般来说,当你有复杂的多部分条件时,你能做的最好的就是提取常见的子表达式,并尝试减少条件的数量。根本问题是您试图用“线性”的代码表达具有多个维度的条件;这种“折叠”会导致代码难以阅读。

解决此问题的一种方法是在表格中“编码”您的条件,如下所示:

var conditions = new[] {
    new[] { "Full",          "Single",   "Full DoubleProduct"    }
,   new[] { "Full",          "Multiple", "Full SingleProduct"    }
,   new[] { "Partial",       "Single",   "Locked DoubleProduct"  }
,   new[] { "Partial",       "Multiple", "Locked SingleProduct"  }
,   new[] { "NotApplicable", "Single",    "Locked DoubleProduct" }
,   new[] { "NotApplicable", "Multiple", "Locked SingleProduct"  }
};

现在您可以在这样的条件下使用它:

Where (p => conditions.Any(cond =>
    cond[0] == p.LicenceType
 && cond[1] == p.SystemType
 && cond[2] != p.ProductName
))

这种方法的优点是条件是为程序的读者“列出”的,并且可以通过添加新行轻松扩展。IQueryable缺点是如果不将部分结果带入内存,您将无法再对源运行类似的查询。

于 2013-02-15T13:21:29.897 回答
0

在 Linq 中,您可以调用外部函数。那么为什么不将“业务逻辑”移出查询呢?即你可以创建一个方法

bool IsLincensedForXXX(Product p)

并在 LINQ 表达式中使用它:

from p in l_list where IsLincensedForXXX(p)

我认为它更清洁,更易于维护和重复使用。

于 2013-02-15T15:01:24.367 回答
0

您可以使用标志来指示对象或属性具有什么值。

[Flags]
enum MyEnum
{
    val1 = 0x01,
    val2 = 0x02,
    val3 = 0x04
}

您可以使用按位运算符(&&、||)来检查值。见这里

于 2013-02-15T13:20:25.923 回答
0

您可以将条件“编码”为数组(状态矩阵),然后使用 foreach/for 和标志。

bash.d已经使用位域给出了另一种可能的解决方案。如果你真的需要,你可以进一步结合两者。

我自己会避免使用重复的字符串(例如“Full”),而是将它们放在常量中以避免出错并提高可读性(有时)。

当操作数具有相同的优先级时,您也不需要使用括号,例如,(a == b && c == d) && e == f不需要括号。

最后但并非最不重要的一点是,您可以尝试反转逻辑,这可能会简化条件,例如(a || b || c) = !(!a && !b && !c). 如果您正在处理可能条件的已知子集,这可能特别有用,然后您可以“优化”它。

于 2013-02-15T13:53:24.703 回答