【问题标题】:Design pattern for including errors with return values包含返回值的错误的设计模式
【发布时间】:2015-10-26 19:32:59
【问题描述】:

我正在通过其 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;}   
}

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

【问题讨论】:

  • 取决于实现,Martin Fowler 认为最后一个选项最有效。还有 Exception 方式,当出现问题时抛出异常。
  • 您是否碰巧有一个链接指向 Martin 谈到此问题的博客文章或演示文稿?
  • 你也可以做回调(委托/lambda)或事件。

标签: c# design-patterns exception-handling error-logging


【解决方案1】:

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

这样做的好处是实体干净

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

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

【讨论】:

  • 这是一个不错的选择,但不幸的是我很少使用单个对象。最典型的用例是比较来自两个单独文件的多个对象导出。我也几乎总是将返回的对象序列化为 JSON,然后再处理该 JSON。所以单独存储错误是有问题的。
  • 我相信他的意思是你会返回ParseResponse,它被定义为public class ParseResponse { public IList&lt;MyPersonDTO&gt; Persons {get;set;} public IList&lt;Exception&gt; Exceptions {get;set;}} 然后你可以序列化return.Persons,它不会有任何状态/返回码数据。
  • 是的,我就是这个意思
【解决方案2】:

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

因此,我想到的方法受到相同哲学的影响 -

1> 定义您自己的异常让我们说IncompleteReadException。 此异常应具有属性IList&lt;MyPersonDTO&gt; 来存储在异常发生之前读取的记录。

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-10-01
    • 2023-03-10
    • 2019-02-20
    • 1970-01-01
    • 1970-01-01
    • 2016-06-07
    • 2016-07-01
    相关资源
    最近更新 更多