2009-12-01 22 views
9
# array 
C:\> (1,2,3).count 
3 
C:\> (1,2,3 | measure).count 
3 

# hashtable 
C:\> @{1=1; 2=2; 3=3}.count 
3 
C:\> (@{1=1; 2=2; 3=3} | measure).count 
1 

# array returned from function 
C:\> function UnrollMe { $args } 
C:\> (UnrollMe a,b,c).count 
3 
C:\> (UnrollMe a,b,c | measure).count 
1 
C:\> (1,2,3).gettype() -eq (UnrollMe a,b,c).gettype() 
True 

Sự khác biệt với HashTables là fairly well known, mặc dù official documentation chỉ đề cập đến nó một cách xiên (thông qua ví dụ).Điều gì xác định xem đường ống Powershell sẽ hủy bỏ một bộ sưu tập?

Vấn đề với chức năng là tin tức đối với tôi. Tôi hơi sốc vì nó đã không cắn tôi trước đây. Có một số nguyên tắc hướng dẫn mà chúng ta có thể làm theo không? Tôi biết rằng khi viết các lệnh ghép ngắn trong C# có overload of WriteObject nơi bạn có thể kiểm soát điều tra một cách rõ ràng, nhưng AFAIK không có cấu trúc như vậy trong chính ngôn ngữ Posh. Như ví dụ cuối cùng cho thấy, các thông dịch viên Posh dường như tin rằng không có sự khác biệt trong các loại đối tượng được đường ống. Tôi nghi ngờ có thể có một số Object vs PSObject weirdness dưới mui xe, nhưng đó là sử dụng ít khi bạn đang viết Posh tinh khiết và mong đợi các ngôn ngữ kịch bản để "chỉ làm việc."

/EDIT/

Keith là chính xác chỉ ra rằng trong ví dụ của tôi, tôi đi qua trong một đơn string [] lập luận chứ không phải là 3 đối số chuỗi. Nói cách khác, lý do Measure-Object nói Count = 1 là bởi vì nó nhìn thấy một mảng đơn của mảng có phần tử đầu tiên là @ ("a", "b", "c"). Đủ công bằng. Kiến thức này cho phép bạn làm việc xung quanh vấn đề này bằng nhiều cách:

# stick to single objects 
C:\> (UnrollMe a b c | measure).count 
3 

# rewrite the function to handle nesting 
C:\> function UnrollMe2 { $args[0] } 
C:\> (UnrollMe2 a,b,c | measure).count 
3 

# ditto 
C:\> function UnrollMe3 { $args | %{ $_ } } 
C:\> (UnrollMe3 a,b,c | measure).count 
3 

Tuy nhiên, nó không giải thích tất cả mọi thứ ...

# as seen earlier - if we're truly returning @(@("a","b","c")) why not count=1? 
C:\> (UnrollMe a,b,c).count 
3 

# our theory must also explain these results: 
C:\> ((UnrollMe a,b,c) | measure).count 
3 
C:\> (@(@("a","b","c")) | measure).count 
3 
C:\> ((UnrollMe a,b,c d) | measure).count 
2 

Từ những gì tôi có thể ngoại suy có một quy tắc chơi: nếu bạn có một mảng với chính xác một phần tử VÀ trình phân tích cú pháp nằm trong expression mode, thì trình thông dịch sẽ "unwrap" phần tử đã nói. Tôi còn thiếu bất kỳ sự tinh tế nào nữa không?

+0

Tương đương với WriteObject là lệnh ghép ngắn đầu ra (bí danh thành echo) mà mọi người hiếm khi sử dụng vì giá trị được ngầm xuất ra luồng stdout. –

+0

Đúng, mặc dù Write-Output không có tham số -EnumerateCollection như WriteObject (đối tượng, bool). –

+0

liên quan: http://stackoverflow.com/questions/28702588/in-what-conditions-does-powershell-unroll-items-in-the-pipeline/28707054#28707054 – alx9r

Trả lời

11

$ args được trải ra. Hãy nhớ rằng các tham số chức năng thường được truyền bằng không gian để tách chúng. Khi bạn vượt qua trong 1,2,3 bạn đang đi qua trong một cuộc tranh luận duy nhất mà là một mảng của ba số đó được gán cho $ args [0]:

PS> function UnrollMe { $args } 
PS> UnrollMe 1 2 3 | measure 

Count : 3 

Đưa kết quả (một mảng) trong một nhóm biểu thức (hoặc subexpression ví dụ$()) làm cho nó đủ điều kiện một lần nữa cho unrolling nên sau unrolls đối tượng [] có chứa 1,2,3 trả về bởi UnrollMe:

PS> ((UnrollMe 1,2,3) | measure).Count 
3 

tương đương với:

PS> ((1,2,3) | measure).Count 
3 

BTW nó không chỉ áp dụng cho một mảng với một phần tử.

PS> ((1,2),3) | %{$_.GetType().Name} 
Object[] 
Int32 

Sử dụng một subexpression mảng (@()) trên một cái gì đó đã là một mảng không có tác dụng dù có bao nhiêu lần bạn áp dụng nó. :-) Nếu bạn muốn ngăn chặn việc hủy đăng ký, hãy sử dụng toán tử dấu phẩy vì nó sẽ luôn luôn tạo một mảng ngoài khác được bỏ chọn. Lưu ý rằng trong trường hợp này bạn không thực sự ngăn chặn unrolling, bạn chỉ cần làm việc xung quanh unrolling bằng cách giới thiệu một "wrapper" ngoài mảng đó được trải ra thay vì mảng gốc ví dụ của bạn:

PS> (,(1,2,3) | measure).Count 
1 

Cuối cùng, khi bạn thực hiện điều này :

PS> (UnrollMe a,b,c d) | %{$_.GetType().Name} 
Object[] 
String 

Bạn có thể thấy UnrollMe trả về hai mục (a, b, c) làm mảng và d làm vô hướng. Hai mục này được gửi xuống đường ống riêng biệt, đó là kết quả đếm là 2.

+0

Cuộc gọi tốt. Để làm rõ: trong ví dụ của tôi, $ args không chỉ là mảng mà là mảng mảng. Phần tử đầu tiên & duy nhất của nó là @ (1,2,3). –

+0

Hmm, trên phản ánh thêm điều này đặt ra nhiều câu hỏi hơn là câu trả lời :) Xem chỉnh sửa. –

+0

>> Đặt kết quả (một mảng) trong một biểu thức nhóm (hoặc biểu thức con, ví dụ: $()) làm cho nó đủ điều kiện một lần nữa để hủy đăng ký. //// Tóm tắt tuyệt vời, cảm ơn. –

1

Dường như có liên quan đến cách thức đối tượng Đo lường hoạt động và cách đối tượng được truyền dọc theo đường ống.

Khi bạn nói

1,2,3 | measure 

bạn nhận được 3 Int32 đối tượng thông qua vào các đường ống dẫn, đo lường đối tượng sau đó đếm từng đối tượng nào được thấy trên các đường ống dẫn.

Khi bạn "hủy" bằng chức năng, bạn sẽ nhận được một đối tượng mảng được truyền vào đường ống đo đối tượng là 1, không cố gắng lặp qua các đối tượng trong mảng, như được hiển thị ở đây:

PS C:\> (measure -input 1,2,3).count 
1 

Một khả năng làm việc xung quanh là để "tái-roll" mảng vào đường ống sử dụng foreach:

PS C:\> (UnrollMe 1,2,3 | %{$_} | measure).count 
3 
Các vấn đề liên quan