问题 Directory.GetParent中的错误?


我被一种非常奇怪的行为击中了脸 System.IO.Directory.GetParent 方法:

string path1 = @"C:\foo\bar";
DirectoryInfo parent1 = Directory.GetParent(path1);
Console.WriteLine (parent1.FullName); // Prints C:\foo, as expected

// Notice the extra backslash. It should still refer to the same location, right ?
string path2 = @"C:\foo\bar\";
DirectoryInfo parent2 = Directory.GetParent(path2);
Console.WriteLine (parent2.FullName); // Prints C:\foo\bar !!!

我认为这是一个错误,但这种方法自1.0以来一直存在,所以我想现在已经检测到了。另一方面,如果它是按照设计的,我想不出对这种设计的明智解释......

你怎么看 ?这是一个错误吗?如果没有,你如何解释这种行为?


9114
2017-10-18 22:47


起源

重要的是要认识到.NET框架的原因 二 处理目录的类。其中一个猜测,另一个验证。你知道区别。 - Hans Passant
@Hans:实际上,Directory和DirectoryInfo都没有验证任何内容......我用于测试的路径实际上并不存在于我的文件系统中,并且两个类都非常乐意处理它(只要我不做某事当然,这确实需要存在的路径)。无论如何,显然目录猜错了... IMO它应该对待两条路径完全一样 - Thomas Levesque
我应该验证,但是,感叹,它可以修复的可能性非常小。没有意义。发布到connect.microsoft.com - Hans Passant
@Hans,我同意:即使这是一个bug,修复它也会是一个突破性的变化,所以他们可能不会这样做。一世 发布到Connect 无论如何... - Thomas Levesque
现在记录了此行为。 - nawfal


答案:


一些谷歌搜索显示 一些想法

DirectoryInfo di = new DirectoryInfo(@"C:\parent\child");
Console.WriteLine(di.Parent.FullName);

DirectoryInfo di = new DirectoryInfo(@"C:\parent\child\");
Console.WriteLine(di.Parent.FullName);

两者都返回“C:\ parent”

我只能假设 Directory.GetParent(...) 不能假设 C:\parent\child 是一个目录而不是没有文件扩展名的文件。 DirectoryInfo 可以,因为你正在以这种方式构建对象。


我个人认为,当有反斜杠时,该字符串被视为目录内“空文件”的路径(即没有名称和扩展名的文件)。显然,那些可以存在(应该有一个链接,但由于某种原因,我找不到任何东西)。

尝试构建一个 FileInfo 对象 path2。你会看到它构造得恰到好处 String.Empty 作为其名称和扩展名,不存在且具有 C:\foo\bar 就像它一样 DirectoryName。鉴于此,情况是有道理的:这个“空文件”的父对象确实如此 C:\foo\bar


9
2017-10-18 23:24



是的,我想到了类似的东西,但它确实没有意义:没有最终反斜杠的情况工作正常(父母是 C:\parent 是否 child 是一个文件或目录),情况就是这样 同 失败的最后反斜杠: c:\parent\child` is obviously a directory, not a file (no file path ends with a backslash). And even if it *could* be a file, its parent should still be C:\ parent` ... - Thomas Levesque
关于解决方法 new DirectoryInfo:那就是我最终做的。实际上我的问题并不是“如何解决这个问题”,而是“为什么它会像那样” - Thomas Levesque
@Thomas:甚至可能没有..看到编辑。 - GSerg
+1为您的上次编辑。现在它是有意义的,我猜...即使我不会那样设计它 - Thomas Levesque


我同意GSerg。只是为了增加一些额外的火力,我将添加以下使用Reflector获得的代码片段。

Directory.GetParent函数基本上只调用Path.GetDirectoryName函数:

[SecuritySafeCritical]
public static DirectoryInfo GetParent(string path)
{
    if (path == null)
    {
        throw new ArgumentNullException("path");
    }
    if (path.Length == 0)
    {
        throw new ArgumentException(Environment.GetResourceString("Argument_PathEmpty"), "path");
    }
    string directoryName = Path.GetDirectoryName(Path.GetFullPathInternal(path));
    if (directoryName == null)
    {
        return null;
    }
    return new DirectoryInfo(directoryName);
}

DirectoryInfo的Parent属性基本上剥离了一个尾部斜杠,然后调用Path.GetDirectoryName:

public DirectoryInfo Parent
{
    [SecuritySafeCritical]
    get
    {
        string fullPath = base.FullPath;
        if ((fullPath.Length > 3) && fullPath.EndsWith(Path.DirectorySeparatorChar))
        {
            fullPath = base.FullPath.Substring(0, base.FullPath.Length - 1);
        }
        string directoryName = Path.GetDirectoryName(fullPath);
        if (directoryName == null)
        {
            return null;
        }
        DirectoryInfo info = new DirectoryInfo(directoryName, false);
        new FileIOPermission(FileIOPermissionAccess.PathDiscovery | FileIOPermissionAccess.Read, info.demandDir, false, false).Demand();
        return info;
    }
}

3
2017-10-18 23:52



有意思......我甚至没想到用Reflector检查(与我不同......)。所以问题实际上是Path.GetDirectoryName,而不是Directory.GetParent - Thomas Levesque


这非常有趣。首先,当我读到这篇文章时,我很确定这会是一个错误,但当我想到它有点长时间我得出的结论是 大概 意图是路径不应该是目录,而是文件的完整路径或相对路径。所以

C:\ somenonexistingpath \到\ A \目录\

被解释为...目录中没有名称的文件的路径。这有点愚蠢,但如果我们假设微软的程序员期望文件的完整路径,那么就不应该涵盖这种情况。

编辑: 

注意

c:\ dir \ makefile - > c:\ dir

c:\ dir \ build.msbuild - > c:\ dir

按预期给予父母。


1
2017-10-18 23:44



这是有道理的,但文档没有说明路径是文件或目录路径...我假设如果方法期望文件路径他们会提到它。一个没有名字的文件就没有多大意义;)。无论如何,我想我会提交关于Connect的错误报告,只是为了看看MS对此有何看法。 - Thomas Levesque
没有名字的文件没有意义,但我的论点是他们没有期望人们会假设一个目录的路径。我同意文件应该更清楚。 - steinar