CSharp - 哪个设计最可取: 测试创建,尝试创建,创建捕捉?

  显示原文与译文双语对照的内容
0 0

假设有一个操作可以创建一个用户。 如果指定的电子邮件或者用户名存在,这里操作可能失败。 如果它失败,则需要确切地知道原因。 有三种方法可以做到这一点,我想知道是否有明确的赢家。

下面是一个类用户:


class User
{
 public string Email { get; set; }
 public string UserName { get; set; }
}

完成创建操作的方法有 3种:

Test-Create


if (UserExists(user)) act on user exists error;
if (UsernameExists(user)) act on username exists error;
CreateUser(user);

UserExists和UsernameExists向数据库服务器发出验证请求。 这些调用再次在CreateUser中重复,以确保正确使用 API 。 如果验证失败,我在两种情况下都会抛出 ArgumentOutOfRangeException 。 所以有一个性能命中。

Try-Create


enum CreateUserResultCode
{
 Success,
 UserAlreadyExists,
 UsernameAlreadyExists
}

if (!TryCreate(user, out resultCode))
{
 switch(resultCode)
 {
 case UserAlreadyExists: act on user exists error;
 case UsernameAlreadyExists: act on username exists error;
 }
}

这个模式只做一次验证,但是我们使用了所谓的错误代码,这不是一个好的实践。

Create-Catch


try
{
 CreateUser(user);
}
catch(UserExistsException)
{
 act on user exists error;
}
catch(UsernameExistsException)
{
 act on username exists error;
}

这里没有使用错误代码,但是现在我必须为每个案例创建一个单独的异常类。 这或多或少是如何使用异常的,但我想知道是否创建一个单独的异常而不是枚举条目是值得的。

那么,我们有一个明确的赢家,还是更多的味道?

时间: 原作者:

0 0

那么,我们有一个明确的赢家,还是更多的味道?

第一个选项有一个根本缺陷,如果 CreateUser 依赖于外部资源,那么它永远不会是线程安全或者安全的,其他实现可能在你的测试中创建。 通常,我倾向于避免这个"图案",因为。

至于另外两个选项- 它实际上要归结于是否将失败预期为多见。 如果 CreateUser 在某种程度上会失败,那么Try*模式是我的首选,因为使用异常实际上是使用控制流的例外。

如果失败真的是一个特例,那么异常会更容易理解。

原作者:
0 0

虽然有些主观,但有一些具体的优点和缺点值得指出。

test-create方法的一个缺点是竞争条件。 如果两个客户端试图在大约相同的时间创建相同的用户,那么它们可能同时通过测试,然后尝试创建相同的用户。

在Try-Create和Create-Catch之间,我喜欢 Create-Catch,但这是个人口味。 有人可能认为Create-Catch使用了流量控制的例外,这通常被忽略。 另一方面,Try-Create需要一些笨拙的output 参数,这可能更容易被忽略。

我更喜欢 Create-Catch,但这里绝对有争论的余地。

原作者:
0 0

你指定 UserExistsUsernameExists 都进行了数据库调用。 我假设 CreateUser 也做了一个数据库调用。

为什么不让数据库处理你的线程问题? 假设在你的table(s), 上设置了适当的约束,你可以让它在存储过程调用中 err-out 。

因此,我将把我的选票投给英镑的Create-Catch 。

原作者:
...