At the moment when my background thread is complete it runs a System.Action callback using an anonymous lambda statement. I'm wondering how can I rewrite the code below to have a callback/lambda statement using a Completed function.
ViewModel : BaseViewModel
public override void Initialize(System.Action onInitializeCallback = null)
{.....
BackgroundEntityWorker.RunWorkerCompleted += (sender, args) =>
{
If (onInitializeCallback != null)
{
onInitializeCallback();
}
};
.....
}
I want to change it to something below
BackgroundEntityWorker.RunWorkerCompleted += BackgroundWorker_Completed =>
{
If (onInitializeCallback != null)
{
onInitializeCallback();
}
};
BaseViewModel
public virtual void Reload(int? id = null, Action<T> callback = null)
{
Initialize(() =>
{
Localize();
if (id == null)
{
IndicateLoading(false);
}
else
{
Load(id.Value, () => IndicateLoading(false));
}
});
}
I get an error Argument type 'Lambda expression is not assignable to parameter type System.ComponentModel.RunWorkerCompletedEventHandler
I tried
BackgroundEntityWorker.RunWorkerCompleted += BackgroundWorker_Completed;
but I lose my callback, how do I set it to have BackGroundWorker_Completed and maintain my callback?
BackgroundEntityWorker.RunWorkerCompleted += (sender, args) =>
{
If (onInitializeCallback != null)
{
onInitializeCallback();
}
}
but careful about BackgroundEntityWorker null access
public override void Initialize(System.Action onInitializeCallback = null)
{
If (BackgroundEntityWorker.RunWorkerCompleted != null)
{
BackgroundEntityWorker.RunWorkerCompleted();
}
}
You are redirecting twice the event. It would be easier for us, if you show how your complete event raising
Related
I made a simple event system by following a tutorial, the registration of listeners and firing events works well, but I can't remove any listener from it.
delegate void EventListener(EventInfoBase eventInfo);
Dictionary<System.Type, List<EventListener>> eventListeners;
public void RegisterListener<T>(System.Action<T> listener) where T : EventInfoBase
{
System.Type eventType = typeof(T);
if (eventListeners == null)
{
eventListeners = new Dictionary<System.Type, List<EventListener>>();
}
if (!eventListeners.ContainsKey(eventType) || eventListeners[eventType] == null)
{
eventListeners[eventType] = new List<EventListener>();
}
EventListener wrapper = (ei) => { listener((T)ei); };
eventListeners[eventType].Add(wrapper);
}
public void UnregisterListener<T>(System.Action<T> listener) where T : EventInfoBase
{
System.Type eventType = typeof(T);
if (eventListeners == null)
{
return;
}
if (!eventListeners.ContainsKey(eventType) || eventListeners[eventType] == null)
{
return;
}
EventListener wrapper = (ei) => { listener((T)ei); };
EventListener toRemove = eventListeners[eventType].Find(x => x.Equals(wrapper));
//EventListener toRemove = eventListeners[eventType].Find(x => x.Target == wrapper.Target && x.Method == wrapper.Method);
if (toRemove != null)
{
eventListeners[eventType].Remove(toRemove); // Never gets called
}
}
This is how it's called (it's a singleton):
EventsSystem.Instance.RegisterListener<EventInfoWin>(OnWin);
EventsSystem.Instance.UnregisterListener<EventInfoWin>(OnWin);
So I expected the listener to be removed from appropriate list, but it stays there. The UnregisterListener method does nothing. Any way to fix it quickly without rewriting everything?
Your problem is that in RegisterListener<T> you create an anonymous wrapper method of type EventListener and in UnregisterListener<T> you create another wrapper method. These wrappers will never match.
What you can do is to store the original listener along with the wrapper. That will allow you to match with the original listener, but execute the wrapper (to execute the original listener you would need reflection - hence the wrapper). If you switch from a dictionary to a list of tuples, you can do this in a straightforward way:
delegate void EventListener(object eventInfo);
List<(System.Type Type, Delegate Listener, EventListener Wrapper)> eventListeners;
public void RegisterListener<T>(System.Action<T> listener)
{
System.Type eventType = typeof(T);
if (eventListeners == null)
{
eventListeners = new List<(System.Type, Delegate, EventListener)>();
}
if (!eventListeners.Any(entry => entry.Type.Equals(eventType) &&
entry.Listener.Equals(listener))) {
eventListeners.Add((eventType, listener, ei => listener((T)ei)));
}
}
public void UnregisterListener<T>(System.Action<T> listener)
{
System.Type eventType = typeof(T);
if (eventListeners == null)
{
return;
}
var toRemove = eventListeners.FirstOrDefault(entry => entry.Type.Equals(eventType) &&
entry.Listener.Equals(listener));
eventListeners.Remove(toRemove);
}
You can try it out here.
You cannot use the wrapper delegate as you do. the reason is, that this is creating another "object" on adding, which will not be be recognizable later when you want to remove it.
As Jon Skeet wrote, you can just save the action directly, but as an object. I've tested it, and I did not find a way to have an list with Action of EventInfoBase putting in an Action of EventInfoWin.
So that is what it could look like:
EDIT: I've created a wrapper again, but with the original action as a token to find it again.
delegate void EventListener(EventInfoBase eventInfo);
private class EventWrapper
{
public EventListener Action { get; set; }
public object Token { get; set; }
}
Dictionary<System.Type, List<EventWrapper>> eventListeners = new Dictionary<System.Type, List<EventWrapper>>();
public void RegisterListener<T>(System.Action<T> listener) where T : EventInfoBase
{
System.Type eventType = typeof(T);
if (!eventListeners.ContainsKey(eventType) || eventListeners[eventType] == null)
{
eventListeners[eventType] = new List<EventWrapper>();
}
EventListener action = (ei) => { listener((T)ei); };
var wrapper = new EventWrapper() { Action = action, Token = listener };
eventListeners[eventType].Add(wrapper);
}
public void UnregisterListener<T>(System.Action<T> listener) where T : EventInfoBase
{
System.Type eventType = typeof(T);
if (!eventListeners.ContainsKey(eventType) || eventListeners[eventType] == null)
{
return;
}
var toRemove = eventListeners[eventType].FirstOrDefault(x => x.Token.Equals(listener));
if (toRemove != null)
{
eventListeners[eventType].Remove(toRemove);
}
}
Good day!
My purpose is to implement class which will allow us subscribe and unsubscribe objects to(from) events. Here is the code of my class.
public static class EventSubscriber
{
public static void AddEventHandler(EventInfo eventInfo, object item, Action action)
{
var parameters = GetParameters(eventInfo);
var handler = GetHandler(eventInfo, action, parameters);
eventInfo.AddEventHandler(item, handler);
}
public static void RemoveEventHandler(EventInfo eventInfo,
object item, Action action)
{
var parameters = GetParameters(eventInfo);
var handler = GetHandler(eventInfo, action, parameters);
eventInfo.RemoveEventHandler(item, handler);
}
private static ParameterExpression[] GetParameters(EventInfo eventInfo)
{
return eventInfo.EventHandlerType
.GetMethod("Invoke")
.GetParameters()
.Select(parameter => Expression.Parameter(parameter.ParameterType))
.ToArray();
}
private static Delegate GetHandler(EventInfo eventInfo,
Action action, ParameterExpression[] parameters)
{
return Expression.Lambda(
eventInfo.EventHandlerType,
Expression.Call(Expression.Constant(action),
"Invoke", Type.EmptyTypes), parameters)
.Compile();
}
}
As you can see here are 2 public methods which actually subscribe and unsubscribe objects to(from) event. And here is the sample how I test it
class Program
{
static void Main()
{
Test test = new Test();
test.SubscribeTimer();
while (true)
{
if(test.a == 10)
{
break;
}
}
test.UnsubscribeTimer();
while (true)
{
}
}
}
class Test
{
System.Timers.Timer timer;
public int a = 0;
public Test()
{
timer = new System.Timers.Timer(1000);
timer.Start();
}
public void SubscribeTimer()
{
var eventInfo = typeof(System.Timers.Timer).GetEvent("Elapsed");
EventSubscriber.AddEventHandler(eventInfo, timer, TimerElapsed);
EventSubscriber.RemoveEventHandler(eventInfo, timer, TimerNotElapsed);
}
public void UnsubscribeTimer()
{
var eventInfo = typeof(System.Timers.Timer).GetEvent("Elapsed");
EventSubscriber.AddEventHandler(eventInfo, timer, TimerNotElapsed);
EventSubscriber.RemoveEventHandler(eventInfo, timer, TimerElapsed);
}
public void TimerElapsed()
{
Console.WriteLine("timer elapsed");
a++;
}
public void TimerNotElapsed()
{
Console.WriteLine("timer not elapsed");
a++;
}
}
The expected behaviour of sample is that on the begining we will see the message "timer elapsed" every second, after 10-th second we should see only "timer not elapsed" and we do, but we still see "timer elapsed" too. This means that AddEventHandler method works, but RemoveEventHandler method doesn't.
I would be very happy if you will help me. Thanks in advance.
Had to stitch a bunch of sources together to get what I needed which was a one-stop extension method (that could be easily modified if we switched component vendors) to simply clear all existing Event Handlers on an Event we did not control.
Usage is simple:
thirdPartyControlInstance.ClearEventHandlers(nameof(ThirdPartyControlType.ToolClick));
Here is the code, any suggestions to make it more robust/efficient/cleaner are welcome:
public static class EventExtensions
{
public static void ClearEventHandlers(this object obj, string eventName)
{
if (obj == null)
{
return;
}
var objType = obj.GetType();
var eventInfo = objType.GetEvent(eventName);
if (eventInfo == null)
{
return;
}
var isEventProperty = false;
var type = objType;
FieldInfo eventFieldInfo = null;
while (type != null)
{
/* Find events defined as field */
eventFieldInfo = type.GetField(eventName, BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
if (eventFieldInfo != null && (eventFieldInfo.FieldType == typeof(MulticastDelegate) || eventFieldInfo.FieldType.IsSubclassOf(typeof(MulticastDelegate))))
{
break;
}
/* Find events defined as property { add; remove; } */
eventFieldInfo = type.GetField("EVENT_" + eventName.ToUpper(), BindingFlags.Static | BindingFlags.Instance | BindingFlags.NonPublic);
if (eventFieldInfo != null)
{
isEventProperty = true;
break;
}
type = type.BaseType;
}
if (eventFieldInfo == null)
{
return;
}
if (isEventProperty)
{
// Default Events Collection Type
RemoveHandler<EventHandlerList>(obj, eventFieldInfo);
// Infragistics Events Collection Type
RemoveHandler<EventHandlerDictionary>(obj, eventFieldInfo);
return;
}
if (!(eventFieldInfo.GetValue(obj) is Delegate eventDelegate))
{
return;
}
// Remove Field based event handlers
foreach (var d in eventDelegate.GetInvocationList())
{
eventInfo.RemoveEventHandler(obj, d);
}
}
private static void RemoveHandler<T>(object obj, FieldInfo eventFieldInfo)
{
var objType = obj.GetType();
var eventPropertyValue = eventFieldInfo.GetValue(obj);
if (eventPropertyValue == null)
{
return;
}
var propertyInfo = objType.GetProperties(BindingFlags.NonPublic | BindingFlags.Instance)
.FirstOrDefault(p => p.Name == "Events" && p.PropertyType == typeof(T));
if (propertyInfo == null)
{
return;
}
var eventList = propertyInfo?.GetValue(obj, null);
switch (eventList) {
case null:
return;
case EventHandlerDictionary typedEventList:
typedEventList.RemoveHandler(eventPropertyValue, typedEventList[eventPropertyValue]);
break;
}
}
}
Hope this helps someone!
I think it's because you are creating a new handler each time: (which doesn't match the previous handler, so can't be removed from the invocation list)
public static void RemoveEventHandler(EventInfo eventInfo,
object item, Action action)
{
var parameters = GetParameters(eventInfo);
var handler = GetHandler(eventInfo, action, parameters); // <--
eventInfo.RemoveEventHandler(item, handler);
}
Why are you wrapping the Action? To lose the parameters? It is not possible to add/remove the eventInfo.RemoveEventHandler(item, action); because of the parameters. If you want to remove a newly generated handler, you should return that handler when you want to remove it.
public static Delegate AddEventHandler(EventInfo eventInfo, object item, Action action)
{
var parameters = GetParameters(eventInfo);
var handler = GetHandler(eventInfo, action, parameters);
eventInfo.AddEventHandler(item, handler);
return handler;
}
public static void RemoveEventHandler(EventInfo eventInfo,
object item, Delegate handler)
{
eventInfo.RemoveEventHandler(item, handler);
}
var handler = EventSubscriber.AddEventHandler(eventInfo, timer, TimerElapsed);
EventSubscriber.RemoveEventHandler(eventInfo, timer, handler);
Is there a way to subscribe a method though it would be called last when the onNext is raised?
m_subject.Subscribe(() => Console.writeLine("firstSubscription");
m_subject.SubscribeLast(() => Console.writeLine("secondSubscription");
m_subject.Subscribe(() => Console.writeLine("thirdSubscription");
m_subject.OnNext();
// prints:
// firstSubscription
// thirdSubscription
// secondSubscription
You cannot have a subscriber be executed last, but you can wrap all your calls in a single subscription.
Something like that:
Action action = () => {};
Action lastAction = () => {};
m_subject.Subscribe(() =>
{
action();
lastAction();
});
action += (() => Console.writeLine("firstSubscription");
lastAction += (() => Console.writeLine("secondSubscription");
action += (() => Console.writeLine("thirdSubscription");
m_subject.OnNext();
// prints:
// firstSubscription
// thirdSubscription
// secondSubscription
You can also do this by defining a custom Subject<T> which internally has a default subject and also a last subject.
Update
I added overloads of ObserveOn to store the IScheduler and SynchronizationContext and then apply those at the time of subscription. Similar technique can be used to enable SubscribeOn to work as well.
public class SubscribeLastSubject<T> : ISubject<T>, IDisposable
{
private readonly Subject<T> subject = new Subject<T>();
private readonly Subject<T> lastSubject = new Subject<T>();
private IScheduler observeScheduler;
private SynchronizationContext observerContext;
public void OnNext(T value)
{
subject.OnNext(value);
lastSubject.OnNext(value);
}
public void OnError(Exception error)
{
subject.OnError(error);
lastSubject.OnError(error);
}
public void OnCompleted()
{
subject.OnCompleted();
lastSubject.OnCompleted();
}
public IDisposable Subscribe(IObserver<T> observer)
{
return GetObservable().Subscribe(observer);
}
public IDisposable SubscribeLast(IObserver<T> observer)
{
return GetLastObservable().Subscribe(observer);
}
public IDisposable SubscribeLast(Action<T> action)
{
return GetLastObservable().Subscribe(action);
}
public SubscribeLastSubject<T> ObserveOn(IScheduler scheduler)
{
observeScheduler = scheduler;
return this;
}
public SubscribeLastSubject<T> ObserveOn(SynchronizationContext context)
{
observerContext = context;
return this;
}
public void Dispose()
{
subject.Dispose();
lastSubject.Dispose();
}
private IObservable<T> GetObservable()
{
if (observerContext != null)
{
return subject.ObserveOn(observerContext);
}
if (observeScheduler != null)
{
return subject.ObserveOn(observeScheduler);
}
return subject;
}
private IObservable<T> GetLastObservable()
{
if (observerContext != null)
{
return lastSubject.ObserveOn(observerContext);
}
if (observeScheduler != null)
{
return lastSubject.ObserveOn(observeScheduler);
}
return lastSubject;
}
}
Usage
var m_subject = new SubscribeLastSubject<string>();
m_subject.ObserveOn(Scheduler.CurrentThread).Subscribe(s => Console.WriteLine("firstSubscription"));
m_subject.ObserveOn(Scheduler.CurrentThread).SubscribeLast(s => Console.WriteLine("secondSubscription"));
m_subject.ObserveOn(Scheduler.CurrentThread).Subscribe(s => Console.WriteLine("thirdSubscription"));
m_subject.OnNext("1");
Console.ReadKey();
Output
firstSubscription
thirdSubscription
secondSubscription
I'm having some hard time understanding the Subject object.
Consider the following code:
var sub = new Subject<int>();
sub.Subscribe(x => Console.WriteLine(x)); //subscriber #1
sub.Subscribe(x => Console.WriteLine(x)); //subscriber #2
sub.OnNext(2);
I'm creating a subject of int, and when i execute OnNext it calls the other subscribers (#1 and #2).
The thing that i don't get is that i read that Subject means an object which is both observable and observer but how does this explains why when i call OnNext the other subscribers are called.
I would understand if OnNext of the subject would propagate it to all subscribers = publish to all others (which make sense) but when I checked the source code i couldn't see anything that does it, see below.
Can someone maybe understand from the code below what exactly makes the OnNext(2) propagate to the other subscriptions? (#1, #2)?
public sealed class Subject : ISubject, ISubject, IObserver, IObservable, IDisposable
{
// Fields
private volatile IObserver _observer;
// Methods
public Subject()
{
this._observer = NopObserver<T>.Instance;
}
public void Dispose()
{
this._observer = DisposedObserver<T>.Instance;
}
public void OnCompleted()
{
IObserver<T> comparand = null;
IObserver<T> completed = DoneObserver<T>.Completed;
do
{
comparand = this._observer;
}
while (((comparand != DisposedObserver<T>.Instance) && !(comparand is DoneObserver<T>)) && (Interlocked.CompareExchange<IObserver<T>>(ref this._observer, completed, comparand) != comparand));
comparand.OnCompleted();
}
public void OnError(Exception error)
{
if (error == null)
{
throw new ArgumentNullException("error");
}
IObserver<T> comparand = null;
DoneObserver<T> observer3 = new DoneObserver<T> {
Exception = error
};
DoneObserver<T> observer2 = observer3;
do
{
comparand = this._observer;
}
while (((comparand != DisposedObserver<T>.Instance) && !(comparand is DoneObserver<T>)) && (Interlocked.CompareExchange<IObserver<T>>(ref this._observer, observer2, comparand) != comparand));
comparand.OnError(error);
}
public void OnNext(T value)
{
this._observer.OnNext(value);
}
public IDisposable Subscribe(IObserver<T> observer)
{
if (observer == null)
{
throw new ArgumentNullException("observer");
}
IObserver<T> comparand = null;
IObserver<T> observer3 = null;
do
{
comparand = this._observer;
if (comparand == DisposedObserver<T>.Instance)
{
throw new ObjectDisposedException("");
}
if (comparand == DoneObserver<T>.Completed)
{
observer.OnCompleted();
return Disposable.Empty;
}
DoneObserver<T> observer4 = comparand as DoneObserver<T>;
if (observer4 != null)
{
observer.OnError(observer4.Exception);
return Disposable.Empty;
}
if (comparand == NopObserver<T>.Instance)
{
observer3 = observer;
}
else
{
Observer<T> observer5 = comparand as Observer<T>;
if (observer5 != null)
{
observer3 = observer5.Add(observer);
}
else
{
observer3 = new Observer<T>(new ImmutableList<IObserver<T>>(new IObserver<T>[] { comparand, observer }));
}
}
}
while (Interlocked.CompareExchange<IObserver<T>>(ref this._observer, observer3, comparand) != comparand);
return new Subscription<T>((Subject<T>) this, observer);
}
private void Unsubscribe(IObserver<T> observer)
{
IObserver<T> comparand = null;
IObserver<T> instance = null;
Label_0004:
comparand = this._observer;
if ((comparand != DisposedObserver<T>.Instance) && !(comparand is DoneObserver<T>))
{
Observer<T> observer4 = comparand as Observer<T>;
if (observer4 != null)
{
instance = observer4.Remove(observer);
}
else
{
if (comparand != observer)
{
return;
}
instance = NopObserver<T>.Instance;
}
if (Interlocked.CompareExchange<IObserver<T>>(ref this._observer, instance, comparand) != comparand)
{
goto Label_0004;
}
}
}
// Properties
public bool HasObservers
{
get
{
return (((this._observer != NopObserver<T>.Instance) && !(this._observer is DoneObserver<T>)) && (this._observer != DisposedObserver<T>.Instance));
}
}
// Nested Types
private class Subscription : IDisposable
{
// Fields
private IObserver<T> _observer;
private Subject<T> _subject;
// Methods
public Subscription(Subject<T> subject, IObserver<T> observer)
{
this._subject = subject;
this._observer = observer;
}
public void Dispose()
{
IObserver<T> observer = Interlocked.Exchange<IObserver<T>>(ref this._observer, null);
if (observer != null)
{
this._subject.Unsubscribe(observer);
this._subject = null;
}
}
}
}
I know that but what bothers me is that it didn't make sense. I dug further into the code and found out that their internal implementation of observer contains more observers, see below.
And if you check the OnNext method you can see that they are iterating over all the observers and calling their OnNext method.
Now everything make sense to me, i understood the logic but couldn't see where it was implemented.
internal class Observer<T> : IObserver<T>
{
private readonly ImmutableList<IObserver<T>> _observers;
public Observer(ImmutableList<IObserver<T>> observers)
{
this._observers = observers;
}
internal IObserver<T> Add(IObserver<T> observer)
{
return new Observer<T>(this._observers.Add(observer));
}
public void OnCompleted()
{
foreach (IObserver<T> observer in this._observers.Data)
{
observer.OnCompleted();
}
}
public void OnError(Exception error)
{
foreach (IObserver<T> observer in this._observers.Data)
{
observer.OnError(error);
}
}
public void OnNext(T value)
{
foreach (IObserver<T> observer in this._observers.Data)
{
observer.OnNext(value);
}
}
internal IObserver<T> Remove(IObserver<T> observer)
{
int index = Array.IndexOf<IObserver<T>>(this._observers.Data, observer);
if (index < 0)
{
return this;
}
if (this._observers.Data.Length == 2)
{
return this._observers.Data[1 - index];
}
return new Observer<T>(this._observers.Remove(observer));
}
}
Subject is an observable because you can subscribe to it. You do it in your example (you did subscribe two subscribers).
Subject is also an observer because you can do the following:
someObservable.Subscribe(subject);
That way your subject will receive the events from someObservable and propagate them to its own subscribers.
P.S. in your code you called the OnNext() method yourself. But that is exactly what will someObservable do when you subscribe to it with your subject.
Have tried to solve this for quite a while now, but without luck... My idea was to have some sort of a configuration for different settings, for instance.. controlling how exceptions are handled.
Some of my code :)
public class ErrorEventArgs : EventArgs
{
public bool Handled { get; set; }
...
...
}
A property in my main class like :
EventHandler<ErrorEventArgs> ErrorConfiguration {get; set;}
I then have an OnError where I need to know value of Handled,
internal void OnError(ErrorEventArgs args)
{
Func<EventHandler<ErrorEventArgs>, bool> IsHandled;
IsHandled = ev => ??? // invoke ErrorConfiguration?
if (ErrorConfiguration != null && IsHandled(ErrorConfiguration ))
error(this, args);
}
How can this be solved?
I can do like this, if it's the EventHandler without the Func, but I want to encapsulate the boolean expression. Why cant I chain the lambda... :(
EventHandler<ErrorEventArgs> IsHandled;
IsHandled = (sender, e) => e.ErrorContext.Handled;
I am not completely sure what you want to achieve, exactly. But you can do something like:
IsHandled = ev => { ev(this, args); return args.Handled; };
Even though I am not sure this is more readable, faster, cleaner, or anything like that. I would just go with something like
if (ErrorConfiguration != null) ErrorConfiguration(this, args);
if (!args.Handled) error(this, args);
You really don't need any lambda to call your just need to call your delegate directly:
internal void OnError(ErrorEventArgs args)
{
if (ErrorConfiguration != null)
ErrorConfiguration(this, args);
if (args.Handled)
error(this, args);
}
If you want to the use the same thing in a lambda, you'll have do to this, which will take more lines of code:
internal void OnError(ErrorEventArgs args) {
Func<EventHandler<ErrorEventArgs>, bool> IsHandled;
IsHandled = ev => {
ErrorConfiguration(this, ev);
return ev.Handled;
};
if (ErrorConfiguration != null && IsHandled(ErrorConfiguration ))
error(this, args);
}