Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why we should use temprary object to raise event?

Tags:

c#

.net

wpf

Most of the time when we use MVVM we use the INotifyPropertyChanged interface to provide the notification to the bindings, and the general implementation looks like this:

public class MyClass : INotifyPropertyChanged
{
    // properties implementation with RaisePropertyChanged

    public event PropertyChangedEventHandler PropertyChanged;
    protected void RaisePropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

This works fine for me whenever I read the code from the experts - they wrote similar code:

public class MyClass : INotifyPropertyChanged
{
    // properties implementation with RaisePropertyChanged

    public event PropertyChangedEventHandler PropertyChanged;
    protected void RaisePropertyChanged(string propertyName)
    {
        var tempchanged = PropertyChanged;
        if (tempchanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

I would like to know what is the exact reason behind creating a temporary object for the PropertyChanged event.

Is it only a good practice or are there any other benefits associated with it?

I have found the answer with Jon's answer and the explained example at:

Understanding C#: Raising events using a temporary variable

Here is the sample code to understand this:

using System;
using System.Collections.Generic;
using System.Threading;

class Plane
{
     public event EventHandler Land;

     protected void OnLand()
     {
          if (null != Land)
          {
               Land(this, null);
           }
      }

     public void LandThePlane()
     {
          OnLand();
      }
}

class Program
{
     static void Main(string[] args)
     {
          Plane p = new Plane();
          ParameterizedThreadStart start = new ParameterizedThreadStart(Run);
          Thread thread = new Thread(start);
          thread.Start(p);

          while (true)
          {
               p.LandThePlane();
           }
      }

     static void Run(object o)
     {
          Plane p = o as Plane;
          while (p != null)
          {
               p.Land += p_Land;
               p.Land -= p_Land;
           }
      }

     static void p_Land(object sender, EventArgs e)
     {
          return;
      }
}
like image 347
JSJ Avatar asked Jul 02 '13 13:07

JSJ


People also ask

Which command is used to raise an event?

Use the Shared modifier to create a shared event if you need to raise an event from a constructor. You can change the default behavior of events by defining a custom event. For custom events, the RaiseEvent statement invokes the event's RaiseEvent accessor.

How do you raise an event?

Typically, to raise an event, you add a method that is marked as protected and virtual (in C#) or Protected and Overridable (in Visual Basic). Name this method On EventName; for example, OnDataReceived .

Which is the best place to subscribe event handler to an event?

To subscribe to events by using the Visual Studio IDEOn top of the Properties window, click the Events icon. Double-click the event that you want to create, for example the Load event. Visual C# creates an empty event handler method and adds it to your code. Alternatively you can add the code manually in Code view.

Which of the following is correct for testing if event is raised?

When testing that a class raises events correctly, there are three elements to verify. Firstly, the class should raise the correct event according to the process being executed. Secondly, the event should refer to the object that raised it.


1 Answers

You're not creating a temporary object. You're using a local variable to avoid a race condition.

In this code:

if (PropertyChanged != null)
{
    PropertyChanged(...);
}

it's possible for PropertyChanged to become null (due to the last subscriber unsubscribing) after the nullity check, which will mean you get a NullReferenceException.

When you use a local variable, you ensure that the reference you check for nullity is the same reference that you use to raise the event - so you won't get the exception. There's still a race condition in that you may end up calling subscribers who have just unsubscribed, but that's unavoidable.

like image 72
Jon Skeet Avatar answered Sep 19 '22 01:09

Jon Skeet