2015-05-29 8 views
9

mia comprensione di stringa di PowerShell embedding sintassi "$($object)" è sempre stata che $object è gettato a [System.String], che invoca $object.ToString(). Tuttavia, ho notato questo strano comportamento con la classe [DateTime] utilizzando PowerShell 4.0 su Windows 8.1.Get-Date cast stringa vs ToString()

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 

Sembra che "$($object)" dà lo stesso comportamento colata a stringa, ma sta producendo chiaramente un risultato diverso da $object.ToString(). $x.ToString() è coerente con il formato data breve impostato in intl.cpl (aaaa-MM-gg). [String]$x sembra utilizzare l'impostazione predefinita en-US.

È possibile che questo sia semplicemente un bug nella classe DateTime, ma sono più sorpreso che i diversi metodi di conversione di un oggetto in una stringa producano risultati diversi. Quali sono le regole per lanciare un oggetto su una stringa, se non si chiama ToString()? La classe DateTime è semplicemente un caso speciale a causa del sovraccarico di ToString(String)?

+1

Non ho sufficiente per una risposta in questo momento, ma ho sicuramente notato che '.ToString()' non sempre produce lo stesso risultato di incorporare un oggetto in una stringa (non ho provato se l'incorporamento è sempre lo stesso del casting in '[String]'). Quindi tutto quello che posso dire è che non è limitato a '[DateTime]'. – briantist

+1

'.Tostring()' accetta un argomento di formato, quindi se hai bisogno di coerenza, sempre '.ToString() 'e fornisci il formato desiderato. Nel frattempo, è stato deciso che 'cast' dovrebbe semplicemente chiamare' .ToString() 'e accettare qualunque sia il suo formato predefinito. Non sono sicuro del motivo per cui lo implementerebbero in un altro modo. – johnjps111

+2

[Probabilmente correlato] (http://stackoverflow.com/q/14359053/1630171). Sospetto che il casting utilizzi en-US come cultura predefinita in ogni caso. 'ToString()' OTOH usa la cultura corrente, come [documentato] (https://msdn.microsoft.com/en-us/library/k494fzbf%28v=vs.110%29.aspx). –

risposta

8

Se un oggetto implementa l'interfaccia IFormattable, PowerShell chiamerà IFormattable.ToString anziché Object.ToString per l'operazione di trasmissione. Una cosa simile accade per il metodo statico Parse: se c'è un sovraccarico con il parametro IFormatProvider, verrà chiamato.

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) 
4

La tua domanda non è la domanda di PowerShell, ma una domanda .NET. Gli script di PowerShell possono utilizzare la struttura .NET [datetime] così com'è, cioè PowerShell non modifica il suo comportamento.

Quali sono le regole per trasmettere un oggetto a una stringa, se non si chiama ToString()?

La trasmissione utilizza definizioni di invarianza di cultura. Il metodo ToString() può contenere implementazioni dipendenti dalla cultura, perché è sovrascrivibile.

La classe DateTime è semplicemente un caso speciale a causa del sovraccarico di ToString (String)?

In primo luogo, DateTime non è una classe; è una struttura. In secondo luogo, non esiste un sovraccarico del metodo ToString(); in questo caso, la denominazione corretta è sovrascritta (sta ignorando il metodo Object.ToString()).

Per capire meglio di cosa sto senso, divertirsi con questi la data e l'ora abbastanza divertente stampa nelle diverse culture (copia, incolla e Run):

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 

Si noti che il codice di cui sopra produrrà diversi stampa se eseguito in ISE o in versioni non-ISE di PowerShell.

+0

Ho usato "Sovraccarico" in questo contesto per distinguere il 'ToString()' di DateTime da 'ToString (formatString)'. Non ho completamente familiarità con la differenza tra struct e class in .NET. È rilevante qui? –

+0

Sì, è confuso. Il metodo 'ToString()' è il metodo 'Object.ToString()', che è sovrascrivibile. Ma, DateTime ** definisce anche ** overload a questo metodo, ma il metodo 'ToString()' è un override e il metodo 'ToString (qualcosa)' è un ** overloading **. Le classi e le strutture sono molto diverse, davvero. –