包含 return 值错误的设计模式

Design pattern for including errors with return values

我正在通过 API 为另一个软件编写插件。 API编辑的类 return只能通过本机软件和API访问。所以我正在编写自己的独立 POCO/DTO 映射到 API 类 的对象。我正在研究一项将读取本机文件的功能,以及 return 这些我可以从其他地方窃取的 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 中会出现完全错误,在没有理由的情况下抛出异常。

目前,当某些事情发生 "exceptional" 时,我只是记录异常并且导出失败。但我决定我宁愿导出我能导出的,并将错误记录在某处。

最简单的选择是只记录并吞下异常和 return 我能做的,但是这样我的调用代码就无法知道何时出现问题。

我正在考虑的一个选项是 return将错误字典作为单独的输出参数。键将标识无法读取的 属性,值将包含 exception/error.

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

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

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;}   
}

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

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

这样做的好处是实体干净

缺点是更难将错误映射回违规 entities/attributes。

发送批量实体时,这个缺点可能是个大问题。当 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> 读取时出现异常,可以catch原来的异常,把原来的异常包裹在这个里面抛出IncompleteReadException

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

您可以 return 一些额外的信息以及您想要的任何内容,而不是在整个代码中抛出异常 return。

    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);
        }            
    }