C#: 我应该抛出ArgumentException还是DirectoryNotFoundException?

14
我有一个接受字符串形式的目录路径的方法。在方法开始时,它会检查此路径是否存在,如果不存在,则应引发异常。我想可能应该抛出一个更具体的DirectoryNotFoundException而不是不太具体的ArgumentException
我阅读了DirectoryNotFoundException的MSDN文档,它说:

DirectoryNotFoundException使用值为0x80070003HRESULT COR_E_DIRECTORYNOTFOUND

我不太清楚这究竟意味着什么,看起来有点可怕... 我应该继续抛出该异常吗?还是应该坚持使用常规的ArgumentException?或者,我应该坚持ArgumentException,只是因为它是我在抱怨的参数吗?或者其他的做法?
public void MakeFunOf(string path)
{
    if(!Directory.Exists(path))
        throw new WhatException();
    TellJokeAbout(path);
    PointAndLaughAt(path);
}

不要害怕异常 HRESULT,实际上在 .net 中每个异常都有其内部的 HRESULT 值。 - arbiter
HRESULT是什么东西? - Svish
HRESULT是Win32 API中从所有API函数返回的类型。它只是一个32位整数错误代码。它被称为“HANDLE to RESULT”,但它实际上并不是一个句柄。 - John Saunders
个人而言,我不会在一个公共方法中检查目录是否存在,该方法接收路径参数。在我看来,这是调用者的责任。如果目录确实不存在,那么我会让代码在堆栈更高的位置失败,并抛出任何IO异常。 - Crono
5个回答

16
如果您希望开发人员在调用您的方法之前检查目录是否存在,请使用ArgumentException。如果您希望开发人员有选择处理缺少的目录,请使用DirectoryNotFound异常。
换句话说,"开发人员告诉我访问一个不存在的目录是不是一个错误?"
个人建议使用 DirectoryNotFound 异常。

1
我同意。InvalidArgument 应该是针对无效的路径,而不仅仅是缺失的路径。所以,“c::\x.txt”可能是无效的,但“c:\x.txt”不是,无论它是否存在。 - paxdiablo
1
这是一个棘手的问题...在开发人员执行检查并将目录路径传递给方法之间,目录可能已被删除,因此方法被传递不存在的目录不能真正成为错误,因为没有真正的方法可以确保它在方法被调用时仍然存在。 - Rob

2

我认为你应该检查参数的正确性,如果不正确则抛出ArgumentException异常,然后再抛出DirectoryNotFoundException异常。 如果没有给出参数或者只是指定了错误的路径,那么这是一个很大的区别。

void CheckDir(string path)
{
  if(String.IsNullOrEmpty(path))
  {
    throw new ArgumentException("Path not specified.");
  }
   if(!Directory.Exists(path))
  {
    throw new DirectoryNotFoundException();
  }
}

1

看起来你应该抛出DirectoryNotFoundException异常,因为如果未提供指定的参数,则ArgumentException更好地发挥作用...即它是null。

另一个选项是创建自己的异常并抛出它,例如:

[Serializable]
public class InvalidConfigurationException: Exception
{
    public InvalidConfigurationException() : base()
    {
    }

    public InvalidConfigurationException(string message)
        : base(message)
    {
    }

    public InvalidConfigurationException(string message, Exception innerException)
        : base(message, innerException)
    {
    }

    protected InvalidConfigurationException(SerializationInfo info, StreamingContext context) 
        : base(info, context) 
    { 
    }
}

然后你可以这样做:

public void MakeFunOf(string path)
{    
   if(!Directory.Exists(path))        
       throw new InvalidConfigurationException('Directory entered was invalid or does not exist');
   TellJokeAbout(path);    
   PointAndLaughAt(path);
}

但是如果参数为null,那么ArgumentNullException更加合适,不是吗? - Svish
是的,ArgumentNullException可能更合适,我只是试图在最理想的情况下使用你选择的异常。然而,如果输入的目录无效,即Pax对Talljoe答案的评论,我认为ArgumentException可能更合适。不管怎样,很高兴你解决了这个问题! - James

1

这只是我的观点(因为我没有具体的支持),但以下是我抛出DirectoryNotFoundException而不是ArgumentException的原因:

  • 您应该抛出最具体/准确的异常类型,以使代码的使用者了解抛出异常的原因。
  • 考虑到框架方法在尝试对不存在的目录执行操作时会抛出DirectoryNotFoundException而不是ArgumentException,请遵循框架的行为

0

关于 'ArgumentException' 的文档:

当调用方法时,如果传递的参数中至少有一个不符合被调用方法的参数规范,则会抛出 'ArgumentException' 异常。 所有 'ArgumentException' 实例都应携带一个有意义的错误消息,描述无效的参数以及参数的预期值范围。

字面上来说,这意味着异常选择取决于您方法的规范/文档。

如果路径参数的文档类似于 '现有文件/目录的路径',那么您可以正当地抛出 'ArgumentException'(或其派生类),因为基本上根据文档,您已经让调用者负责确保文件实际存在。

如果路径参数的文档更一般地描述为 '用于开玩笑和嘲笑的文件路径',那么我认为 'DirectoryNotFoundException' 更合适。


我很乐意承认,实际上这个区别可能比现实世界中任何人关心的都要微妙;) - jerryjvl

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接