【问题标题】:Class defined errors [closed]类定义错误[关闭]
【发布时间】:2020-10-21 12:29:38
【问题描述】:

我想将我的错误分开,因为它们的定义非常详细,这是一个错误模型:

public interface IErrorResult : IResult
{
    string Code { get; set; }
    string Message { get; set; }
    string Description { get; set; }
}

一个例子:

public static class CheckoutError
{
    public static ErrorResult Purchased = new ErrorResult
    {
        Code = CheckoutErrors.AlreadyPurchased,
        Message = "License already bought.",
        Description = "A license for this account already exists."
    };

    public static ErrorResult Expired = new ErrorResult
    {
        Code = CheckoutErrors.Expired,
        Message = "Checkout Expired.",
        Description = "The checkout session expired, please try again."
    };

    public static ErrorResult NotFound = new ErrorResult
    {
        Code = CheckoutErrors.NotFound,
        Message = "Checkout not found.",
        Description = "This checkout session doesn't exist."
    };
}

我将这些单独定义的原因是它们可以重复使用,并且在必要时更容易修改它们。

在调用业务逻辑之前调用的验证器中使用这些错误,如下所示:

public class CheckoutValidator : ICheckoutValidator
{
    private readonly ICheckoutSessionRepository _checkoutSessionRepository;
    private readonly ILicenseValidator _licenseValidator;

    public CheckoutValidator(ICheckoutSessionRepository checkoutSessionRepository)
    {
        _checkoutSessionRepository = checkoutSessionRepository;
    }

    public async Task<IResult> ValidateSession(string userId)
    {
        var checkout = await _checkoutSessionRepository.GetBySession(userId);
        if (checkout == default(CheckoutSession) || checkout.User.AspNetUserId != userId)
        {
            var error = CheckoutError.NotFound;
            error.Status = ResultStatusEnum.NotFound;
            return error;
        }

        if (DateTime.Now > checkout.Expires)
        {
            var error = CheckoutError.Expired;
            error.Status = ResultStatusEnum.Invalid;
            return error;
        }

        return new Result
        {
            Status = ResultStatusEnum.Valid
        };
    }
}

我想知道,这种设计是常用的吗?我觉得它可以变得更简单,我已经解决了复杂的问题,但我正在努力寻找可以改变和改进的地方和地方

【问题讨论】:

  • 注意error.Status = ResultStatusEnum.NotFound;,因为这会修改CheckoutError.NotFound 实例。
  • @Vernou 可以修改Status 属性,因为在不同情况下,结果状态可能会有所不同。然后在控制器中使用它来了解要发回给用户的内容,即NotFound()BadRequest()
  • 问题是同一个实例被重用了。在并行上下文(如 API)中,这会产生非常难以调试的错误。如果一个请求产生NotFound和其他产生BadRequest同时执行,结果是不可预测的。
  • @Vernou 我不明白,你能举个例子吗?
  • @Vernou 是不是因为是静态类?我应该改变这个吗?

标签: c# validation error-handling


【解决方案1】:

我见过并使用过一些错误模型

简单成功/失败的替代方案

  1. bool Try*(out T result) - 模式
  2. 返回空值
  3. 返回Maybe Monad

提供有关失败的附加信息的替代方案

  1. 抛出异常
  2. 返回result-object

每个选项都有各种缺点/优点。关于exception vs result objects,一种观点是异常应该用于“异常”,即意外和罕见的错误,而结果对象应该用于常见和/或预期的错误。 内存不足可能是前者的示例,而无效用户可能是预期错误的示例。

关于您的具体实施,有几个问题:

  1. 您的结果对象不是通用的,那么如果您需要返回某个任意对象,您会怎么做?似乎调用者必须进行一些转换才能从返回的对象中获取任何有用的东西,这通常会导致代码混乱。我建议将结果对象设为通用,查看this implementation 以获得灵感
  2. 您的错误是静态(即全局)对象,但具有公共设置器。这是一个很大的禁忌,很容易导致奇怪的行为。例如,考虑是否从多个线程访问错误对象(属性可能随时更改),或者如果您忘记设置其中一个属性(它将保留最后一个值)。要么使对象不可变,要么将它们更改为返回新对象的方法。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-11
    • 2016-08-18
    • 2014-06-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多