【问题标题】:Get-Date cast to string vs ToString()Get-Date 转换为字符串 vs ToString()
【发布时间】:2015-05-29 21:01:36
【问题描述】:

我对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)

【问题讨论】:

  • 我现在没有足够的答案,但我确实注意到.ToString() 并不总是产生与将对象嵌入字符串相同的结果(我没有测试是否嵌入总是与转换为[String] 相同。所以我只能说不限于[DateTime]
  • .Tostring() 接受格式参数,因此如果您需要一致性,请始终使用.ToString() 并提供您想要的格式。同时,同意cast 应该只调用.ToString() 并接受它的默认格式。不知道他们为什么会以其他方式实现它。
  • Probably related。我怀疑无论哪种方式,铸造都使用 en-US 作为默认文化。 ToString() OTOH 使用当前文化,如 documented
  • 你机器上Get-Culture的输出是什么?
  • 嗯.. 我得到mm/dd/yyyy 格式和$x.ToString()。虽然我也有 12 小时的时间,而 [String]$x 我有 24 小时的时间。另外值得注意的是 - 从DateTime[String] 的转换必须是 Powershell 支持的,因为它对 C# 或其他 .NET 语言无效。

标签: .net powershell datetime


【解决方案1】:

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

【讨论】:

    【解决方案2】:

    您的问题不是 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 中运行,上述代码将产生不同的打印

    【讨论】:

    • 我在此上下文中使用“重载”来区分 DateTime 的 ToString()ToString(formatString)。我并不完全熟悉 .NET 中结构和类之间的区别。它在这里相关吗?
    • 是的,这令人困惑。 ToString() 方法是 Object.ToString() 方法,它是可重写的。但是,DateTime也定义了这个方法的重载,但是ToString()方法是一个覆盖,ToString(something)方法是一个重载。类和结构是完全不同的,真的。
    猜你喜欢
    • 1970-01-01
    • 2021-03-28
    • 1970-01-01
    • 2023-03-24
    • 2021-07-23
    • 1970-01-01
    • 1970-01-01
    • 2017-02-04
    • 2018-04-01
    相关资源
    最近更新 更多