处理自定义类中的异常

时间:2012-02-23 18:46:00

标签: c# .net exception exception-handling

我的班级包含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(...);
}

第三种方法与第二种方法类似,但它使用TryGetValue的{​​{1}}方法。

Dictionary

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

  

如果事件真的异常且是错误,请使用异常   处理更好,因为在正常情况下执行的代码更少...   如果事件经常发生,请使用编程方法进行检查   对于错误更好......

在我的情况下,很少会调用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(...); } 方法,但是该类的潜在用户可能会非常频繁地使用它。

4 个答案:

答案 0 :(得分:2)

ContainsKeyTryGetValue这两种方法都可以避免抛出KeyNotFoundException

仅检查天气键的ContainsKey方法与获取值之间的差异,但TryGetValue不仅检查键是否存在,而且还获得该键的值。

TryGetValue方法比ContainsKey方法更易于使用,但仅当您想要检查集合中的键并且还希望获得与其关联的值时。如果您只想检查密钥是否存在,请仅使用ContainsKey。

了解详情:Dictionary Object (ContainsKey Vs. TryGetValue)可能对您有帮助。

答案 1 :(得分:2)

这取决于你班级的预期目的。例如,如果您的类要充当字典包装器,那么传播典型Dictionary的类似错误/异常行为可能对客户端有益。如果你的班级正在实施更复杂的东西(最有可能),我会说你最好向调用者展示你自己的错误。就采用哪种方法而言,执行与普通Dictionary交互相同的输入验证。换句话说,如果您在添加到ContainsKey之前通常会检查TryGetValueDictionary,请继续在此处执行此操作,但之后无需抛出新的异常。而是以他们可能理解的方式将错误报告给调用者。他们不应该知道您正在使用Dictionary

答案 2 :(得分:2)

当有一种实用且高效的方法来避免底层数据类型中的异常时,这样做可能是个好主意,即使你最终会自己抛出异常。使用TryGetValue几乎总是从字典中获取某些内容的正确方法,该字典可能包含或不包含特定项目。

除此之外,你的内部方法调用抛出异常并且你知道它们的含义,通常最好将它们包装在你自己的异常中,除非你确定所有这些异常在代码中出现时总是具有相同的语义含义呼叫。否则,假设当尝试添加重复的用户时,Dictionary会抛出ArgumentException。如果您将其作为ArgumentException进行渗透而不是将其包装为其他内容,那么稍后您的AddUser方法中的代码可能会为其他内容抛出ArgumentException,您可能很难帮助调用者区分由重复用户导致的ArgumentException与由于其他原因而导致的ArgumentException

答案 3 :(得分:0)

第三次实施是最好的,因为它是最快和最短的。

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

第一次实施是最糟糕的:

  • 如果参数为null,则在功能上不相同。
  • 它会从 try 语句中受到性能损失 - 编译器必须在堆栈上设置一些数据。
  • 在我看来,还有一个样式问题,程序大量使用 catch 语句。对异常做的最好的事情通常是让它们冒泡,直到它们被记录下来或者可以对它们做些什么。