This question already has an answer here:
C# Handle Event
(1 answer)
Closed 8 years ago.
I have created this program here to demonstrate what i am trying to do. You can see that all the code is already written except the line where the _OnSell event should be invoked. (Line 21~)
using System;
namespace example
{
public class Car
{
public int Price;
public string ModelName;
private Boolean Sold;
public delegate void SellEventHandler(string str);
public event SellEventHandler _OnSell;
public Boolean _Sold
{
get { return Sold; }
set
{
Sold = value;
if (Sold == true)
{
// INVOKE _OnSell EVENT HERE !!
}
}
}
public void OnSell(string str)
{
Console.WriteLine("library stuff");
}
public Car(int price, string modelname)
{
Price = price;
ModelName = modelname;
Sold = false;
_OnSell = OnSell;
}
}
public class Program
{
static void Main()
{
Program p1 = new Program();
Car _car = new Car(6000, "audi");
_car._OnSell += p1.Car_OnSell;
_car._Sold = Console.ReadLine() == "true" ? true : false;
Console.ReadLine();
}
public void Car_OnSell(string message)
{
Console.WriteLine("user stuff");
}
}
}
I am trying to invoke the event _car._OnSell whenever the value _car._Sold is changed. How can i do that in C# ?
See Handling and Raising Events
Thus, following the example provided, the code would look like the following.
Note the name changes for a cleaner public API and de facto consistency and naming standards.
public class Car
{
// Note use of `sender` convention
public delegate void SoldEventHandler(object sender, string str);
// Events normally do not have the `On` prefix, also the event
// name is normally the sense-correct verb such as `Sold` or `Selling`.
public event SoldEventHandler Sold;
private bool _isSold;
public bool IsSold
{
get { return _isSold; }
set
{
if (value && !_isSold) {
// Only sell when false -> true
OnSold("whatever string it is supposed to be");
}
_isSold = value;
}
}
// "Typically, to raise an event, you add a method that is marked as protected and virtual.
// .. Name this method OnEventName; for example, OnDataReceived."
public virtual void OnSold(string str)
{
// Follow the conventions in the link - ask on SO as to why the local
// variable and check for null are important/necessary.
var handler = Sold;
if (handler != null) {
handler(this, str);
}
}
// ..
_car.Sold += p1.Car_OnSell;
_car.IsSold += Console.ReadLine() == "true" ? true : false;
In most cases I would recommend having the event take (object sender, EventArgs args) as it makes future changes to the event much more flexible - this is also discussed in the link.
As explained in the links offered by commenters (but unfortunately not explained in the first answer that was posted), you need to change your code so that it looks more like this:
public Boolean _Sold
{
get { return Sold; }
set
{
Sold = value;
if (Sold)
{
OnSell("your string here");
}
}
}
public void OnSell(string str)
{
SellEventHandler handler = _OnSell;
if (handler != null)
{
handler(str);
}
Console.WriteLine("library stuff");
}
The above will work. However, it's worth noting that you're deviating from the normal .NET event-handling idioms in a couple of important ways:
Your event delegate does not follow the EventHandler<T> structure. The normal .NET method signature offers two advantages: identification of the sender, and a standardized EventArgs data structure on which to base your event arguments.
You are raising the event only when the property is set to true. More typical, and frankly more useful, is a "changed" event. E.g. SoldChanged, which would be raised any time the value of the Sold property was changed.
One of the nicer benefits of following the standard event-handling idioms is that your class will work with most if not all of the common data binding implementations in .NET. The way you have it implemented here, your event is very limited in the way it can be used. That might be fine in this scenario, but as a general rule it's so easy to provide more flexible implementation, you might as well get in the habit of doing so.
Try this:
_OnSell( "some message" );
Related
I have a simple delegate, event and property allowing me to create callback subscriptions on events:
public static class Test
{
/// <summary>Delegate for property changed event</summary>
public delegate void TestEventHandler();
/// <summary>Event called when value is changed</summary>
public static event TestEventHandler OnTestHappening;
/// <summary>Property to specify our test is happening</summary>
private static bool testHappening;
public static bool TestHappening
{
get
{
return testHappening;
}
set
{
testHappening = value;
// Notify our value has changed only if True
// ie. Only fire an event when we're ready as we'll hook methods to the Event that must only fire if ready
if ( value )
{
if ( OnTestHappening != null )
OnTestHappening();
}
}
}
}
I can then easily subscribe and unsubscribe to the event and fire the event callbacks as needed:
public class Tester
{
private void Main()
{
Testing();
// Start the test
Test.TestHappening = true;
}
private void Testing()
{
// Unsubscribe from event
Test.OnTestHappening -= Testing;
// Check if we're busy testing yet
if ( !Test.TestHappening )
{
// Subscribe to event
Test.OnTestHappening += new Test.TestEventHandler( Testing );
return;
}
// Do stuff here....
}
}
When compiling, code analysis gives me, "CA1009: Declare event handlers correctly?" and I've searched high and low and found many questions, articles etc but none that feel like they address my scenario. I can't seem to find a concrete starting point for the conversion and I'm starting to wonder if I'm meant to completely rewrite the implementation?
Edit: Firstly I really appreciate the assists, I did look carefully through all the sites I could before posting this and I did see (and try work with) each of the links that you all posted. I even went back and studied delegates and events again but I feel like I'm missing the starting point somehow because each time I try change a part of it, I just keep producing errors that I can't come back from like:
public delegate void TestEventHandler( object sender, EventArgs e );
With the other links I visited, I could only find 1 similarity to my code (either in the delegate, the handler or the property) but couldn't find anything that related enough to mine to actually instil that "eureka" moment
Edit 2: I have now rebuilt my example with what "looks" to be the correct standard but this code is so fugly it looks like it was beaten with a confogulus stick and dipped in a tank of confutious before being deep fried in horriduculous:
public static class Test
{
/// <summary>Delegate for property changed event</summary>
public delegate void TestEventHandler( object sender, EventArgs e );
/// <summary>Event called when value is changed</summary>
public static event TestEventHandler OnTestHappening;
/// <summary>Property to specify our test is happening</summary>
private static bool testHappening;
public static bool TestHappening
{
get
{
return testHappening;
}
set
{
testHappening = value;
// Notify our value has changed only if True
// ie. Only fire an event when we're ready as we'll hook methods to the Event that must only fire if ready
if ( value )
{
if ( OnTestHappening != null )
OnTestHappening( null, EventArgs.Empty );
}
}
}
}
public class Tester
{
private void Main()
{
Testing( this, EventArgs.Empty );
// Start the test
Test.TestHappening = true;
}
private void Testing( object sender, EventArgs e )
{
// Unsubscribe from the event
Test.OnTestHappening -= Testing;
// Check if we're busy testing yet
if ( !GlobalClass.SystemOnline )
{
// Subscribe to the event
Test.OnTestHappening += new Test.TestEventHandler( Testing );
return;
}
// Do stuff here....
}
}
Please tell me I've missed something and that there is in fact a more elegant implementation
Edit 3 : Based on the code by Enigmativity, I've reworked the code to it's most basic form. I've also moved the code setting the variable to true in a different method so it doesn't look so daft sitting in Main.
public static class Test4
{
/// <summary>Event called when value is changed</summary>
public static event EventHandler TestHappening;
/// <summary>Property to specify our test is happening</summary>
private static bool test = false;
public static bool Test
{
get
{
return test;
}
set
{
// Notify our value has changed only if True
// ie. Only fire an event when we're ready as we'll hook methods to the Event that must only fire if ready
if ( value )
{
TestHappening( null, EventArgs.Empty );
}
}
}
}
public class Tester4
{
private void Main()
{
Testing( this, EventArgs.Empty );
}
private void Testing( object sender, EventArgs e )
{
// Unsubscribe from the event
Test4.TestHappening -= Testing;
// Check if we're busy testing yet
if ( !Test4.Test )
{
// Subscribe to the event
Test4.TestHappening += Testing;
return;
}
// Do stuff here....
}
private void SomeMethodCalledFromSomewhere()
{
// Set the value to true and thereby start the test
Test4.Test = true;
}
}
Would this be considered good code or should I rather have the OnTestHappening method as defined in Enigmativity's code?
Why can't I use a parameterless delegate? It's now using the default ( object sender, EventArgs e ) but that feels overkill and doesn't make sense why the compiler is happy with it but according to coding standards it's considered bad code? I'm not arguing the standard but rather trying to understand it's reasoning.
As per Storm's request, here is how I would most likely structure the code. It's more inline with the standard conventions.
public static class TestClass
{
public delegate void TestEventHandler(object sender, EventArgs e);
public static event TestEventHandler TestHappening;
private static bool test = false;
public static bool Test
{
get
{
return test;
}
set
{
test = value;
if (test)
{
OnTestHappening();
}
}
}
private static void OnTestHappening()
{
var handler = TestHappening;
if (handler != null)
handler(null, EventArgs.Empty);
}
}
And Tester would look like this:
public class Tester
{
public void Main()
{
TestClass.TestHappening += Testing;
Go();
}
private void Testing(object sender, EventArgs e)
{
Console.WriteLine(TestClass.Test);
TestClass.TestHappening -= Testing;
}
private void Go()
{
TestClass.Test = true;
}
}
Calling it would look like this:
var tester = new Tester();
tester.Main();
Running this outputs True to the console.
If I were writing this in a more standard way, it would look like this:
public class TestEventArg : EventArgs
{
public TestEventArg(bool updatedValue)
{
this.UpdatedValue = updatedValue;
}
public bool UpdatedValue { get; private set; }
}
public class TestClass
{
public event EventHandler<TestEventArg> TestHappening;
private bool test = false;
public bool Test
{
get { return test; }
set
{
var old = test;
test = value;
if (test != old)
OnTestHappening(test);
}
}
private void OnTestHappening(bool updatedValue)
{
var handler = TestHappening;
if (handler != null)
handler(this, new TestEventArg(updatedValue));
}
}
I am new to events and I am trying to see how an event works and what purpose they would have. The code below is some code that a friend helped me with that we found on the net. It works but I am not certain as to how the event is used.
In the Main method there is the EventTest which creates a new object e which then intern calls SetValue method twice with a different parameter.
static void Main(string[] args)
{
EventTest e = new EventTest(5);
e.SetValue(7);
e.SetValue(11);
Console.ReadKey();
}
The following code is actually the event code.The OnNumChanged is the event that writes information if the number is changed. So when SetValue(100) is set to a different number then the event is fired.
Question: When the SetValue is set with a new value this is what cause the event to change correct?
I am just new enough to the event change that I could really use some good examples or have someone really explain this example line by line.
e.SetValue(7);
e.SetValue(11);
protected virtual void OnNumChanged()
{
if (ChangeNum != null)
{
ChangeNum();
}
else
{
Console.WriteLine("Event fired!");
}
}
Code:
class Program
{
static void Main(string[] args)
{
EventTest e = new EventTest(5);
e.SetValue(7);
e.SetValue(11);
Console.ReadKey();
}
}
public class EventTest
{
private int value;
public delegate void NumManipulationHandler();
public event NumManipulationHandler ChangeNum;
public EventTest(int n)
{
SetValue(n);
}
public void SetValue(int n)
{
if (value != n)
{
value = n;
OnNumChanged();
}
}
protected virtual void OnNumChanged()
{
if (ChangeNum != null)
{
ChangeNum();
}
else
{
Console.WriteLine("Event fired!");
}
}
}
Yes, you are correct:
public void SetValue(int n)
{
if (value != n) // check if the value actually changed
{
value = n;
OnNumChanged(); // call the event "in a save way", see below
}
}
protected virtual void OnNumChanged()
{
if (ChangeNum != null) // check if someone is listening - PROBLEM: see below
ChangeNum(); // trigger the event and call all event handlers registered
}
The Problem I mentioned above: You get the event to check it for null and then get it again to execute. In a multi-threaded environment it can happen, that between these two "gets" it changes => create a local copy:
protected virtual void OnNumChanged()
{
var changeNum = ChangeNum;
if (changeNum != null)
changeNum();
}
To actually get notified on the event you need to register for the event e.g. like this:
static void Main(string[] args)
{
EventTest e = new EventTest(5);
e.ChangeNum += () => Console.WriteLine("Num changed"); //<== this
e.SetValue(7);
e.SetValue(11);
Console.ReadKey();
}
It also would make more sense to also supply the new value in the event. That can be done by altering the delegate to:
public delegate void NumManipulationHandler(int newValue);
and call it like:
ChangeNum(value);
Then you can register like:
e.ChangeNum += newValue => Console.WriteLine("Num changed to " + newValue);
in short: yes! if the value that is passed along with the SetValue method differs from the one that was already stored, an event is fired, indicating the change as such.
Any other code that might be subscribed to such an event can then react accordingly in whatever way.
Even though I myself can learn easier from video (and I advise you to search for videos on events in C# as well), it all boils down to a way for a class to provide notifications to clients of that class when some interesting thing happens to an object (further reading here)
I know Events are always associated with Delegates. But, I am missing some core use of Events, and trying to understand that.
I created a simple Event program, as below, and it works perfectly fine.
namespace CompleteRef3._0
{
delegate void someEventDelegate();
class EventTester
{
public event someEventDelegate someEvent;
public void doEvent()
{
if (someEvent != null) someEvent();
}
}
class Program
{
static void EventHandler1()
{
Console.WriteLine("Event handler 1 called..");
}
static void EventHandler2()
{
Console.WriteLine("Event handler 2 called..");
}
static void EventHandler3()
{
Console.WriteLine("Event handler 3 called..");
}
static void Main(string[] args)
{
EventTester evt = new EventTester();
evt.someEvent += EventHandler1;
evt.someEvent += EventHandler2;
evt.someEvent += EventHandler3;
evt.doEvent();
Console.ReadKey();
}
}
}
I replaced the event declaration with delegates. That is I replaced the line public event someEventDelegate someEvent; with someEventDelegate someEvent; on the above program, and I still get the same result. Now, I was confused why we need to use Events, if it can be achieved by Delegates only. What is the real use of Events?
The modified program without events is as below -
namespace CompleteRef3._0
{
delegate void someEventDelegate();
class EventTester
{
someEventDelegate someEvent;
public void doEvent()
{
if (someEvent != null) someEvent();
}
}
class Program
{
static void EventHandler1()
{
Console.WriteLine("Event handler 1 called..");
}
static void EventHandler2()
{
Console.WriteLine("Event handler 2 called..");
}
static void EventHandler3()
{
Console.WriteLine("Event handler 3 called..");
}
static void Main(string[] args)
{
EventTester evt = new EventTester();
evt.someEvent += EventHandler1;
evt.someEvent += EventHandler2;
evt.someEvent += EventHandler3;
evt.doEvent();
Console.ReadKey();
}
}
}
Imagine you have 3 subscribers who are interested in your someEvent. Let's further imagine they are interested in receiving events from the same EventTester instance. For brevity, let's leave out the details of how the exact same instance is passed to all the clients. When I say clients, I mean any class who is a subscriber to the event.
Here is the instance:
EventTester evt = new EventTester();
They have subscribed to the event of the above instance as shown below:
Client 1
evt.someEvent += Client1Handler1;
evt.someEvent += Client1Handler2;
Client 2
evt.someEvent += Client2Handler1;
Client 3
evt.someEvent += Client3Handler1;
evt.someEvent += Client3Handler2;
Client 4:
Imagine client 4 did one of the 3 below:
// 1: See Note 1 below
evt.someEvent = null;
// 2: See Note 2 below
evt.someEvent = new someEventDelegate(MyHandler);
// 3: See Note 3 below
evt.someEvent();
//...
private void MyHandler()
{
MessageBox.Show("Client 4");
}
Note 1
Client 1, 2, and 3 will not be getting any events anymore. Why? Because Client 4 just did this evt.someEvent = null; and in EventTester you have this line of code:
if (someEvent != null) someEvent();
Since that condition will not pass anymore, no event will be raised. There is nothing wrong with the above line of code by the way. But there is the problem with using delegates: It can be assigned to.
Note 2
It has been completely over-written to a brand new instance. Now regardless of the client, they will all see a message box that says "Client 4".
Note 3
Ooops all of a sudden one of the clients is broadcasting the event.
Imagine for a second EventTester was a Button and someEvent was Click. Imagine you had multiple clients interested in the click event of this button. All of a sudden, one client decides no-one else should get notifications (Note 1). Or one client decides that when the button is clicked, it will be handled only 1 way (Note 2). Or it has made the decision that it will decide when a button is clicked even though the button may not have been clicked (Note 3).
If you have an event and one of the clients tried the above, they will not be allowed and get a compile error, like this:
Sure, you can use delegates because behind the scenes an event is a construct that wraps a delegate.
But the rationale of using events instead of delegates is the the same as for using properties instead of fields - data encapsulation. It's bad practice to expose fields (whatever they are - primitive fields or delegates) directly.
By the way, you missed a public keyword before your delegate field to make it possible in the second snippet.
Another "by the way" with the second snippet: for delegates you should use Delegate.Combine instead of "+=".
The main purpose of events is to prevent subscribers from interfering with each other. If you do not use events, you can:
Replace other subscribers by reassigning delegate(instead of using the += operator),
Clear all subscribers (by setting delegate to null),
Broadcast to other subscribers by invoking the delegate.
Source: C# in a Nutshell
public class Program
{
public static void Main()
{
Number myNumber = new Number(100000);
myNumber.PrintMoney();
myNumber.PrintNumber();
Console.ReadKey();
}
}
public class Number
{
private PrintHelper _printHelper;
public Number(int val)
{
_value = val;
_printHelper = new PrintHelper();
//subscribe to beforePrintEvent event
_printHelper.beforePrintEvent += printHelper_beforePrintEvent;
}
//beforePrintevent handler
void printHelper_beforePrintEvent(string message)
{
Console.WriteLine("BeforePrintEvent fires from {0}", message);
}
private int _value;
public int Value
{
get { return _value; }
set { _value = value; }
}
public void PrintMoney()
{
_printHelper.PrintMoney(_value);
}
public void PrintNumber()
{
_printHelper.PrintNumber(_value);
}
}
public class PrintHelper
{
public delegate void BeforePrintDelegate(string message);
public event BeforePrintDelegate beforePrintEvent;
public PrintHelper()
{
}
public void PrintNumber(int num)
{
if (beforePrintEvent != null)
beforePrintEvent.Invoke("PrintNumber");
Console.WriteLine("Number: {0,-12:N0}", num);
}
public void PrintDecimal(int dec)
{
if (beforePrintEvent != null)
beforePrintEvent("PrintDecimal");
Console.WriteLine("Decimal: {0:G}", dec);
}
public void PrintMoney(int money)
{
if (beforePrintEvent != null)
beforePrintEvent("PrintMoney");
Console.WriteLine("Money: {0:C}", money);
}
public void PrintTemperature(int num)
{
if (beforePrintEvent != null)
beforePrintEvent("PrintTemerature");
Console.WriteLine("Temperature: {0,4:N1} F", num);
}
public void PrintHexadecimal(int dec)
{
if (beforePrintEvent != null)
beforePrintEvent("PrintHexadecimal");
Console.WriteLine("Hexadecimal: {0:X}", dec);
}
}
I have a simple Screen class in C# that has a bunch of events (with corresponding delegates) like the FadeOutEvent.
I want to port my library to Java, and I find that the mechanism for events/delegates is really cludgey. Specifically, I cannot easily write code like:
if (someVar == someVal) {
this.FadeOutComplete += () => {
this.ShowScreen(new SomeScreen());
};
} else {
this.FadeOutComplete += () => {
this.ShowScreen(new SomeOtherScreen());
};
}
For all you Java-only guys, essentially, what I'm whinging about is the inability to reassign the event-handling method in the current class to something else dynamically, without creating new classes; it seems that if I use interfaces, the current class must implement the interface, and I can't change the code called later.
In C#, it's common that you have code that:
In a constructor / early on, assign some event handler code to an event
Later during execution, remove that code completely
Often, change that original handler to different handler code
Strategy pattern can solve this (and does), albeit that I need extra classes and interfaces to do it; in C#, it's just a delcarative event/delegate and I'm done.
Is there a way to do this without inner/anonymous classes?
Edit: I just saw this SO question, which might help.
Most of the time, it's done the other way round:
this.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (someVar == someVal) {
showSomeScreen();
}
else {
showSomeOtherScreen();
}
}
});
But you could do something similar to your C# code by delegating to two other objects:
private Runnable delegate;
// ...
this.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
delegate.run();
}
});
// ...
if (someVar == someVal) {
this.delegate = new Runnable() {
#Override
public void run() {
showSomeScreen();
}
};
}
else {
this.delegate = new Runnable() {
#Override
public void run() {
showSomeOtherScreen();
}
};
}
Delegates were proposed by Microsoft for Java a long long time ago, and were refused by Sun. I don't remember if anonymous inner classes already existed at that time or if they were chosen as the alternative.
With lambdas in JDK 1.8 / Java 8:
private Runnable delegate;
public void delegateTest() {
// ...
this.addActionListener(e -> delegate.run());
// ...
if (someVar == someVal) {
this.delegate = () -> showSomeScreen();
}
else {
// or like this:
this.delegate = this::showSomeOtherScreen;
}
}
private void showSomeOtherScreen() {
}
private void showSomeScreen() {
}
I am creating an event driven class so that when I pass it a series of data, it will process and then return the value when ready.
Below is the code that I am currently using the below code however it is quite nasty and I'm not sure if can be simpler than this.
public delegate void MyEventHandler(double result);
public static MyEventHandler EventComplete;
public static void MakeSomethingHappen(double[] data)
{
ThreadPool.QueueUserWorkItem(DoSomething, data);
}
private static void DoSomething(object dblData)
{
InvokeEventComplete(AndSomethingElse((double[])dblData));
}
private static void InvokeEventComplete(double result)
{
if (EventComplete != null)
{
EventComplete(result);
}
}
public static double AndSomethingElse(double[] data)
{
//do some code
return result; //double
}
In my main class I simply hook up a method to the event like so,
MyClass.EventComplete += new MyClass.EventCompleteHandler(MyClass_EventComplete);
Here you are:
Exposed event as an actual event rather than a publicly accessible member delegate.
Eliminated extra delegate declaration and used generic delegate Action.
Eliminated extra invocation function which was simply verbose.
Used lambda expression for event registration.
Edited code is:
MyClass.EventComplete += (result) => Console.WriteLine("Result is: " + result);
public class MyClass
{
public static event Action<double> EventComplete;
public static void MakeSomethingHappen(double[] data)
{
ThreadPool.QueueUserWorkItem(DoSomething, data);
}
private static void DoSomething(object dblData)
{
var result = AndSomethingElse((double[])dblData);
if (EventComplete != null)
{
EventComplete(result);
}
}
public static double AndSomethingElse(double[] data)
{
//do some code
return result; //double
}
}
Some things to consider...
There's an EventHandler<T> where T : EventArgs in .NET, but the trade off is you end up writing a custom EventArgs to pass your double data instead of a custom delegate. Still I think that's a cleaner pattern to follow.
If you were to define your event as
public static MyEventHandler EventComplete = delegate {};
//using a no-op handler like this has implications on Garbage Collection
Does using a no-op lambda expression for initializing an event prevent GC?
you could save yourself the if(EventComplete != null) check everytime and hence make the Invoke... method redundant.
you can also simplify
MyClass.EventComplete += new MyClass.EventCompleteHandler(MyClass_EventComplete);
to
MyClass.EventComplete += MyClass_EventComplete;
Aside from that it looks fine. I presume all the static's around the code are just from working in a ConsoleApplication :-)
try using standart event pattern (thousands times used inside FCL)
// in [CompleteEventArgs.cs] file
public class CompleteEventArgs : EventArgs {
private readonly double _result;
public CompleteEventArgs(double result) {
_result = result;
}
public double Result {
get { return _result; }
}
}
// inside your class
// don't forget 'event' modifier(!) it prevents lots of illegal stuff
// like 'Complete = null' on the listener side
public static event EventHandler<CompleteEventArgs> Complete;
public static void MakeSomethingHappen(double[] data) {
ThreadPool.QueueUserWorkItem(DoSomething, data);
}
private static void DoSomething(object dblData) {
OnComplete(new CompleteEventArgs(AndSomethingElse((double[])dblData)));
}
// if you're working with a 'normal' (non-static) class
// here should be 'protected virtual' modifiers to allow inheritors
// use polymorphism to change the business logic
private static void OnComplete(CompleteEventArgs e) {
if (Complete != null)
Complete(null, e); // in 'normal' way here stands 'this' instead of 'null'
// this object (link to the sender) is pretty tricky
// and allows extra flexibility of the code on the listener side
}
public static double AndSomethingElse(double[] data) {
double result = 0;
//do some code
return result; //double
}