2010-05-05 30 views
5

Lệnh ghép ngắn biết khi nào thực sự nên gọi WriteVerbose(), WriteDebug() và v.v.?Làm thế nào để lệnh ghép ngắn biết khi nào nó thực sự nên gọi WriteVerbose()?

Có lẽ tôi bỏ lỡ điều gì đó đơn giản nhưng tôi không thể tìm thấy câu trả lời. Tất cả các lệnh ghép ngắn Tôi đã thấy cho đến nay chỉ cần gọi WriteVerbose() mà không cần bất kỳ sự do dự nào . Tôi biết rằng đó là chính xác để làm như vậy, nhưng không phải là hiệu quả.

Hiệu suất bị khi chế độ tiết đang tắt nhưng lệnh ghép ngắn vẫn chuẩn bị dữ liệu cho cuộc gọi WriteVerbose(), tức là không có gì.

Nói cách khác, trong một cmdlet Tôi muốn để có thể:

if (<VerboseMode>) 
{ 
    .... data preparation, sometimes expensive ... 
    WriteVerbose(...); 
} 

Nhưng tôi không biết làm thế nào để có được if (<VerboseMode>) này. Ý tưởng nào?


Kết luận: Câu trả lời của @ stej cho thấy như thế nào có được thông tin cần thiết về mặt lý thuyết. Trong thực tế điều này là hacky và không phù hợp. Do đó, nếu một lệnh ghép ngắn tạo ra kết quả đầu ra hoặc chi tiết thực sự tốn kém thì có vẻ hợp lý để giới thiệu một tham số bổ sung chỉ định mức độ độ dài.

+0

Tôi không đồng ý với kết luận của bạn. Xem câu trả lời của tôi cho một giải pháp. –

Trả lời

5

Đây là phương thức từ System.Management.Automation.MshCommandRuntime.

internal void WriteVerbose(VerboseRecord record) 
{ 
    if ((this.Host == null) || (this.Host.UI == null)) 
    { 
     tracer.TraceError("No host in CommandBase.WriteVerbose()", new object[0]); 
     throw tracer.NewInvalidOperationException(); 
    } 
    ActionPreference verbosePreference = this.VerbosePreference; 
    if (this.WriteHelper_ShouldWrite(verbosePreference, this.lastVerboseContinueStatus)) 
    { 
     if (record.InvocationInfo == null) 
     { 
      record.SetInvocationInfo(this.MyInvocation); 
     } 
     this.CBhost.InternalUI.WriteVerboseRecord(record); 
    } 
    this.lastVerboseContinueStatus = this.WriteHelper(null, null, verbosePreference, this.lastVerboseContinueStatus, "VerbosePreference"); 
} 

MshCommandRuntime thực hiện giao diện ICommandRuntime mà không biết gì về tính cách rườm rà: | (tìm thấy thông qua phản xạ). Phiên bản của MshCommandRuntime sẽ có sẵn trong Cmdlet (public ICommandRuntime CommandRuntime { get; set; }).

Vì vậy, bạn có thể truyền thuộc tính CommandRuntime đến MshCommandRuntime và kiểm tra độ dài. Dù sao, điều này thực sự xấu xí.


Tôi hoàn toàn đồng ý rằng cần có cách dễ dàng để tìm ra. Và bên cạnh đó (mơ) trình biên dịch sẽ đủ thông minh để không đánh giá một số chuỗi trong trường hợp như thế này:

$DebugPreference = 'SilentlyContinue' 
$array = 1..1000 
Write-Debug "my array is $array" 

Input để Write-Debug sẽ không bao giờ sử dụng, vì vậy $array nên không được đánh giá trong chuỗi trôi qua .. (nó có thể kiểm tra rằng nó thực sự được đánh giá như thế này: Write-Debug "my array is $($array|%{write-host $_; $_})"

+0

@stej: Cảm ơn bạn đã điều tra hữu ích. Về mặt lý thuyết, có thể hack theo cách này bằng cách sử dụng sự phản chiếu (vì hầu hết các nội dung là nội bộ và không thể truy cập bình thường). Nhưng tất nhiên đây không phải là một giải pháp thực tế. Tuy nhiên, tôi sẽ chấp nhận câu trả lời trong một thời gian nếu chúng ta không tìm thấy lựa chọn thay thế tốt hơn. Tôi cũng tìm thấy đề xuất có liên quan tại Kết nối: https://connect.microsoft.com/PowerShell/feedback/details/74811/performance-provide-formatting-overloads-for-writeverbose-writedebug-etc (Điều này sẽ không là đủ mặc dù, tôi nghĩ rằng, chúng tôi cần một lá cờ IsVerbose, IsDebug, vv) –

+0

@Roman, bình chọn. | Những gì hiện đang đến trong tâm trí của tôi - khi phát triển cmdlet, bạn nên có quyền truy cập vào tất cả các biến, không nên bạn. Sau đó, bạn có thể nhận '$ DebugPrecedence' và hành động tương ứng. Không lý tưởng, nhưng nên làm việc. – stej

+1

'$ DebugPreference',' $ VerbosePreference' là tốt hơn so với không có gì, thực sự. Nhưng chúng không đủ, bởi vì chúng bị ghi đè bởi các tham số phổ biến cmdlet '-Verbose',' -Debug' nếu có bất kỳ quy định nào. Nhưng các tham số này không thể truy cập từ một lệnh ghép ngắn. Các tham số có thay đổi '$ DebugPreference' cục bộ,' $ VerbosePreference' không? Tôi nghi ngờ điều đó, nhưng tôi sẽ cố gắng tìm ra. –

4

Làm thế nào về:

BEGIN { 
    if ($PSCmdlet.MyInvocation.BoundParameters["Debug"].IsPresent) { 
     $HasDebugFlag = $true 
    } 

    if ($PSCmdlet.MyInvocation.BoundParameters["Verbose"].IsPresent) { 
     $HasVerboseFlag = $true 
    } 
} 
PROCESS { 
    if ($HasVerboseFlag) { 
     expensive_processing 
    } 
} 

Nên biết trước: Tested chỉ trên PowerShell 3.

+3

Điều này là tốt, thực sự. +1. Điều này sẽ làm việc trong một số trường hợp, thực sự, nhiều. Nó sẽ không hoạt động nếu các chế độ được đặt không theo tham số nhưng thông qua '$ VerbosePreference' hoặc' $ DebugPreference'. Do đó, 'if'-s cũng nên kiểm tra các biến này. Nhưng V3 đã giới thiệu các giá trị mặc định tùy chỉnh. Các tham số ràng buộc có thể không giúp ích nếu các chế độ được bật thông qua các giá trị mặc định tùy chỉnh. –

+1

Và không hoạt động nếu một lệnh ghép ngắn được gọi từ một lệnh khác. –

4

Vì vậy, không chỉ chúng ta phải lấy các tham số chung -Debug và -Kéo của cmdlet vào tài khoản, mà còn các cờ $ DebugPreference và $ VerbosePreference toàn cầu và thực tế là các tham số chung này được kế thừa nếu một cmdlet được gọi từ một lệnh khác cmdlet.

Nó có thể được thực hiện mà không cần hack xung quanh bên trong.

This answer cho bạn thấy nó có thể được thực hiện với ít sự cố trong lệnh ghép ngắn PowerShell.

function f { [cmdletbinding()]Param() 
    $debug = $DebugPreference -ne 'SilentlyContinue' 
    $verbose = $VerbosePreference -ne 'SilentlyContinue' 
    "f is called" 
    " `$debug = $debug" 
    " `$verbose = $verbose" 
} 
function g { [cmdletbinding()]Param() 
    "g is called" 
    f 
} 
f 
f -Debug -Verbose 
g 
g -Debug -Verbose 

Từ C#, chúng tôi phải kiểm tra cả hai cờ chung này, nhưng cũng là thông số chung. Hãy chắc chắn kế thừa từ PSCmdlet thay vì Cmdlet để đến phương thức GetVariableValue.

bool debug = false; 
bool containsDebug = MyInvocation.BoundParameters.ContainsKey("Debug"); 
if (containsDebug) 
    debug = ((SwitchParameter)MyInvocation.BoundParameters["Debug"]).ToBool(); 
else 
    debug = (ActionPreference)GetVariableValue("DebugPreference") != ActionPreference.SilentlyContinue; 

bool verbose = false; 
bool containsVerbose = MyInvocation.BoundParameters.ContainsKey("Verbose"); 
if (containsVerbose) 
    verbose = ((SwitchParameter)MyInvocation.BoundParameters["Verbose"]).ToBool(); 
else 
    verbose = (ActionPreference)GetVariableValue("VerbosePreference") != ActionPreference.SilentlyContinue; 
Các vấn đề liên quan