2015-12-22 103 views
1

我擴展了System.Collections.Concurrent.ConcurrentQueue以在對象入隊時引發事件。我現在需要能夠使用System.Management.Automation.WriteObject/WriteVerbose/WriteDebug方法來編寫上述事件中的對象。但是,嘗試在事件處理程序中使用System.Management.Automation.WriteObject/WriteVerbose/WriteDebug時收到以下錯誤。事件中的C#PowerShell Cmdlet WriteObject

有誰知道我可以如何編組事件回主線程,以便我可以使用System.Management.Automation.WriteObject/WriteVerbose/WriteDebug方法嗎?

這是我的擴展ConcurrentQueue類。

public class ConcurrentQueueEx<T> : ConcurrentQueue<T> 
{ 
    #region Private Variables 

    private Guid _id; 

    #endregion 

    #region Public Accessors 

    public Guid Id 
    { 
     get { return this._id; } 
    } 

    #endregion 

    #region Event Declarations 

    public event PSObjectAddedEventHandler PSObjectAdded; 

    protected virtual void OnPSObjectAdded(Guid parentId, object obj) 
    { 
     PSObjectAddedEventHandler handler = PSObjectAdded; 
     if (handler != null) 
     { 
      PSObjectAddedEventArgs oae = new PSObjectAddedEventArgs(); 
      oae._ParentId = parentId; 
      oae._Object = obj; 
      handler(oae); 
     } 
    } 

    #endregion 

    #region Public Functions 

    public new virtual void Enqueue(T item) 
    { 
     base.Enqueue(item); 

     OnPSObjectAdded(this._id, item); 
    } 

    public virtual void Push(T item) 
    { 
     base.Enqueue(item); 

     OnPSObjectAdded(this._id, item); 
    } 

    public virtual T Pop() 
    { 
     T obj; 

     base.TryDequeue(out obj); 

     return obj; 
    } 

    #endregion 
} 

以下是cmdlet中的相關部分。

protected override void BeginProcessing() 
    { 
     base.BeginProcessing(); 

     _messageQueue = new ConcurrentQueueEx<object>(); 
     _messageQueue.PSObjectAdded += _messageQueue_PSObjectAdded; 

     _resultQueue = new ConcurrentQueueEx<object>(); 
     _resultQueue.PSObjectAdded += _resultQueue_PSObjectAdded; 
    } 

private void _resultQueue_PSObjectAdded(PSObjectAddedEventArgs e) 
    { 
     WriteObject(e._Object); 
    } 

    private void _messageQueue_PSObjectAdded(PSObjectAddedEventArgs e) 
    { 
     WriteVerbose(e._Object.ToString()); 
    } 

這裏是例外的細節。

System.Management.Automation.PSInvalidOperationException was unhandled by user code 
HResult=-2146233079 
Message=The WriteObject and WriteError methods cannot be called from outside the overrides of the BeginProcessing, ProcessRecord, and EndProcessing methods, and they can only be called from within the same thread. Validate that the cmdlet makes these calls correctly, or contact Microsoft Customer Support Services. 
Source=System.Management.Automation 
+0

錯誤告訴你在執行流水線(即開始/處理/結束)時你只有輸出通道(以及調試,警告等)。沒有地方可以將這個對象寫到這個範圍之外。 –

回答

0

當引發事件的線程正在排隊時,「主線程」在做什麼?

如果主線程被阻塞,那麼您可以讓它在同步對象上等待,然後讓它出隊對象。

如果線程關閉做其他事情,那麼你需要它來讓它中斷(通過一個事件)或者讓它輪詢隊列。我假設你會想要做第一個。在這種情況下,您需要在cmdlet中註冊一個事件並從另一個線程中觸發該事件。第二個回答here顯示瞭如何做到這一點。

+0

這比我所做的更優雅的解決方案(一旦有機會,我會更新我的代碼)。我只是將處理髮送到第三個線程,並監視事件,直到兩個線程都在消息隊列中報告完成的消息。 – ekeel