How to raise parent class events with Expression (C#) - c#

I'm writing a class library for a Web API.
I have a base class and an interface with 30 blocks like this:
interface ISomethingApi {
void AuthenticateAsync(string username, string password);
event AsyncResponseHandler AuthenticateEnded;
void GetMemberAsync(string username);
event AsyncResponseHandler<Member> GetMemberEnded;
// more...
}
The base class called BaseHttpClient contains the implementation and all methods are empty and virtual.
class BaseHttpClient : ISomethingApi {
public virtual void GetMemberAsync(string username) {
throw new NotImplementedException();
}
public event AsyncResponseHandler<Member> GetMemberEnded;
// more...
}
Because the API is pretty non-standard, I am inheriting the base class with a XmlClient class. This class overrides virtual methods and do the job.
class XmlClient : BaseHttpClient {
public override void GetMemberAsync(string username) {
Member member;
// process here
// raising the event
GetMemberEnded(this, new AsyncResponseArgs<Member>(member));
// error: LogoffEnded can only appear on the left hand side of += or -=
}
}
The problem is I can't raise the events:
The event 'BaseHttpClient.LogoffEnded' can only appear on the left hand side of += or -=
A basic solution is to create methods in the base class like
protected void RaiseLogoffEnded(AsyncResponseArgs args) {
if (LogoffEnded != null) {
LogoffEnded(this, args);
}
}
But there are too many methods to create. I'd like to do something like:
public override void GetMemberAsync(string username) {
Member member;
// work done here
RaiseEvent(x => x.GetMemberEnded, new AsyncResponseArgs<Member>(member));
}
I suppose this is about reflection and expressions.
Is it a right way to do? (performace)
What documentation could I read to make this?
could you show me a valid code for this?

You could use a couple of static extension methods:
static class Extensions
{
public static void Raise(this EventHandler #event, object sender, EventArgs e)
{
if (#event != null)
#event(sender, e);
}
public static void Raise<T>(this EventHandler<T> #event, object sender, T e) where T : EventArgs
{
if (#event != null)
#event(sender, e);
}
}
Whereby you could do:
public class MyClass
{
public event EventHandler MyEvent;
public void DoSomething()
{
MyEvent.Raise(this, EventArgs.Empty);
}
}
While you can in fact use an expression, e.g.:
public void Raise<T>(Expression<Func<EventHandler<T>>> expr, T eventArgs)
where T : EventArgs
{
EventHandler<T> handler = expr.Compile().Invoke();
handler(this, eventArgs);
}
You probably want to do away with the redundant expression, and just use a Func<T> instead, as you are raising the event from the class directly. Through expressions, you would need to compile the expression, whereas Func<T> you don't:
public void Raise<T>(Func<EventHandler<T>> func, T eventArgs)
where T : EventArgs
{
EventHandler<T> handler = func();
handler(this, eventArgs);
}

You can make use of System.ComponentModel.EventHandlerList which will net you two advantages:
1) You will have your FireEvent mechanism.
2) The Events member doesn't use memory unless there are delegates subscribed. If you have a class with 30 events, you have 30 pointers in your class' footprint, whether or not there are any subscribers. EventHandlerList is a single object that contains any and all delegates subscribed. It's a very light-weight map (not a Dictionary). Notice that the event keys are static objects so as not to add to the class' footprint.
class AsyncResponseArgs : EventArgs
{
public Member Member { get; private set; }
public AsyncResponseArgs(Member m)
{
Member = m;
}
}
interface ISomethingApi
{
void AuthenticateAsync(string username, string password);
event EventHandler<AsyncResponseArgs> AuthenticateEnded;
void GetMemberAsync(string username);
event EventHandler<AsyncResponseArgs> GetMemberEnded;
}
class BaseHttpClient : ISomethingApi
{
private EventHandlerList Events = new EventHandlerList();
public virtual void AuthenticateAsync(string username, string password)
{
throw new NotImplementedException();
}
protected static object AuthenticateEndedEvent = new object();
public event EventHandler<AsyncResponseArgs> AuthenticateEnded
{
add { Events.AddHandler(AuthenticateEndedEvent, value); }
remove { Events.RemoveHandler(AuthenticateEndedEvent, value); }
}
public virtual void GetMemberAsync(string username)
{
throw new NotImplementedException();
}
protected static object GetMemberEndedEvent = new object();
public event EventHandler<AsyncResponseArgs> GetMemberEnded
{
add { Events.AddHandler(GetMemberEndedEvent, value); }
remove { Events.RemoveHandler(GetMemberEndedEvent, value); }
}
protected void FireEvent(object key, AsyncResponseArgs e)
{
EventHandler<AsyncResponseArgs> handler = (EventHandler<AsyncResponseArgs>)Events[key];
if (handler != null)
handler(this, e);
}
}
class XmlClient : BaseHttpClient
{
public override void GetMemberAsync(string username)
{
Member member;
// process here
FireEvent(GetMemberEndedEvent, new AsyncResponseArgs(member));
}
}
Added:
You can save yourself some typeing in BaseHttpClient by writing a code snippet.

You have to move your RaiseXXX methods to parent class, where you have your events defined. Make sure these methods are at least protected.
And don't forget to call your events via local variable to minimize error field.
var e = MyEvent;
if (e != null) e(this, EventArgs.Empty);

You could add a method to the base class that takes the event name as a String and raises the corresponding event via reflection like
public void Raise(String eventName, object source, EventArgs eventArgs)
{
var field = this.GetType().GetField(eventName, BindingFlags.Instance | BindingFlags.NonPublic);
if (field == null)
throw new ArgumentException("No such event: " + eventName);
var eventDelegate = (MulticastDelegate)field.GetValue(this);
if (eventDelegate != null)
foreach (var handler in eventDelegate.GetInvocationList())
handler.Method.Invoke(handler.Target, new object[] { source, eventArgs });
}
I don't know anything about performance, though.

Related

.NET c# - how to pass aditional data to PropertyChangedEventHandler

I have this code :
public void SomeMethod()
{
MyClass clss = new MyClass(); //note: MyClass implements INotifyPropertyChanged
clss.DoSomething();
clss.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(MyEventHandler);
}
static void MyEventHandler(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
Debug.WriteLine("some property on MyClass has changed!");
}
This is working ok and when the property in SomeClass changes, MyEventHandler() is run.
But now I need to pass aditional data from SomeMethod() to MyEventHandler() , how can I do this?
* UPDATE *
ok I guess I should have explained better the whole problem: the method DoSomething() in MyClass makes a call to an external web service, passing it a callback so when the web service finish its work, it will call the callback, passing it a value with the result of the operation. Inside that callback, I am changing a property of the class to assign it the value received from the web service, thus triggering the propertyChanged event.
Then in the caller class, I subscribe to that event so I can do some things when it happens.
The final objective is, after calling DoSomething(), be able to wait until the web service has finished its job and returned a result, so I can then save some things in the database etc. and only then, return from SomeMethod()...
so this is MyClass, simplified:
public class MyClass : INotifyPropertyChanged
{
private long _wsReturnValue;
public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
public long wsReturnValue
{
get { return _wsReturnValue; }
set {
_wsReturnValue = value;
OnPropertyChanged("wsReturnValue");
}
}
protected void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
handler(this, new System.ComponentModel.PropertyChangedEventArgs(name));
}
public void DoSomething(object entity)
{
//here I just call external web service and returns, the webservice will call TheCallback() when finished
}
public void TheCallback(CommunicationEventArgs e)
{
this.wsReturnValue = e.res;
}
}
And this is the class that uses MyClass:
class MainClass
{
public void SomeMethod(object someObject)
{
MyClass clss = new MyClass(); //note: MyClass implements INotifyPropertyChanged
clss.DoSomething(someObject); //someObject contains data that I want to use later in the event handler
clss.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(MyEventHandler);
}
private static void MyEventHandler(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
//here I need to use the object someObject...
}
}
Not sure if this is even close to what you mean, but here you go;
class EventClass
{
public void SomeMethod()
{
MyClass clss = new MyClass(); //note: MyClass implements INotifyPropertyChanged
clss.DoSomething(new object());
clss.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(MyEventHandler);
}
private static void MyEventHandler(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
var customeEventArgs = (CustomEventArgs) e;
Debug.WriteLine("some property on MyClass has changed! Extra Data : {0}", customeEventArgs.ExtraData);
}
}
Implemented some more shell code to illustrate
internal class MyClass
{
public void DoSomething(object data)
{
var e = new CustomEventArgs("Property")
{
ExtraData = data
};
PropertyChanged?.Invoke(this, e);
}
public event PropertyChangedEventHandler PropertyChanged;
}
internal class CustomEventArgs : PropertyChangedEventArgs
{
public CustomEventArgs(string propertyName) : base(propertyName)
{
}
public object ExtraData { get; set; }
}
Any help? :)

xamarin EventHandler is always null

I have a code which should notify a delegate in one of service classes on receiving an event:
public class TestClass : ParentClass
{
public event EventHandler<string> MyDelegate;
public override void OnAction(Context context, Intent intent)
{
var handler = MyDelegate;
if (handler != null)
{
handler(this, "test");
}
}
}
I instantiate it by:
private TestClass mytest= new TestClass ();
And then assign it in one of the functions:
mytest.MyDelegate+= (sender, info) => {
};
The delegate never gets called. I have stepped through with debugger and I see that delegate is being assigned, but the check inside a class is always null... Cant figure out whats the problem...
Sounds like an execution order issue. What could be happening is that OnAction within TestClass is being called before the delegate hookup. Try the following:
public class TestClass : ParentClass
{
public event EventHandler<string> MyDelegate;
public class TestClass(Action<string> myAction)
{
MyDelegate += myAction;
}
public override void OnAction(Context context, Intent intent)
{
var handler = MyDelegate;
if (handler != null)
{
handler(this, "test");
}
}
}
Just pass the delegate through the constructor, this should make sure its hooked up before any calls to OnAction()
You can pass through the handler in a couple ways:
1.) As an anonymous method:
private TestClass mytest= new TestClass ((sender, info) => { Console.WriteLine("Event Attached!") });
2.) Pass in the method group:
public class MyEventHandler(object sender, string e)
{
Console.WriteLine("Event Attached!");
}
private TestClass mytest= new TestClass(MyEventHandler);
I generally recommend the second way as it allows you to unhook the handler and do clean up once you are done with it:
myTest.MyDelegate -= MyEventHandler;

Events only being detected by single instance of class

I am trying to write an abstract class that contains data common to multiple components of an application and provides the ability for those components to notify other components that the data they're working on has changed. Unfortunately, none of the other components are picking up the events being fired. I decided to write up a quick test to see if I could pinpoint what was wrong, but I'm running into the exact same issues. Am I misunderstanding how events work? Or am I missing something obvious?
void Main()
{
EventHandler<string> EVENT = delegate {};
var test = new DerivedClass("test", ref EVENT, 6);
var test2 = new DerivedClass("test2", ref EVENT, 8);
test.Number = 7;
test2.Number = 4;
}
public class DerivedClass : BaseClass
{
protected override void OnChanged(object sender, string e)
{
Console.WriteLine(string.Format("Derived class event fired from {0}! New value is {1}", sender, e));
}
public DerivedClass(string name, ref EventHandler<string> handler, int val) : base(ref handler, val)
{
this._name = _name;
}
public override string ToString()
{
return _name;
}
string _name;
}
public abstract class BaseClass
{
public virtual int Number
{
get { return _number; }
set
{
_handler(this, value);
_number = value;
}
}
protected virtual void OnChanged(object sender, string e)
{
Console.WriteLine("Base class event fired! " + e);
}
protected BaseClass(ref EventHandler<string> handler, int val)
{
_number = val;
_handler = handler;
if (_handler != null) _handler += this.OnChanged;
}
protected event EventHandler<string> _handler;
protected int _number;
public override string ToString()
{
return "A BaseClass";
}
}
output:
Derived class event fired from test! New value is 7
Derived class event fired from test2! New value is 4
Am I misunderstanding how events work?
Probably. Specifically, you seem to be under the impression either that events are handled on a per-class basis, or that child class instances will all share the same parent class instance.
You've declared your event to be non-static:
protected event EventHandler<string> _handler;
So every instance of any class that extends this class will have its own instance of this event. Depending on what you're trying to accomplish, you might consider making the event static?

Event default initializer

I used to utilize the following:
public event EventHandler OnComplete = delegate { };
I'm not sure, how this is called, is this an "event default initializer"??
But the problem appeared to be when I derived from EventArgs, created my own EventHandler and decided to use the same approach. Please, see:
public class MyEventArgs : EventArgs
{
int result;
public int Result
{
get
{
if (exceptionObject == null)
return result;
else
throw new InvalidOperationException();
}
internal set { result = value; }
}
Exception exceptionObject;
public Exception ExceptionObject
{
get { return exceptionObject; }
internal set { exceptionObject = value; }
}
}
public delegate EventHandler MyEventHandler(object sender, MyEventArgs e);
public class MyOperation
{
public event MyEventHandler OnOperationComplete = delegate { };
}
So, the line
public event MyEventHandler OnOperationComplete = delegate { };
causes the problem.
How can I make the proper default initialization for "my" events?
public event MyEventHandler OnOperationComplete = (sender, args) => { return null; };
I also think you meant to say:
public delegate void MyEventHandler(object sender, MyEventArgs e);
not
public delegate EventHandler MyEventHandler(object sender, MyEventArgs e);
public event Action OnDied = delegate { };
The easiest method

How to make only farthest child receive shared event?

I have run into a bit of a design issue with my code.
I have a object that creates a child object (the child could then create another child, etc), and both objects subscribe to the same event.
But, I only want the most child object to receive the event.
Overview of what my project is:
I am creating a IVR system. When a user calls into the system, the user will have X menu choices. Based on what the user chooses they will have a sub menu of choices, and so on and so on. I am using State Machines for this. Every State Machine needs to "listen" for when the user presses a number on their phone. But only the current State Machine needs to process the entered number. Each State Machine can create a new State Machine to represent the sub menu.
Here is some sample code:
Base class:
public delegate void DoSomething(object sender, EventArgs data);
public class Base
{
public event DoSomething myEvent;
private IObject foo;
public Base ()
{
foo = new myObjectA(this);
}
public void SomeAction()
{
((myObjectA)foo).CreateChild();
}
public void EventFired()
{
if (myEvent != null)
{
myEvent(this, new EventArgs());
}
}
}
ObjectA:
class myObjectA : IObject
{
private Base theCallingObject;
private IObject child;
public myObjectA (Base _base)
{
theCallingObject = _base;
theCallingObject.myEvent += new DoSomething(theCallingObject_myEvent);
}
public void CreateChild()
{
child = new myObjectB(theCallingObject);
}
void theCallingObject_myEvent(object sender, EventArgs data)
{
// Handle event
MessageBox.Show("myObjectA");
}
}
ObjectB:
class myObjectB : IObject
{
private Base theCallingObject;
public myObjectB (Base _base)
{
theCallingObject = _base;
theCallingObject.myEvent += new DoSomething(theCallingObject_myEvent);
}
void theCallingObject_myEvent(object sender, EventArgs data)
{
// Handle event
MessageBox.Show("myObjectB");
}
}
Now when I do this:
Base blah = new Base();
blah.SomeAction();
blah.EventFired();
I get message boxes for both A and B.
I need to implement Base so that only myObjectB gets the event.
I will have hundreds of myObject's so I need a implementation at the Base level and NOT the myObject level. Plus, handling it at the myObject level would still require the event to be fired causing performance issues if there are hundreds of objects.
One solution I have considered is when myObjectA creates the child, unsubscribe from the event, then resubscribe when we get back to the myObjectA level. However I feel something better could be done.
Anyone have any ideas?
Edit: Using payo's input I have come up with this:
public delegate void DoSomething(object sender, EventArgs data);
public class Base
{
private IObject foo;
private List<DoSomething> _myEventStorage;
public event DoSomething myEvent
{
add
{
_myEventStorage.Insert(0, value);
}
remove
{
_myEventStorage.Remove(value);
}
}
public Base ()
{
_myEventStorage = new List<DoSomething>();
foo = new myObjectA(this);
}
public void SomeAction()
{
((myObjectA)foo).CreateChild();
}
public void EventFired()
{
_myEventStorage[0].Invoke(this, new EventArgs());
}
}
you would need to explicitly implement myEvent (add/remove) handlers and track the "farthest" independently of the registered observers. then you can send the notification to that single instance.
For events, each subscriber is queued up (put at end of list), a FIFO model. You want the most-child object to 'own' the event, not just subscribe and be part of some abstract list of other unknown objects.
I would provide a new model that represents what you are trying to do. This might be what Jason recommended: (he posted his answer as I was typing this out)
public class Base
{
private DoSomething _myEventStorage;
public event DoSomething myEvent
{
add
{
_myEventStorage = value;
}
remove
{
_myEventStorage -= value;
}
}
...
public void EventFired()
{
if (_myEventStorage != null)
{
_myEventStorage(this, new ChainEventArgs());
}
}
}
This calls last ONLY. Another option (to add to this custom add/remove) would be to provide a derived EventArgs:
public class ChainEventArgs : EventArgs
{
public bool Handled { get; set; }
}
public delegate void DoSomething(object sender, ChainEventArgs data);
...
public event DoSomething myEvent
{
add
{
var temp = _myEventStorage;
_myEventStorage = null;
_myEventStorage += value;
_myEventStorage += temp; // now all are called, but FILO
}
remove
{
_myEventStorage -= value;
}
}
At this point, you can either check Handled on each IObject
void theCallingObject_myEvent(object sender, ChainEventArgs data)
{
if (data.Handled)
return;
if (I_want_to_block_parents)
data.Handled = true;
// else leave it false
}
Or, add some complexity to your Base class and stop calling up the chain (let's the children have no need to check Handled). I'll show the solution with a List<> of delegates, but some MulticaseDelegate casts and calls could do the same. I just feel the List<> code might be more readable/maintainable.
public class Base
{
private List<DoSomething> _myEventStorage;
public event DoSomething myEvent
{
add
{
_myEventStorage.Insert(0, value);
}
remove
{
_myEventStorage.Remove(value);
}
}
...
public void EventFired()
{
var args = new ChainEventArgs();
foreach (var handler in _myEventStorage)
{
handler(this, args);
if (args.Handled)
break;
}
}
}

Categories