在返回值中包含错误的设计模式

本文关键字:设计模式 错误 包含 返回值 | 更新日期: 2023-09-27 18:19:16

我正在通过它的API为另一个软件编写一个插件。API返回的类只能通过本机软件和API访问。因此,我正在编写自己独立的POCO/DTO对象,这些对象映射到API类。我正在研究一个功能,它将在本机文件中读取,并返回这些POCO对象的集合,我可以在其他地方窃取。目前我正在使用JSON。. NET将这些类序列化为JSON。

例如,我可能有一个像这样的DTO

public class MyPersonDTO
{
    public string Name {get; set;}
    public string Age {get; set;}
    public string Address {get; set;}       
}

. .和这样的方法来读取本地"Persons"到我的DTO对象

public static class MyDocReader
{
    public static IList<MyPersonDTO> GetPersons(NativeDocument doc)
    {
        //Code to read Persons from doc and return MyPersonDTOs
    }
}

我用一个测试文件设置了单元测试,但是当我在其他文件上运行导出时,我总是遇到意想不到的问题。有时本机对象会有意想不到的值,或者在没有理由的情况下,API会抛出异常。

目前,当一些"异常"发生时,我只是记录异常和导出失败。但我已经决定,我宁愿导出我所能导出的,并将错误记录在某个地方。

最简单的选择是只记录和吞下异常,并返回我能返回的,然而,这样我的调用代码就没有办法知道什么时候有问题。

我正在考虑的一个选项是返回一个错误字典作为单独的输出参数。键将标识无法读取的属性,值将包含异常/错误的详细信息。

public static class MyDocReader
{
    public static IList<MyPersonDTO> persons GetPersons(NativeDocument doc, out IDictionary<string, string> errors)
    {
        //Code to read persons from doc
    }
}

或者,我也考虑只将错误存储在返回对象本身中。这增加了对象的大小,但有一个额外的好处,就是可以直接将错误存储在对象中。因此,如果稍后某人的导出生成错误,我不必担心在他们的计算机上跟踪正确的日志文件。

public class MyPersonDTO
{
    public string Name {get; set;}
    public string Age {get; set;}
    public string Address {get; set;}
    public IDictionary<string, string> Errors {get; set;}   
}

这通常是如何处理的?是否有其他选项可以报告错误以及我没有考虑的返回值?

在返回值中包含错误的设计模式

您可以将结果包装在回复或响应消息中,而不是将错误作为实体的一部分返回。错误可能是响应消息的一部分,而不是实体。

这样做的好处是实体是干净的

缺点是很难将错误映射回违规的实体/属性。

当发送批量实体时,这个缺点可能是一个大问题。当API更加面向单一实体时,这就不那么重要了。

原则上,如果API出现问题(无法恢复),调用代码必须知道发生了异常。所以它可以有一个适当的策略来处理它。

因此,我想到的方法受到同样的哲学的影响——

1>定义你自己的异常,比如IncompleteReadException。这个异常应该有一个属性IList<MyPersonDTO>来存储在异常发生之前所读取的记录。

public class IncompleteReadException : Exception
{
    IList<MyPersonDTO> RecordsRead { get; private set; }       
   public IncompleteReadException(string message, IList<MyPersonDTO> recordsRead, Exception innerException) : base(message,innerException)
    {
        this.RecordsRead = recordsRead;
    }
}

2>当读取过程中出现异常时,您可以捕获原始异常,将原始异常包装在这个&throw IncompleteReadException

这将允许调用代码(应用程序代码)有一个适当的策略来处理读取不完整数据时的情况。

您可以返回一些额外的信息,而不是在您的代码中抛出异常。

    public (ErrMsg Msg, int? Result) Divide(int x, int y)
    {
        ErrMsg msg = new ErrMsg();
        try
        {
            if(x == 0){
                msg = new ErrMsg{Severity = Severity.Warning, Text = "X is zero - result will always be zero"};
                return (msg, x/y);
            }
            else
            {
                msg = new ErrMsg{Severity = Severity.Info, Text = "All is well"};
                return (msg, x/y);
            }
        }
        catch (System.Exception ex)
        {
            logger.Error(ex);
            msg = new ErrMsg{Severity=Severity.Error, Text = ex.Message};                
            return (msg, null);
        }            
    }