包含 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);
}
}
我正在通过 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);
}
}