编写一个 switch case。

3

请问有没有更好的方法来编写下面的代码,可以使用Switch case或其他方式(非常感谢在这里提供宝贵建议的所有人,我正在使用它在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")

3
你给代码加上了C#的标签,但是where关键字在C#中是无效的。 - luiges90
5
似乎是查询表达式的一部分。 - Lee
3
可以,这是在 LinQ 中实现的(http://msdn.microsoft.com/zh-cn/library/6b0scde8(v=vs.80).aspx)。 - Abbas
3
@GopeshSharma 这并没有什么帮助。 - spender
没有其他类型。 - Kittu
显示剩余2条评论
5个回答

6

那个庞大的布尔条件描述了一组数据对象中共享的某些常见特质。找出这个特质并给它取一个描述性的名称。

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

例如,如果特质的名称是“友好度”,则可以这样做:

where model.IsFriendly // property

或者是这个:
where model.IsFriendly() // extension method BusinessRules.IsFriendly(Model m)

1
如果要将该表达式转换为SQL语言可能有些棘手,但创建一个条件的抽象似乎是一个不错的选择。+1 - spender

4

看起来你可以通过“分解”许可类型并观察条件,使表达式更简单化,这样条件就变得简单多了。

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

如果除了 "Full"、"Partial" 和 "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
))

这种方法的优点是可以为程序读者"制表"条件,并且只需添加新行即可轻松扩展。缺点是如果针对源运行这样的查询,就无法避免将部分结果带入内存。

嗨,@dasblinkenlight,感谢您的回复。这里我有不同的产品名称。我通过查看问题已编辑了我的问题,如果您可以,请指导我。 - Kittu
它并不总是与ProductName进行比较,而可能与ChildProductName进行比较。 - Rune FS
抱歉,那是我的错误,只有产品名称,没有子产品名称。我已经重新编辑了我的问题。 - Kittu
谢谢你,但是我这里会单独提供许可证。在我的列表中,我没有许可证类型。如果我们在这种情况下使用switch case是否更好? - Kittu
@Kittu 使用switch语句处理单变量条件以外的任何内容的问题在于,您会得到大量不健康的代码重复。具体来说,如果您使用switch处理许可证类型,您将最终得到三个分支,它们都有相同的if-then-else语句,也许每个分支内部的语句不同。 - Sergey Kalinichenko

0

您可以使用标志来指示对象或属性的值。

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

你可以使用位运算符(&&, ||)来检查值。请参见这里


0
在Linq中,您可以调用外部函数。 那么为什么不将“业务逻辑”移出查询呢? 也就是说,您可以创建一个方法。
bool IsLincensedForXXX(Product p)

并在LINQ表达式中使用它:

from p in l_list where IsLincensedForXXX(p)

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


嗨@Stefano Altieri,这也是我想要单独编写一个函数的原因。但是我该如何根据上述三个条件(许可证类型、系统大小、产品名称)进行过滤呢?请指导我。 - Kittu
许可类型、系统大小、产品属性是什么? - Stefano Altieri
是的,LicenceType和SystemSize是属性。 - Kittu
仅在函数中使用它们:bool IsCompatibleWithXXX(Product p){ if p.SystemSize==.... return true;} - Stefano Altieri

0

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

另一个可能的解决方案已经由提供了 - 使用位域。如果确实需要,您可以进一步结合两者

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

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

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接