c # – One-shot event manager "without blocking"

Giving a review to Oachkatzl and recently about some other synchronization problems (lazy with invalidate and some block list of nodes), I wanted to test my skills and redesign them as lightly as possible.

I'm especially concerned about thread safety here, because there is no statement of LOCK, just Interlocked.CompareExchange in a loop, which is used for the event fields anyway. There is only one field – object _estado to avoid torn readings (for example, overwriting the sender + args without the proper lock and knowing for sure that we won to make the invocation).

Having a single field also makes me consider changing all this to structure, because it will be used as a private field for public events anyway.

The last thing I was thinking about was maybe to eliminate the runtime type checks (state is invoked), but I do not think it's worth it (it would probably need to involve the delegates in another class and use an interface or a common base class).

/// 
/// Thread-safe event manager that ensures that subscribers receive a notification once the event occurs,
/// even if the event has already happened.
/// 
/// Event sender
/// Additional arguments passed on to subscribers
public class OneShotEvent
{
public delegate void Handler (sender of the sender, Args of Args);

// auxiliary class to store the sender and arguments when invoked
private class invoked
{
sender public sender;
Args public args;
Public Summoned (Sender Sender, Args Args)
{
this.sender = sender;
this.args = args;
}
}

// Delegate (subscribers) or Invoked (sender and arguments)
private object _estado;

/// 
    /// Subscribers will be notified once the event happens,
/// can be notified immediately if the event has already happened.
/// 
    public event Handler Event
{
Add
{
state var = state_status;
previous object
do
{
if (the state is invoked invoked)
{
value (invoked.sender, invoked.args);
he came back;
}
prev = state;
state = Interlocked.CompareExchange (ref _state, Delegate.Combine ((Delegate) state, value), prev);
}
while (prev! = state);
}
remove
{
state var = state_status;
previous object
do
{
yes (state is invoked)
he came back;
prev = state;
state = Interlocked.CompareExchange (ref _state, Delegate.Remove ((Delegate) state, value), prev);
}
while (prev! = state);
}
}

/// 
    /// Notify subscribers if you have not already done so.
/// 
    /// Sender of the notification.
    /// Allegations of the notification.
    /// true if invocation was not invoked before, false if it was already invoked
    public bool TryInvoke (Sender Sender, Args Args)
{
state var = state_status;
yes (state is invoked)
false return;

var invoked = new Invoked (sender, args);
previous object
do
{
prev = state;
state = Interlocked.CompareExchange (ref _state, invoked, prev);
yes (state is invoked)
false return;
}
while (prev! = state);

((Controller) status)? Summon (sender, args);
true returns
}
}