PowerShell中DirectoryInfo/FileInfo转字符串机制及自定义类型复用问题
背景示例
执行以下代码:
cd $home foreach ($dir in gci d*) { $dir }
输出结果为:
Directory: C:\Users\User Mode LastWriteTime Length Name ---- ------------- ------ ---- d-r--- 1/19/2023 11:14 PM Desktop d-r--- 1/13/2023 1:31 PM Documents d-r--- 1/30/2023 5:35 PM Downloads
但执行以下代码时:
cd $home foreach ($dir in gci d*) { [string]$dir }
或者:
cd $home foreach ($dir in gci d*) { "$dir" }
输出变成了完整路径:
C:\Users\User\Desktop C:\Users\User\Documents C:\Users\User\Downloads
可见字符串转换时自动选取了DirectoryInfo的FullName属性。
更特殊的是,执行下面的代码:
cd $home foreach ($dir in gci -Directory) { "$dir" }
输出仅为目录名称,而非完整路径。
技术问题
- PowerShell是如何实现将DirectoryInfo类型强制转换为字符串时自动选择FullName属性的?
- 是否存在某种后台属性来实现这一转换逻辑?
- 我们能否在自定义类型中使用该属性,指定转换为基元类型时的默认属性?
- 为何未指定路径时,字符串转换会选择Name属性?
环境信息:
74|PS(5.1.19041) C:\Users\....\wsPowerShell\Modules [230131-09:47:18]> $PSVersionTable Name Value ---- ----- PSVersion 5.1.19041.2364 PSEdition Desktop PSCompatibleVersions {1.0, 2.0, 3.0, 4.0...} BuildVersion 10.0.19041.2364 CLRVersion 4.0.30319.42000 WSManStackVersion 3.0 PSRemotingProtocolVersion 2.3 SerializationVersion 1.1.0.1
解答
1. 底层转换机制
PowerShell将.NET对象转字符串时,并非仅依赖对象原生的ToString()方法。对于DirectoryInfo/FileInfo这类文件系统类型,PowerShell通过类型适配器(Type Adapter) 自定义了上下文感知的转换逻辑:
- 当对象通过带通配符的路径(如
gci d*)获取时,适配器判定需要明确的路径标识,返回FullName属性值; - 当直接获取当前目录下的子项(如
gci -Directory)时,适配器判定用户关注的是子项名称,返回Name属性值。
2. 后台实现的核心逻辑
这个转换逻辑不是由单一属性实现,而是PowerShell类型扩展与格式化系统共同作用的结果。FileSystemInfo类型在PowerShell中被注册了自定义转换规则,核心是类型适配器对字符串转换过程的拦截,根据获取对象的上下文动态选择返回的属性。
你可以通过以下命令查看该类型的扩展信息:
Get-TypeData System.IO.DirectoryInfo | Select-Object -ExpandProperty Members
3. 自定义类型中复现默认转换
有两种方式可以实现自定义类型的默认字符串转换:
方法一:重写ToString()方法
在自定义.NET类中直接重写ToString()方法,PowerShell会优先调用该方法作为字符串转换结果:
public class MyCustomType { public string Name { get; set; } public string FullPath { get; set; } public override string ToString() { return FullPath; // 指定默认返回的字符串属性 } }
在PowerShell中使用时,"$customObj"会直接返回FullPath的值。
方法二:PowerShell类型扩展
如果无法修改类的源代码,可以通过Update-TypeData为现有类型添加自定义转换逻辑:
Update-TypeData -TypeName MyCustomType -MemberType ScriptMethod -MemberName ToString -Value { return $this.FullPath }
4. 为何有时返回Name属性
这是PowerShell针对文件系统类型优化的上下文感知行为:当你通过gci -Directory直接获取当前目录的子项时,PowerShell判定你更关注子项的名称而非完整路径,因此在字符串转换时返回Name;而使用通配符筛选时,PowerShell认为你需要明确的路径来区分匹配项,因此返回FullName。
内容的提问来源于stack exchange,提问作者Blaisem

