How can lambda expressions as event handlers can change local variables? - c#

I was writing some tests for one of my classes and I needed to test that an event was being raised. Out of just trying it and seeing what happened I coded something similar to the following extremely simplified code.
public class MyEventClass
{
public event EventHandler MyEvent;
public void MethodThatRaisesMyEvent()
{
if (MyEvent != null)
MyEvent(this, new EventArgs());
}
}
[TestClass]
public class MyEventClassTest
{
[TestMethod]
public void EventRaised()
{
bool raised = false;
var subject = new MyEventClass();
subject.MyEvent += (s, e) => raised = true;
subject.MethodThatRaisesMyEvent();
Assert.IsTrue(raised);
}
}
I wasn't so much amazed when it worked as when I started to try and figure out how it worked. Specifically, how would I write this without lambda expressions so that the local variable raised can be updated? In other words, how is the compiler refactoring/translating this?
I got this far...
[TestClass]
public class MyEventClassTestRefactor
{
private bool raised;
[TestMethod]
public void EventRaised()
{
raised = false;
var subject = new MyEventClass();
subject.MyEvent += MyEventHandler;
subject.MethodThatRaisesMyEvent();
Assert.IsTrue(raised);
}
private void MyEventHandler(object sender, EventArgs e)
{
raised = true
}
}
But this changes raised to a class-scoped field rather than a local-scope variable.

Specifically, how would I write this without lambda expressions so that the local variable raised can be updated?
You would create an extra class, to hold the captured variables. That's what the C# compiler does. The extra class would contain a method with the body of the lambda expression, and the EventRaised method would create an instance of that capturing class, using the variables within that instance instead of "real" local variables.
It's easiest to demonstrate this without using events - just a small console application. Here's the version with the lambda expression:
using System;
class Test
{
static void Main()
{
int x = 10;
Action increment = () => x++;
increment();
increment();
Console.WriteLine(x); // 12
}
}
And here's code which is similar to the code generated by the compiler:
using System;
class Test
{
private class CapturingClass
{
public int x;
public void Execute()
{
x++;
}
}
static void Main()
{
CapturingClass capture = new CapturingClass();
capture.x = 10;
Action increment = capture.Execute;
increment();
increment();
Console.WriteLine(capture.x); // 12
}
}
Of course it can get much more complicated than this, particularly if you have multiple captured variables with different scopes - but if you can understand how the above works, that's a big first step.

Compiler generates class like this, which has method with signature of lambda delegate. All captured local variables moved to this class fields:
public sealed class c_0
{
public bool raised;
public void m_1(object s, EventArgs e)
{
// lambda body goes here
raised = true;
}
}
And final compiler trick is replacing usages of local raised variable with this field of generated class:
[TestClass]
public class MyEventClassTest
{
[TestMethod]
public void EventRaised()
{
c_0 generated = new c_0();
generated.raised = false;
var subject = new MyEventClass();
subject.MyEvent += generated.m_1;
subject.MethodThatRaisesMyEvent();
Assert.IsTrue(generated.raised);
}
}

Related

Why is "MyEvent" always make compiler error "CS0070"?

how to fixed CS0070 error?
Error:
Error CS0070 The event 'Demo.MyEvent' can only appear on the left hand side of += or -= (except when used from within the type 'Demo')
Code:
class Demo
{
public event EventHandler<int> MyEvent;
public void Handler(object sender, int arg)
{
Console.WriteLine($"I just go {arg}");
}
}
class Program
{
static void Main(string[] args)
{
var demo = new Demo();
var eventInfo = typeof(Demo).GetEvent("MyEvent");
var handlerMethod = demo.GetType().GetMethod("Handler");
var handler = Delegate.CreateDelegate(
eventInfo.EventHandlerType,
null,
handlerMethod
);
eventInfo.AddEventHandler(demo, handler);
demo.MyEvent?.Invoke(null, 312);
}
}
Error line:
demo.MyEvent?.Invoke(null, 312);
Field-like events (which this is) act like a field to the declaring type, but just appear like an event add/remove pair to external types. This means that only the type that declares the event can do things like access the current value, which is required in order to invoke the backing delegate. Basically, there's a hidden private field that the compiled declares that you can't see - and when you access the event from within the type, you're talking to the field directly. But when accessing the event from outside, you have to go via the accessors - and the only accessors that C# provides are the add and remove accessors.
If you write a method inside Demo, that method will be able to invoke the event.
Event must be invoked directly form it's class, if your scenario requires to invoke it from outside the event then simply encapsulate your event with a method:
public void InvokeMyEvent(int value)
{
MyEvent?.Invoke(this,value);
}
Then subscribe to it easily with a short code:
demo.MyEvent += MyEvent_EventHandeler;
private void My_EventHandeler(object sender, int e)
{
//enter code here
}
Or even shorter with lambda:
demo.MyEvent += (s, e) =>
{
//enter code here
}
Invoke it from anywhere:
demo.InvokeMyEvent(321);
Thanks Mr. Marc Gravell.
Excuse me, My code is wrong.
Correct code is:
namespace ConsoleApp1
{
class Demo
{
public event EventHandler<int> MyEvent;
public void Handler(object sender, int arg)
{
Console.WriteLine($"I just go {arg}");
}
public static void Main(string[] args)
{
var demo = new Demo();
var eventInfo = typeof(Demo).GetEvent("MyEvent");
var handlerMethod = demo.GetType().GetMethod("Handler");
var handler = Delegate.CreateDelegate(
eventInfo.EventHandlerType,
null,
handlerMethod
);
eventInfo.AddEventHandler(demo, handler);
demo.MyEvent?.Invoke(null, 312);
}
}
}

Declare callback event handlers correctly

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));
}
}

Avoiding null pointer exception in delegates

I'm using delegates
in my c# windows forms application project.Using that I'm trying to remove items in a list box. I'm getting this null pointer exception and can somebody suggest a way to avoid that?
Delegate
public delegate void OrderEventDelegate (Object sender, OrderEventArgs args);
OrderEventArgs class
public class OrderEventArgs
{
private String message;
public String Message
{
get { return message; }
set { message = value; }
}
private int tableNo;
public int TableNo
{
get { return tableNo; }
set { tableNo = value; }
}
}
Class 1
public partial class Class1 : Form
{
private event OrderEventDelegate readyEvent;
public Class1(HomeForm parent, int tableNo)
{
InitializeComponent();
readyEvent -= new OrderEventDelegate(parent.readyOrder);
}
public void button_click()
{
OrderEventArgs readyOrderArg = new OrderEventArgs();
readyOrderArg.TableNo = 1;
readyOrderArg.Message = "123";
readyEvent(this, readyOrderArg);
}
}
Here readyEvent -= new OrderEventDelegate(parent.readyOrder);readyOrder() is the method which remove items in the list, which is located in the 'Homeform'.
Exception
It is possible to initialize C# events with an empty delegate. This way it can always be called safely without a null pointer check. As shown in this answer: https://stackoverflow.com/a/340618/2404788.
public delegate void OrderEventDelegate (Object sender, OrderEventArgs args) = delegate {};
If there's a possibility of something being null and you can do something about it/don't want to critically fail when it is, then check for it:
if (readyEvent != null) {
readyEvent( ... );
}
But the point here, I suppose, is that you don't want this thing to be null; so you should subscribe a handler to the event. I'm not sure why you're trying to remove a new instance of the delegate handler, but to add one you would use +=.

c# delegates and events

im trying to learn delegates and events in c#, i understand that an event is some sort of a wrapper for a delegate and a delegate is a pointer for functions/methods...
below is my code but when i run it, nothing is being shown... what could be the problems?
public class ClassHandler
{
public delegate void DoProcesses();
public event DoProcesses DoProcessesEvent;
}
public class Class1
{
public void Func1()
{
Console.WriteLine("Class 1 doing function 1");
}
public void Func2()
{
Console.WriteLine("Class 1 doing function 2");
}
}
public class Class2
{
public void Func1()
{
Console.WriteLine("Class 2 doing function 1");
}
public void Func2()
{
Console.WriteLine("Class 2 doing function 2");
}
}
class Program
{
static void Main(string[] args)
{
Class1 cs1 = new Class1();
Class2 cs2 = new Class2();
ClassHandler main = new ClassHandler();
main.DoProcessesEvent += new ClassHandler.DoProcesses(cs1.Func1);
main.DoProcessesEvent += new ClassHandler.DoProcesses(cs1.Func2);
main.DoProcessesEvent += new ClassHandler.DoProcesses(cs2.Func1);
main.DoProcessesEvent += new ClassHandler.DoProcesses(cs2.Func2);
main.DoProcessesEvent += new ClassHandler.DoProcesses(ff); // this line here is causing an error: An object reference is required for the non-static field, method, or property 'TryDelegatesAndEvents.Program.ff()'
Console.Read();
}
public void ff()
{
Console.WriteLine("gggg");
}
}
UPDATE: how do i raise the event so it will execute the methods already?
Problem with this line: main.DoProcessesEvent += new ClassHandler.DoProcesses(ff)
That is because your method ff() is a non-static method and you can't access it directly like that from a static method.
Make your method ff as static, or create and object of the containing class and assign the method with an instance of it.
For Comments: The reason you are not seeing anything is because you are just binding them to an event DoProcessesEvent, but you are not raising the event any where. You are only defining the handler for the event.
EDIT:
Change your ClassHandler class to:
public class ClassHandler
{
public delegate void DoProcesses();
public event DoProcesses DoProcessesEvent;
public void OnDoProcessEvent()
{
if (DoProcessesEvent != null)
DoProcessesEvent();
}
}
In your Main method before Console.Read(); Type:
main.OnDoProcessEvent();
This will raise the event and it will handled from the application and will give you the following output.
Class 1 doing function 1
Class 1 doing function 2
Class 2 doing function 1
Class 2 doing function 2
gggg
change main.DoProcessesEvent += new ClassHandler.DoProcesses(ff); to main.DoProcessesEvent += new ClassHandler.DoProcesses(new Program().ff); or make ff static
Well it does not compile due to the line:
main.DoProcessesEvent += new ClassHandler.DoProcesses(ff);
The error VS spits out is that:
An object reference is required for the non-static field, method, or property 'ConsoleApplication2.Program.ff()'
Just change your ff() method to be static to get around it.
Eg:
public static void ff()
{
Console.WriteLine("gggg");
}
Besides the problem pointed out in earlier comments, You have to trigger the event.
make a copy of an event before you check it for null and fire it. This will eliminate a potential problem with threading where the event becomes null at the location right between where you check for null and where you fire the event:
// Copy the event delegate before checking/calling
EventHandler copy = DoProcessesEvent ;
if (copy != null)
copy(this, EventArgs.Empty); // Call any handlers on the copied list
This will ensure that your event fires and you will get the result.
Just to add to #Habib's answer, it would be fairly unusual to subscribe instance class methods as event handlers of an object potentially in another scope (e.g. what happens if Class1 goes out of scope, yet main() still has a subscription?). A more common scenario would be to subscribe (and de-subscribe) handlers in the same scope, often in an asynchronous manner (the below events are still raised synchronously).
namespace ConsoleApplication1
{
public delegate void ProcessCompletedEvent(string description);
public class Class1
{
public void Func1()
{
// Do Func1 work
Thread.Sleep(500);
RaiseEvent("Func1 completed");
}
public void Func2()
{
// Do Func2 work
Thread.Sleep(1000);
RaiseEvent("Func2 completed");
}
private void RaiseEvent(string description)
{
if (ProcessCompleted != null)
{
ProcessCompleted(description);
}
}
public event ProcessCompletedEvent ProcessCompleted;
}
class Program
{
static void Main(string[] args)
{
Class1 cs1 = new Class1();
// Wire up event handler
cs1.ProcessCompleted += new ProcessCompletedEvent(MyHandler);
cs1.Func1();
cs1.Func2();
Console.Read();
// Remove the subscription
cs1.ProcessCompleted -= MyHandler;
}
// *** Is in the same scope as main, which subscribes / desubscribes
public static void MyHandler(string description)
{
Console.WriteLine(description);
}
}
}

Event driven classes in C#

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
}

Categories

Resources