我对PowerShell的字符串嵌入语法"$($object)"
的理解一直是$object
被强制转换为[System.String]
,从而调用$object.ToString()
。但是,我注意到[DateTime]
类在Windows8.1上使用PowerShell 4.0时出现了这种奇怪的行为。
PS> $x = Get-Date
PS> $x.GetType() | select -ExpandProperty Name
DateTime
PS> $x.ToString()
2015-05-29 13:36:06
PS> [String]$x
05/29/2015 13:36:06
PS> "$($x)"
05/29/2015 13:36:06
"$($object)"
似乎给出了与字符串强制转换相同的行为,但显然产生了与$object.ToString()
不同的结果。$x.ToString()
与intl.cpl(yyyy-MM-dd(中设置的短日期格式一致。[String]$x
似乎使用en-US默认值。
这可能只是DateTime类中的一个错误,但我更惊讶的是,将对象转换为字符串的不同方法会产生不同的结果。如果不调用ToString()
,将对象强制转换为字符串的规则是什么?DateTime类只是因为ToString(String)
过载而成为一个特例吗?
如果对象实现IFormattable
接口,则PowerShell将为强制转换操作调用IFormattable.ToString
而不是Object.ToString
。静态Parse
方法也会发生类似的情况:如果IFormatProvider
参数过载,则会调用它。
Add-Type -TypeDefinition @'
using System;
using System.Globalization;
public class MyClass:IFormattable {
public static MyClass Parse(string str) {
return new MyClass{String=str};
}
public static MyClass Parse(string str,IFormatProvider fp) {
return new MyClass{String=str,FormatProvider=((CultureInfo)fp).DisplayName};
}
public string String {get;private set;}
public string FormatProvider {get;private set;}
public override string ToString() {
return "Object.ToString()";
}
string IFormattable.ToString(string format,IFormatProvider fp) {
return string.Format("IFormattable.ToString({0},{1})",format,((CultureInfo)fp).DisplayName);
}
}
'@
[String](New-Object MyClass) #Call IFormattable.ToString(null,CultureInfo.InvariantCulture)
[MyClass]'Test' #Call MyClass.Parse("Test",CultureInfo.InvariantCulture)
您的问题不是PowerShell问题,而是.NET问题。PowerShell脚本可以按原样使用.NET结构[datetime],即PowerShell不会更改其行为。
如果不调用ToString((,将对象强制转换为字符串的规则是什么?
强制转换使用区域性不变定义。ToString()
方法可以包含依赖于区域性的实现,因为它是可重写的。
DateTime类只是一个特例,因为它重载了ToString(String(吗?
首先,DateTime不是一个类;这是一个结构。其次,不存在ToString()
方法重载在这种情况下,正确的面额将被覆盖(它将覆盖Object.ToString()
方法(。
为了更好地理解我的意思,请在不同文化中使用这些非常有趣的日期和时间打印(复制、粘贴和运行(:
function f{
$x=get-date
[CultureInfo]$currentCulture = [System.Threading.Thread]::CurrentThread.CurrentCulture
[System.Threading.Thread]::CurrentThread.CurrentCulture=[CultureInfo]::CreateSpecificCulture('en-US')
$x.ToString()
[System.Threading.Thread]::CurrentThread.CurrentCulture=[CultureInfo]::CreateSpecificCulture('ar-IQ')
$x.ToString()
[System.Threading.Thread]::CurrentThread.CurrentCulture=[CultureInfo]::CreateSpecificCulture('de-DE')
$x.ToString()
[System.Threading.Thread]::CurrentThread.CurrentCulture=[CultureInfo]::CreateSpecificCulture('ru-RU')
$x.ToString()
[System.Threading.Thread]::CurrentThread.CurrentCulture=[CultureInfo]::CreateSpecificCulture('fr-FR')
$x.ToString()
[System.Threading.Thread]::CurrentThread.CurrentCulture=[CultureInfo]::CreateSpecificCulture('zh-CN')
$x.ToString()
[System.Threading.Thread]::CurrentThread.CurrentCulture=[CultureInfo]::CreateSpecificCulture('zh-HK')
$x.ToString()
[System.Threading.Thread]::CurrentThread.CurrentCulture=[CultureInfo]::CreateSpecificCulture('zh-TW')
$x.ToString()
[System.Threading.Thread]::CurrentThread.CurrentCulture=[CultureInfo]::CreateSpecificCulture('hu-HU')
$x.ToString()
[System.Threading.Thread]::CurrentThread.CurrentCulture=[CultureInfo]::CreateSpecificCulture('ko-KR')
$x.ToString()
[System.Threading.Thread]::CurrentThread.CurrentCulture=[CultureInfo]::CreateSpecificCulture('ja-JP')
$x.ToString()
[System.Threading.Thread]::CurrentThread.CurrentCulture=[CultureInfo]::CreateSpecificCulture('ka-GE')
$x.ToString()
[System.Threading.Thread]::CurrentThread.CurrentCulture=[CultureInfo]::CreateSpecificCulture('pt-BR')
$x.ToString()
[System.Threading.Thread]::CurrentThread.CurrentCulture=$currentCulture
}
f
请注意,如果在ISE或非ISE版本的PowerShell中运行,上面的代码将产生不同的打印。