像我对 TryPassNameValidation 函数所做的那样,在函数参数验证时抛出异常是否被视为一种好的做法,如果:
- 代码没有直接面向用户界面。它是 API 的一部分。
- 重要的是执行不会因参数错误而继续。
- 我想要良好的可读性和流畅性。
我还考虑过返回一个验证对象,如 answer 中所述但是这种编程风格让我想起了 GoLang functions handle errors .我认为异常是为了防止我们不得不这样做而发明的。
public void AddChildStructureLevel(Structure childStructureLevel)
{
try
{
TryPassNameValidation(childStructureLevel.Name); // throws if something is wrong
Children.Add(childStructureLevel);
}
catch (ArgumentException ae)
{
throw new ArgumentException($"Provided structure name {childStructureLevel.Name} is invalid.", ae);
}
Trace.WriteLine($"Added new child structure level to parent structure children.");
}
private void TryPassNameValidation(string structureName)
{
TryPassingStructureNameMinMaxLength(structureName);
TryPassingStructureNameUnique(structureName);
}
private void TryPassingStructureNameMinMaxLength(string structureName)
{
bool nameIsTooLong = structureName.Length >= maxLengthStructureName;
bool nameIsTooShort = structureName.Length <= minLengthStructureName;
if (nameIsTooLong) throw new ArgumentException($"Structure name is too long. Max {maxLengthStructureName} characters.");
if (nameIsTooShort) throw new ArgumentException($"Structure name is too short. Min {minLengthStructureName} characters.");
}
private void TryPassingStructureNameUnique(string childName)
{
foreach (Structure child in Children) //TODO: recurse over children.children
if (child.Name == childName) throw new ArgumentException($"Structure level name {childName} already exists.");
}
最佳答案
我发现这段代码很难理解,这与您的目标背道而驰。验证是通过嵌套调用和非显而易见的控制流(异常)完成的。我发现每个方法开头的常用 if ... throw;
序列更容易理解。部分原因是几乎所有的验证代码看起来都是这样。
TryPassingStructureNameUnique
应该使用 Any
编写。这样做之后,它适合一行,并且可以在提到的 if ... throw;
验证模式中使用。
bool nameIsTooLong
真的很冗长。这些条件是微不足道的。他们应该只使用 if ... throw;
模式。
除此之外,我认为这种设计是一个有效的选择。这不是一个容易的选择。如果可以的话,我不会那样做。
如果有效性是您的核心概念,请考虑将每个 Structure
包装在 ValidatedStructure
包装器类中。施工验证。通过这种方式,您可以通过目测了解给定的 Structure
是否已经过验证。
关于c# - 在 API 中对参数验证抛出异常是否被认为是一种好的做法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36390959/