i created a class and when i create an employee object via form , i want to give a message;
this is my class, event and delegate
public delegate void ctorDel();
class Employee
{
private int empID;
private string empName;
public event ctorDel myEvent;
public Employee(int empID,string empName)
{
this.empID = empID;
this.empName = empName;
**if (myEvent != null)
{
myEvent();
}**
}
and in form
int id = Convert.ToInt16(textBox1.Text);
string name = textBox2.Text;
Employee emp = new Employee(id, name);
emp.myEvent += new ctorDel(showMessage);
and function
public void showMessage()
{
MessageBox.Show("An employee is created");
}
What is it you're trying to accomplish? The reason what you've tried doesn't work is because you're attaching your delegate after the ctor. Once you've called "new Employee" the event is long since fired.
If you really need such an event, create a factory class:
public delegate void EmpCreated();
public EmployeeFactory {
public event EmpCreated myEvent;
public Employee Create(int empId, string empName){
var result = new Employee(empId, empName);
if(myEvent != null) myEvent();
return result;
}
}
Subscribe to the event on the factory class and you'll get the event.
You're attaching the event after the constructor has already run.
It doesn't make sense to raise an instance event in the constructor, because since the initialization of the instance is not yet complete, there can't be any handler attached to the event...
However, you could create a static event:
public static event ctorDel myEvent;
...
Employee.myEvent += new ctorDel(showMessage);
(but don't subscribe to the event every time you create an Employee, or the handler will be invoked as many times as there are instances...)
Solution
Here's a generic approach to your problem
public class EventFactory
{
public U Create<U, V>(V constructorArgs)
{
var instance = (U)Activator.CreateInstance(typeof(U), constructorArgs);
OnCreated?.Invoke();
return instance;
}
public delegate void CreatedEventHandler();
public event CreatedEventHandler OnCreated;
}
You can then do
var ef = new EventFactory();
ef.OnCreated += myEventHandler;
var instance = ef.Create<Employee>(employeeArgs);
.. Going further
It is possible to adjust my code to provide greater flexiblity when you need to pass event arguments or when the constructor is parameterless. I haven't tested it but it should look somewhere along the lines of
public class EventFactory<T>
{
public U Create<U, V>(V constructorArgs, T eventArgs)
{
var instance = (U)Activator.CreateInstance(typeof(U), constructorArgs);
OnCreated?.Invoke(eventArgs);
return instance;
}
public U Create<U>(T eventArgs)
{
return Create<U, object>(null, eventArgs);
}
public delegate void CreatedEventHandler(T args);
public event CreatedEventHandler OnCreated;
}
public class EventFactory
{
public U Create<U, V>(V constructorArgs)
{
var instance = (U)Activator.CreateInstance(typeof(U), constructorArgs);
OnCreated?.Invoke();
return instance;
}
public U Create<U>() where U : new()
{
var instance = new U();
OnCreated?.Invoke();
return instance;
}
public delegate void CreatedEventHandler();
public event CreatedEventHandler OnCreated;
}
You can pass the handler when creating the Employee:
private Employee(ctorDel construcEvent)
{
if (construcEvent != null)
this.myEvent += construcEvent;
}
public Employee(int empID,string empName, ctorDel construcEvent)
: this(construcEvent)
{
this.empID = empID;
this.empName = empName;
if (myEvent != null)
{
myEvent();
}
}
And then:
Employee emp = new Employee(id, name, new ctorDel(showMessage));
By the time you subscribe for this event the instance is already constructed.
I would recommend using Factory pattern to hide the constructor.
class EmployeeFactory
{
public Employee Create(int id, string name)
{
Employee instance = new Employee(id, name);
var handler = EmployeeCreated;
if (handler != null)
{
EmployeeEventArgs e = new EmployeeEventArgs(instance);
handler(e);
}
return instance;
}
public event EventHandler<EmployeeEventArgs> EmployeeCreated;
}
Event subscription:
factory.EmployeeCreated += MyHandler;
Instance construction:
var emp = factory.Create(id, name);
Related
I try to return an object in my event:
public class MyEvent : EventArgs
{
public Channels number = new Channels(); // Channels is a class where i declared only variables( i try to return all variables inside this class)
public MyEvent(Channels numero)
{
return numero;
}
}
This code doesn't work and i don't know how to return an object which contains my variables of Channels.
Change that to:
public class MyEvent : EventArgs
{
public Channels Number {get;}
public MyEvent(Channels numero)
{
Number = numero;
//return numero; You cannot use "return" in a CTOR!
}
}
Then you can use it in an EventHandler like this:
void MyEventHandler( object sender, MyEvent e )
{
// sender => object that raised the event
// e => an instance of `MyEvent`, having a property, we can read.
var channels = e.Number; // use the info
}
Of course you would have registered it, before it will be triggered:
someInstanceProvidingTheEvent.MyEventHappened += MyEventHandler;
Raising the event works something like this:
// assume we are in the class that offers the Event
public event EventHandler<MyEvent> MyEventHappened;
protected virtual void OnMyEventHappened( Channels chans )
{
// You may want to add some error fortification, here
MyEventHappened?.Invoke(this, new MyEvent(chans));
}
// raise it
public void SomeMethod(){
var theChannels = new Channels();
// yadda yadda
// now it happens!
OnMyEventHappened(theChannels);
}
public class MyEvent : EventArgs
{
public Channels _channels { get; set; }
public MyEvent(Channels numero)
{
_channels = numero;
}
}
public class Program
{
public Main()
{
Channels myChannels = new Channels();
MyEvent _myEvent = new MyEvent(myChannels);
var youWant = _myEvent._channels;
}
}
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? :)
I have WebSocket class configured as a singleton:
public class ViSoftAdsHub : ViewModelBase
{
private static ViSoftAdsHub _instance;
ViSoftAdsHub()
{
ConnectAsync();
}
public static ViSoftAdsHub Instance
{
get
{
if (_instance == null)
{
_instance = new ViSoftAdsHub();
}
return _instance;
}
}
}
Multiple object instances of any type can add a notification to this singleton:
public void AddNotification(string name, ConfigurationsConfigSectionAdd sourceConfig,Type t)
{
NotificationObject no = new NotificationObject
{
ConnectionSettings = sourceConfig,
Name = name,
type = t
};
_Notifications.Add(name, no);
}
I need the callback only to be fired in the callback of the object who created the notification. Now, when a notification is received in the hub it fires on all callbacks on all objects.
This is the event implementation in the singleton:
protected virtual void OnNotification(ViSoftNotificationEventArgs e)
{
EventHandler<ViSoftNotificationEventArgs> handler = Notification;
if (handler != null)
{
handler(this, e);
}
}
public event EventHandler<ViSoftNotificationEventArgs> Notification;
public void OnMessage2(ViSoftNotificationEventArgs arg1, Type arg2)
{
OnNotification(arg1 as ViSoftNotificationEventArgs);
}
caller method of objects subscribing to the event:
hub = ViSoftAdsHub.Instance;
hub.Notification += new EventHandler<ViSoftNotificationEventArgs>(Hub_Notification);
hub.AddNotification(Name, SourceConfig, typeof(Sometype));
I also get a major memory leak.
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
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.