Get-Date强制转换为字符串vs ToString()

时间:2015-05-29 21:01:37

标签: .net powershell datetime

我对PowerShell的字符串嵌入语法"$($object)"的理解始终是$object强制转换为[System.String],后者调用$object.ToString()。但是,我在Windows 8.1上使用PowerShell 4.0的[DateTime]类注意到了这种奇怪的行为。

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)

2 个答案:

答案 0 :(得分:8)

如果对象实现了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)

答案 1 :(得分:4)

您的问题不是PowerShell问题,而是.NET问题。 PowerShell脚本可以原样使用.NET结构[datetime],即PowerShell不会改变其行为。

  

如果不调用ToString(),将对象强制转换为字符串的规则是什么?

Casting使用文化不变定义。 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中运行,上面的代码将产生不同的打印