- r - 以节省内存的方式增长 data.frame
- ruby-on-rails - ruby/ruby on rails 内存泄漏检测
- android - 无法解析导入android.support.v7.app
- UNIX 域套接字与共享内存(映射文件)
我很难描述这个问题。也许这就是为什么我很难找到一个好的解决方案(这些词只是不合作)。让我通过代码来解释:
// original code
enum Fruit
{
Apple,
Orange,
Banana,
}
...
Fruit fruit = acquireFruit();
if (fruit != Fruit.Orange && fruit != Fruit.Banana)
coreFruit();
else
pealFruit();
eatFruit();
现在假装这三种类型经历了多年的发展。上述逻辑的不同风格在整个存储过程、SSIS 程序包、Windows 应用程序、Web 应用程序、Java 应用程序、Perl 脚本等中传播....
最后:
// new code
enum Fruit
{
Apple,
Orange,
Banana,
Grape,
}
大多数时候,“系统”运行良好,直到使用 Grapes。然后,系统的某些部分会出现不当行为,在不需要或不需要时对葡萄进行去皮和/或去核。
为了避免这些困惑,您遵循什么样的准则?如果旧代码没有被重构以考虑新的枚举,我的偏好是抛出异常。
我在黑暗中想出了一个办法:
#1 避免这样的“不符合逻辑”
// select fruit that needs to be cored
select Fruit from FruitBasket where FruitType not in(Orange, Banana)
#2 在需要时使用精心构造的 NotIn() 方法
internal static class EnumSafetyExtensions
{
/* By adding enums to these methods, you certify that 1.) ALL the logic inside this assembly is aware of the
* new enum value and 2.) ALL the new scenarios introduced with this new enum have been accounted for.
* Adding new enums to an IsNot() method without without carefully examining every reference will result in failure. */
public static bool IsNot(this SalesOrderType target, params SalesOrderType[] setb)
{
// SetA = known values - SetB
List<SalesOrderType> seta = new List<SalesOrderType>
{
SalesOrderType.Allowance,
SalesOrderType.NonAllowance,
SalesOrderType.CompanyOrder,
SalesOrderType.PersonalPurchase,
SalesOrderType.Allotment,
};
setb.ForEach(o => seta.Remove(o));
// if target is in SetA, target is not in SetB
if (seta.Contains(target))
return true;
// if target is in SetB, target is not not in SetB
if (setb.Contains(target))
return false;
// if the target is not in seta (the considered values minus the query values) and the target isn't in setb
// (the query values), then we've got a problem. We've encountered a value that this assembly does not support.
throw new InvalidOperationException("Unconsidered Value detected: SalesOrderType." + target.ToString());
}
}
现在,我可以安全地使用如下代码:
bool needsCoring = fruit.IsNot(Fruit.Orange, Fruit.Banana);
如果此代码在整个系统中传播,当 Grape 滚进城镇时将抛出异常(qa 将捕捉所有)。
无论如何,这就是计划。这个问题看起来应该很常见,但我似乎无法在谷歌上找到任何东西(可能是我自己的错)。
你们是怎么处理的?
更新:
我觉得这个问题的答案是创建一个“捕获所有其他”机制来停止处理并提醒测试人员和开发人员注意新枚举需要考虑的事实。如果你有“switch ... default”,那就太好了。
如果 C# 没有有 switch ... default,我们可以像这样纠正上面的代码:
Fruit fruit = acquireFruit();
if (fruit != Fruit.Orange && fruit != Fruit.Banana)
coreFruit();
else if(fruit == Fruit.Apple)
pealFruit();
else
throw new NotSupportedException("Unknown Fruit:" + fruit)
eatFruit();
免责声明:
你真的不应该使用上面的任何伪代码。它可能(?)编译甚至工作,但它真的是可怕的代码。如果您正在寻找基于 OOP 的方法,我在此线程中看到了很多不错的解决方案。当然,一个好的解决方案是将所有的切换和检查放在一个集中的方法中(工厂方法让我印象深刻)。除此之外,还需要进行同行代码审查。
最佳答案
如果我正确理解了您的问题,最常见的做法是抛出 NotSupportedException
或 NotImplementedException
。
switch (fruit.Kind) {
case Fruit.Apple:
Bite(fruit);
break;
case Fruit.Banana:
FeedToMonkey(fruit);
break;
default: throw new NotSupportedException("Unknown fruit.");
}
至于添加会破坏现有 if-not-is 逻辑的新枚举值,我认为在这种情况下使用枚举是一个糟糕的选择。您的元素显然具有明显不同的行为,它们不像例如颜色。或许最好让选项负责决定如何对待它们。那么你应该用多态替换枚举。
关于c# - 您如何编写其逻辑不受 future 额外枚举影响的代码?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3833793/
我是一名优秀的程序员,十分优秀!