Get-Date приведение к строке против ToString()

Мое понимание синтаксиса встраивания строк в PowerShell "$($object)" всегда было так $object брошен в [System.String], который вызывает $object.ToString(), Тем не менее, я заметил это любопытное поведение с [DateTime] класс с использованием PowerShell 4.0 на Windows 8.1.

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 (гггг-мм-дд). [String]$x По-видимому, используется по умолчанию в США.

Возможно, это просто ошибка в классе DateTime, но меня больше удивляет, что разные методы преобразования объекта в строку дают разные результаты. Каковы правила приведения объекта в строку, если не вызывается ToString()? Является ли класс DateTime просто частным случаем из-за его перегрузки ToString(String)?

2 ответа

Решение

Если объект реализует 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

Обратите внимание, что приведенный выше код будет производить различную печать, если он выполняется в версиях PowerShell не для ISE.

Другие вопросы по тегам