2009-01-23 77 views
2

这是验证传递给函数,即输入的最佳方式做您验证所有输入出发某些东西一样编码风格 - 输入验证

class A; 
void fun(A* p) 
{ 
    if(! p) 
    { 
    return; 
    } 

B* pB = p->getB(); 
    if(! pB) 
    { 
    return; 
    } 

....... 

} 

之前还是你写这样的:

void fun(A* p) 
{ 
    if(p) 
    { 
    B* pB = p->getB(); 
    if(pB) 
    { 
     ..... 
    } 
    } 
} 

我在问这是因为,如果我使用第一种风格,那么我的代码中会有多个返回语句,很多人都说不好(不知道为什么),如果使用第二种风格,那么会有在我的代码中嵌套层次太多。

回答

1

我喜欢做我输入验证前期,但往往会一次性进行测试

if(!p || !p->getB()){ 
    return; 
} 

如果功能操作输入是必需的,并且语言支持它,我抛出了参数异常(请参阅.NET ArgumentNullException,ArgumentException),以便在无效状态下代码不会执行干净的返回。这让调用者知道参数不足以完成操作。

+0

这与NullPointerException有何不同? – Arkadiy 2009-01-23 20:02:41

+0

输入先决条件不限于指针非空的情况 – 2009-01-26 16:01:52

7

第一种方式比第二种方式更容易阅读,且复杂程度较低(深度)。在第二种情况下,随着参数数量的增加,复杂性和深度会增加。但在第一个例子中,它只是线性的。

+1

说多个回报不好的人是'结构化编程'嬉皮士。假设有多个返回语句会导致代码难以阅读。我认为这个例子突出了事实,这并非总是如此。 – paxos1977 2009-01-24 03:06:44

0

理想情况下,你会通过引用传递,然后你不必担心这一点。但这并不总是一种选择。否则,这是一个偏好问题。

我个人更喜欢第一个,因为我没有多少回报问题。我认为函数应该基本适合一个或两个屏幕,所以只要你有语法突出显示它不应该很难看到一个函数的所有退出点。

0

我用您发布的第一种方法,这让我在大多数情况下,提供两种:meaningfull返回值或消息给用户:


btnNext_OnClick(...) 
{ 
if(!ValidateData()) 
return; 

// do things here 
} 


boolean ValidateData() 
{ 
if(!condition) 
{ 
MessageBox.Show("Message", "Title", MessageBoxButtons.OK, MessageBoxIcons.Information); 
return false; 
} 

return true; 
} 

这样一来,当我添加一个字段,需要表单级别验证,我可以添加另一个if语句检查验证方法。

1

我更喜欢第一个,我有一组宏处理常见情况(通常为了调试目的同时断言)。这种方法的缺点是你的函数返回类型必须相当统一,以使你的宏使用统一;好处是使用/效果非常明显。因此,例如,我的代码可能会显示为:

class A; 
void fun(A* p) 
{ 
    ASSERT_NONZERO_RETURN_ON_FAIL(p); 

    B* pB = p->getB(); 
    ASSERT_NONZERO_RETURN_ON_FAIL(pB); 

    ....... 
} 

这会产生更多可读代码,这些代码还会提醒您错误。此外,作为额外的好处,如果您发现重视运行时检查值的边际速度增加,您可以轻松禁用检入发布版本。

补充说明:根据我的经验,有些人说从函数返回多个点的原因很糟糕,因为他们在函数退出之前显式地进行资源解除分配,因此你不想重复去分配码。但是,如果您正确且一致地使用RIIA,这不应该成为问题。由于这是我试图总是这样做的,所以多个返回点比我更适合嵌套。

4

多重回报:人员和编码标准都是双向的。在C++中,如果使用RAII等,没有理由不喜欢多个返回(和异常)。许多C编码标准强制执行单入单出,以确保所有清理代码得到执行,因为没有RAII和基于范围的销毁/资源清理。

Should a function have only one return statement?

1

我倾向于在该方法的开始使用这些类型检查并返回的。 这样在 Bertrand Meyer'sObject-Oriented Software Construction, second edition, Prentice Hall描述我有点效仿 Eiffeldesign by contractpreconditionsassertions, 。

对于你的榜样,而不是返回无效,我将返回 枚举识别违反类似:

enum Violation { inviolate = 0, p_unspecified_unavailable, p_B_unspecified_unavailable,..... }; 

Violation fun(A* p) 
{ 
//__Preconditions:___________________________________ 
    if (! p)   return p_unspecified_unavailable: 
    if (! p->getB()) return pB_unspecified_unavailable; 
//__Body:____________________________________________ 
    .... 
//__Postconditions: _________________________________ 
    ..(if any).. 
    return inviolate; 
} 

我的意思是说,我考虑的前提条件(和任何职位条件)验证 到是围绕方法/函数主体的实现的一种包装,并倾向于区分和分离控制条件逻辑与主体表达的流程。