C# PowerShell Cmdlet WriteObject 事件

C# PowerShell Cmdlet WriteObject on Event

我扩展了 System.Collections.Concurrent.ConcurrentQueue 以在对象排队时引发事件。我现在需要能够使用 System.Management.Automation.WriteObject/WriteVerbose/WriteDebug 方法从上述事件中写入对象。但是,当我尝试在事件处理程序中使用 System.Management.Automation.WriteObject/WriteVerbose/WriteDebug 时收到以下错误。

有谁知道如何将事件编组回主线程以便我可以使用 System.Management.Automation.WriteObject/WriteVerbose/WriteDebug 方法?

这是我扩展的 ConcurrentQueue class。

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

当引发事件的线程排队时,"main thread" 正在做什么?

如果主线程被阻塞,那么您可以让它等待一个同步对象,然后让它从队列中取出对象。

如果线程停止执行其他操作,那么您需要它来中断它(例如通过事件)或者让它轮询队列。我假设你会想做第一个。在这种情况下,您需要在您的 cmdlet 中注册一个事件并从另一个线程触发该事件。第二个答案 here 显示了如何执行此操作。