通过 C# 中的委托对象识别订阅者对象

Recognize subscriber objects by their Delegate object in C#

我有这个对象:

public class ImageQueueMgr
{
    public delegate void OnImageQueueFilledHandler(int imageQueueId);
    public event OnImageQueueFilledHandler OnImageQueueFilled;

    ReleaseImageQueue(Object obj);

    Delegate[] delegateList;
}

其他对象可以订阅此对象事件OnImageQueueFilled。我希望所有对象都保持订阅状态,但我也想跟踪调用 ReleaseImageQueue(Object obj) 的订阅者,以便我可以在所有订阅者调用后进行一些清理:
ReleaseImageQueue(this)

我知道我可以拥有这样的订阅者列表:

delegateList = OnImageQueueFilled?.GetInvocationList();  

所以我的问题是,如何找到与调用 ReleaseImageQueue(this) 的对象对应的委托?

如果我答对了你想从实际事件调用列表的副本中删除委托,你不想取消订阅实际事件。在这种情况下,您可以使用 Delegate.Combine() 方法在另一个事件中复制调用列表。考虑以下代码:

 public class ImageQueueMgr
{
    public delegate void OnImageQueueFilledHandler(int imageQueueId);
    public event OnImageQueueFilledHandler OnImageQueueFilled;

    private OnImageQueueFilledHandler _onImageQueueFilledCopy;
    private void CopyEventInvocationList()
    {
        var delegateList = OnImageQueueFilled.GetInvocationList();
        _onImageQueueFilledCopy = (OnImageQueueFilledHandler)Delegate.Combine(delegateList);
    }

    public void NotifyFinish(OnImageQueueFilledHandler finishedHandler)
    {
        _onImageQueueFilledCopy -= finishedHandler;
    }

}

这样,订阅者可以轻松地从调用列表中删除委托,而无需实际取消订阅。请参阅以下使用示例:

    public static class Program
    {
        private static ImageQueueMgr _queueManager = new ImageQueueMgr();
        
        public static void ImageQueuedEventProcessor(int imageQueueId)
        {
            //some code here
            //........
            
            //unsubscribe when done
            _queueManager.NotifyFinish(ImageQueuedEventProcessor);
        }
        
        public static void ImageQueuedEventProcessor2(int imageQueueId)
        {
            //some code here
            //........
            
            //unsubscribe when done
            _queueManager.NotifyFinish(ImageQueuedEventProcessor2);
        }

        public static void Main()
        {
            _queueManager.OnImageQueueFilled += ImageQueuedEventProcessor;
            _queueManager.OnImageQueueFilled += ImageQueuedEventProcessor2;
        }
    }

我使用 delegate->Target->Equals 找到了一个解决方案,它在托管 C++ 中,但 C# 等价物非常简单:

List<Delegate^>^ m_delegateList = gcnew List<Delegate^>();

void SetDelegateList(cli::array<Delegate^>^ delegateList)
{
    // Convert cli::array to List
    for each (Delegate^ delegate in delegateList)
    {
        m_delegateList->Add(delegate);
    }
}

bool RemoveDelegateFromList(System::Object^ obj)
{
    Delegate^ delegateToRemove = nullptr;

    for each (Delegate^ delegate in m_delegateList)
    {
        if (delegate->Target->Equals(obj))
        {
            delegateToRemove = delegate;
            exit;
        }
    }

    if (delegateToRemove != nullptr)
    {
        m_delegateList->Remove(delegateToRemove);

        Debug::Print("removed delegate");
    }

    // If the list of delegates is empty then all of them are done with this image queue
    if (m_delegateList->Count == 0)
    {
        m_mreWaitDone->Set();
    }

    return false;
}