2012-02-23 170 views
1

我有一个Dictionary<string, T>私有字段(users),其中string键代表用户名。我为这个类写了一些方法,例如GetValue(string userid)方法返回与指定用户名关联的T对象。处理自定义类中的异常

我会处理这个类中可能出现的异常,这些异常是由Dictionary引起的。例如:

  • 如果指定键为空,则Dictionary抛出ArgumentNullException;
  • 如果指定的键不存在于Dictionary中,则会抛出KeyNotFoundException

第一种方法可以赶上由Dictionary抛出的异常,并重新抛出同样的例外或抛出自定义异常。

public T GetValue(string userid) 
{ 
    try 
    { 
     return users[userid]; 
    } 
    catch(ArgumentNullException ex1) 
    { 
     // re-throw the same exception 
    } 
    catch(KeyNotFoundException ex2) 
    { 
     throw new UserIdNotFoundException("The specified userid does not exist.", ex2); // custom exception 
    } 
} 

第二种方法可避免捕捉异常,但检查导致他们的条件,并抛出适当的例外。

public T GetValue(string userid) 
{ 
    if (userid != null) 
    { 
     if(users.ContainsKey(userid)) 
      return users[userid]; 
     else throw new UserIdNotFoundException("The specified userid does not exist.", ex2); // custom exception 
    } 
    else throw new ArgumentNullException(...); 
} 

第三种方法是类似于第二之一,但它使用了DictionaryTryGetValue方法。

public T GetValue(string userid) 
{ 
    if (userid != null) 
    { 
     T value; 
     if(users.TryGetValue(userid, out value)) 
      return value; 
     else throw new UserIdNotFoundException("The specified userid does not exist.", ex2); // custom exception 
    } 
    else throw new ArgumentNullException(...); 
} 

每种方法的优点和缺点是什么? 的best practices for handling exceptions说:

如果该事件是真正的例外,是错误的,因为使用更少的代码在正常情况下,执行异常 处理比较好... 如果事件发生日常使用编程的方法来检查 错误比较好...

在我的情况下GetValue(string userid)方法将被调用很少,但是类的潜在用户可以使用它非常频繁。

回答

2

当存在避免底层数据类型中的异常的实用和高性能的方法时,即使您最终会自行抛出异常,也可能是一个好主意。使用TryGetValue几乎总是从字典中提取可能包含或不包含特定项目的东西的正确方法。

除此之外,你的内部方法调用抛出异常,你知道它们是什么意思,除非你确定所有这些异常在代码中出现时总是具有相同的语义含义,你打电话。否则,假设尝试添加重复的用户时,Dictionary会抛出ArgumentException。如果您将此渗透为ArgumentException而不是将其包装为其他内容,并且稍后可以使用AddUser方法中某处的代码为其他内容抛出ArgumentException,则可能很难帮助您的调用者区分一个ArgumentException由一个重复的用户造成,而一个ArgumentException由于其他原因而发生。

2

ContainsKeyTryGetValue两个方法可避免抛出方法KeyNotFoundException

Diffrence之间ContainsKey它仅仅检查天气键存在或不存在且比得到的值,但TryGetValue不仅检查键存在或不存在,但也获取该密钥的值。

TryGetValue方法很容易使用比ContainsKey的方法,但只有当你想检查集合中的关键,也想获得与它相关的值。如果您只想检查密钥是否存在,或仅仅使用ContainsKey。

了解更多:Dictionary Object (ContainsKey Vs. TryGetValue)可能会对您有所帮助。

2

这取决于你的班级的预期目的。例如,如果您的类充当Dictionary包装器,则客户端可能会传播典型的Dictionary类似的错误/异常行为。如果你的班级正在实施更复杂的(最有可能的),我会说你最好向调用者提出自己的错误。至于采取哪种方法,请在正常的Dictionary交互中进行相同的输入验证。换句话说,如果您在添加到Dictionary之前通常检查ContainsKeyTryGetValue,请继续在此处执行此操作,但不需要抛出新的异常。相反,用他们可能理解的方式将错误报告给调用者。他们不应该知道你在底层使用Dictionary

0

第三执行是最好的,因为它是最快和最短的。

实现是次优的:它访问字典两次,一次检查是否存在,第二次是获取值。

第一实现是最差的:

  • 这不是万一功能上等同参数为null。
  • 它从尝试声明收到性能损失 - 编译器将不得不在堆栈上设置一些数据显然。
  • 还有一个风格问题,在我看来,程序大量使用捕获陈述。对异常做的最好的事情往往是让他们冒泡直到他们可以被记录或者可以完成一些事情。