2015-05-29 14 views
9

Sự hiểu biết của tôi về cú pháp nhúng chuỗi của PowerShell "$($object)" luôn là $object được truyền đến [System.String], gọi số $object.ToString(). Tuy nhiên, tôi đã nhận thấy hành vi kỳ lạ này với lớp [DateTime] bằng PowerShell 4.0 trên Windows 8.1.Lấy ngày tháng thành chuỗi so với 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 

Dường như "$($object)" cung cấp cho các hành vi tương tự như đúc để chuỗi, nhưng được sản xuất rõ ràng là một kết quả khác nhau từ $object.ToString(). $x.ToString() phù hợp với định dạng ngày ngắn được đặt trong intl.cpl (yyyy-MM-dd). [String]$x xuất hiện để sử dụng mặc định ở Hoa Kỳ. Có thể đây chỉ đơn giản là một lỗi trong lớp DateTime, nhưng tôi ngạc nhiên hơn khi các phương thức chuyển đổi một đối tượng khác nhau thành một chuỗi tạo ra các kết quả khác nhau. Các quy tắc để đúc một đối tượng vào một chuỗi là gì, nếu không gọi ToString()? Lớp DateTime có phải là trường hợp đặc biệt do quá tải của nó là ToString(String) không?

+1

Tôi không có đủ câu trả lời ngay bây giờ, nhưng tôi đã nhận thấy rằng '.ToString()' không phải lúc nào cũng tạo kết quả tương tự như nhúng đối tượng vào chuỗi (tôi chưa thử nghiệm nếu nhúng luôn giống như đúc thành '[Chuỗi]'). Vì vậy, tất cả những gì tôi có thể nói là nó không giới hạn trong '[DateTime]'. – briantist

+1

'.Tostring()' chấp nhận một đối số định dạng, vì vậy nếu bạn yêu cầu tính nhất quán, luôn luôn '.ToString() 'và cung cấp định dạng mong muốn của bạn. Trong khi đó, đồng ý rằng 'cast' chỉ nên gọi'. ToString() 'và chấp nhận bất cứ định dạng mặc định nào. Không chắc chắn lý do tại sao họ sẽ thực hiện nó theo bất kỳ cách nào khác. – johnjps111

+2

[Có thể liên quan] (http://stackoverflow.com/q/14359053/1630171). Tôi nghi ngờ rằng việc đúc sử dụng en-US làm nền văn hóa mặc định theo cách nào đó. 'ToString()' OTOH sử dụng văn hóa hiện tại, như [tài liệu] (https://msdn.microsoft.com/en-us/library/k494fzbf%28v=vs.110%29.aspx). –

Trả lời

8

Nếu một đối tượng thực hiện giao diện IFormattable, thì PowerShell sẽ gọi IFormattable.ToString thay vì Object.ToString cho thao tác truyền. Một điều tương tự cũng xảy ra đối với phương thức tĩnh Parse: nếu có quá tải với tham số IFormatProvider, thì nó sẽ được gọi.

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

Câu hỏi của bạn không phải là câu hỏi PowerShell, mà là câu hỏi .NET. Kịch bản PowerShell có thể sử dụng cấu trúc .NET [datetime] vì nó, tức là, PowerShell không thay đổi hành vi của nó.

Quy tắc để đưa đối tượng vào chuỗi là gì, nếu không gọi ToString()?

Đúc sử dụng định nghĩa bất biến văn hóa. Phương thức ToString() có thể chứa các triển khai phụ thuộc vào văn hóa, bởi vì nó có thể được ghi đè lên.

Lớp DateTime có phải là trường hợp đặc biệt do quá tải của ToString (Chuỗi) không?

Thứ nhất, DateTime không phải là một lớp; đó là một cấu trúc. Thứ hai, không có quá tải phương thức ToString(); trong trường hợp này là, mệnh giá chính xác sẽ ghi đè (nó ghi đè phương pháp Object.ToString()).

Để hiểu rõ hơn về những gì tôi đang có nghĩa, vui vẻ với những ngày tháng và thời gian khá hài hước in ấn trong các nền văn hóa khác nhau (sao chép, dán và chạy):

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 

Chú ý rằng đoạn mã trên sẽ sản xuất khác nhau in nếu chạy trong ISE hoặc trong các phiên bản PowerShell không phải là ISE.

+0

Tôi đã sử dụng "Overloading" trong ngữ cảnh này để phân biệt 'ToString()' của DateTime từ 'ToString (formatString)'. Tôi không hoàn toàn quen thuộc với sự khác biệt giữa struct và class trong .NET. Ở đây có liên quan không? –

+0

Vâng, thật khó hiểu. Phương thức 'ToString()' là phương thức 'Object.ToString()', có thể ghi đè lên. Nhưng, DateTime ** cũng định nghĩa ** quá tải cho phương thức này, nhưng phương thức 'ToString()' là một trọng số, và phương thức 'ToString (something)' là một ** overloading **. Các lớp và cấu trúc khá khác nhau, thực sự. –

Các vấn đề liên quan