我正在为公共Web API构建.NET客户端库。我努力解决的问题之一是如何最好地向库用户指出错误情况。显然,当执行失败时,我的库应该向调用者抛出或传递异常,但是我应该使用现有的异常还是为我的库创建新的异常?如果我创建新的异常,我应该只创建一个或多个异常吗?
选项1:仅使用现有的例外
最基本的,我可以举例如throw new Exception("API authentication error.");
,但这是非常通用的,需要大量处理才能处理。我也可以使用更合适的现有异常,例如System.Security.Authentication.AuthenticationException
,但是由于所有不同的命名空间,使用该库会很尴尬。在某些情况下,没有比InvalidOprationException
更合适的情况,因此采用这种方法似乎会使使用该库来处理错误的人变得很麻烦。最简单的可能就是使用HttpException
类,因为大多数错误条件在任何情况下都是HTTP状态代码和消息的转换。
选项2:为每种情况创建例外
我还可以为每个场景创建一个例外,但是将它们全部保存在库中。因此,我可以创建NotFoundException
,AuthorizationException
,TransactionsPendingException
和其他特定例外。
选项3:为我的客户创建一个例外
第三个选项是创建一个自定义异常MyApiException
,其中包含出现的不同错误的状态代码(当然还有适当的消息)。那么我可能会throw new MyApiException(401,"Not authorized.")
在我看来,选项3是最直接的实现,也是最容易处理的调用方法。我在GitHub和Codeplex上看到过使用这些选项的API客户端。是否有针对客户端库的推荐方法,或者它们都是有效的吗?
答案 0 :(得分:2)
Microsoft在MSDN上提供了一些有关此内容的重要信息:
https://msdn.microsoft.com/en-us/library/seyhszts%28v=vs.110%29.aspx
就个人而言,我倾向于做以下事情:
在有意义时使用现有的例外
e.g。传递无效密钥时,基于密钥的操作投掷
KeyNotFoundException
为有保证的情况创建自定义例外
Either<TSuccess,TFail>
等结果类型的例外情况
public int GetMyItem(string key)
{
if (string.IsNullOrEmpty(key)) throw new ArgumentNullException("key");
if (!_myDictionary.ContainsKey(key))
{
throw new KeyNotFoundException();
}
// Additional implementation left out
}
public class ArgumentNotOddException : ArgumentException
{
public ArgumentNotOddException(string paramName)
: base(@"The argument must be odd", paramName)
{
}
}
public class MyClass
{
public void DoSomething(int x)
{
if (x%3 == 0) throw new ArgumentNotOddException("x");
}
}
public class MyClass
{
public IEnumerable<IEither<int, string>> Divide(int left, IEnumerable<int> right)
{
foreach (var num in right)
{
if (num == 0)
{
yield return Either.Right<int, string>("cannot divide by zero");
}
yield return Either.Left<int, string>(left/num);
}
}
}
你也可以创建一个使用异常代码和消息的MyAppException
,但是你会失去表现力,异常代码容易出错输入(除非你使用枚举),{{1}并不能说MyAppException
与<{1}}完全相同。
我最好的建议是仔细思考代码应该抛出,或者它是否合理地返回混合结果/错误;在C#中这样做有点笨拙,但它消除了未处理异常的负担,并允许您在调用代码中更灵活。