An Explanation of the .NET add_EventName / remove_EventName Methods for PowerShell Scripters

If you have ever attempted to write a little WinForms or WPF UI using PowerShell you have no doubt run across a method like add_Click() e.g.

Add-Type -AssemblyName System.Windows.Forms 
$form = New-Object Windows.Forms.Form 
$button = New-Object Windows.Forms.Button 
$button.Text = "Close" 
$button.add_Click({$form.Close()}) 
$form.Controls.Add($button) 
$form.ShowDialog() 

This might be a bit confusing if you are looking at C# examples or even the MSDN topic on a Windows Form Button.  It says the event name is simply “Click”.  What is going on here?

When C# and .NET were first introduced they were inspired by Java but they also added some features Java didn’t have.  Two of these features were language level support for properties and events.  Two concepts borrowed from Delphi which isn’t too surprising given that the chief architect of C#, Anders Heljsberg, came from Borland where he was the chief architect of Delphi.  Anders’ contributions date back to the introduction of Turbo Pascal which I thoroughly enjoyed during my college days.

The basic gist of properties is that they are used as if you are reading and writing a field of an object except that the author of the type can inject code during the read/write process.  So in C#, when creating a class you can create a property like this:

public class MyClass 
{
    private string _name;
    public string Name 
    {
        get { return _name; }
        set
        {
            if (_name != value) 
            {
                _name = value;
            }
        }
    }
}

As an author of a type in .NET this is great because I can check to see if the value is different and only if it is different, perform some application specific logic.  For instance, WPF apps often need to let UI elements know when the value of the property has changed.  WPF’s data binding relies on this behavior and when it has been notified of a change to a property, it can get the new value for the property and update the UI automatically. Properties in .NET give us the necessary hooks to do this.

Note that in the code above, _name is a field. If I had made that field public, then a user of the type would have direct access to the field.  They could get or set the _name field and the class would have no way to know the field has been accessed or modified because there is no way to inject code during the read or write of a field.

Keep in mind that getting and setting a property in C#, VB and PowerShell is a language convenience commonly referred to as “syntactical sugar“.  When the C# source above is compiled, the generated assembly (dll or exe) shows this representation in common intermediate language (CIL):

image

Sidebar: Common Intermediate Language
What C# and VB compile down to is known as Common Intermediate Language.  This is typically what a .NET executable or DLL contains.  It is an architecture neutral representation of compiled source code that is not directly executable.  It has to be “just in time” compiled using a jitter (just-in-time compiler) or “ahead-of-time” compiled using a tool such as ngen.exe or the new .NET native compiler.

In either case, the JIT or AOT compiler needs to know the CPU architecture of the target device so it can generate the appropriate machine code.  This is typically either x86 (32 or 64 bit) or ARM.  .NET assemblies running on a Raspbery Pi2 with Windows 10 IoT or a Windows Phone require ARM compiled machine code

I’m using a tool called ILDASM that comes with the Windows SDK above to show the CIL contents of the .NET assembly generated from the C# MyClass source code shown above.  Notice that there is a “Name” property.  Here’s what ILDASM shows if you double-click on Name:

.property instance string Name()
{
  .get instance string MyClass::get_Name()
  .set instance void MyClass::set_Name(string)
} // end of property MyClass::Name

The Name property is simply a pointer to the compiler generated methods get_Name() and set_Name(string).  This is where the actual implementations of the property getter and setter reside.

The way you access a property in Java is to call a method; either a get<Property> or set<Property> method.  This is a common convention that is used because Java does not have first class support for properties.   Fortunately, accessing a property in C# looks just like you are reading or writing a field:

var obj = new MyClass();
obj.Name = "John";
Console.WriteLine(obj.Name);

Keep in mind that the C# source “obj.Name” is converted into a call to obj.get_Name() and obj.Name = “John” is converted to a call to obj.set_Name(“John”) at the CIL level.  At first glance this seems like it would be a minimal convenience but it turns out to be huge for C# and .NET’s usability IMO.

PowerShell also supports the property access syntactical sugar at the language level as well:

$obj = New-Object MyClass
$obj.Name = 'John'
$obj.Name

Unfortunately, PowerShell does not support .NET event subscription syntactical sugar like C# and VB do.  That said, you’ll see that there is an easy workaround.  You could also argue that for most scripting scenarios you don’t use .NET events.  However, as soon as you want to build a UI, either with Windows Forms or WPF you’ll be using events, perhaps a lot.

Lets take a look at a class definition with events:

using System;
using System.ComponentModel;

public class MyClass : INotifyPropertyChanged
{
    private string _name;
    public string Name 
    {
        get { return _name; }
        set
        {
            if (_name != value) 
            {
                _name = value;
                OnPropertyChanged(nameof(Name));   
            }
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    private void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, 
            new PropertyChangedEventArgs(propertyName));
    }        
}

This adds an event definition – PropertyChanged.  Let’s take a look at the CIL that got generated when I compiled this C# source code:

image

Notice again that there is an event called “PropertyChanged” but if we look at its CIL definition we will see it is very similar to the one for the Name property:

.event [System]System.ComponentModel.PropertyChangedEventHandler PropertyChanged
{
  .addon instance void MyClass::add_PropertyChanged(class [System]System.ComponentModel.PropertyChangedEventHandler)
  .removeon instance void MyClass::remove_PropertyChanged(class [System]System.ComponentModel.PropertyChangedEventHandler)
} // end of event MyClass::PropertyChanged

It just references the add_PropertyChanged and remove_PropertyChanged methods.  The actual implementation of event subscription and unsubscription are done in these two methods.

In C# you can subscribe to the PropertyChanged event with the += and -= syntactical sugar e.g.:

var obj = new MyClass();
obj.PropertyChanged += 
    (sender, args) => Console.WriteLine(args.PropertyName);

The same syntax += in PowerShell does not work for event subscription.  Fortunately the syntactical sugar is not required, we can just call the add_PropertyChanged() method directly.  The same goes for remove_PropertyChanged(), instead of C#’s -= syntax, if we need to unsubscribe from the event.

Add-Type -Path .\MyClass.dll
$obj = New-Object MyClass
$obj.add_PropertyChanged({Write-Host "$($_.PropertyName)"})
$obj.Name = 'Paul'

It works. It perhaps isn’t as elegant but more importantly I think the issue is lack of documentation and examples that use an event’s add/remove methods.  This is because the vast majority of .NET samples on the internet are in C# which are going to use the += and -= syntax..  It leaves the average PowerShell scripter scratching their head about why the C# += syntax doesn’t work.  And wondering what is up with this weird add_Click() method in the PowerShell script examples that show how to use Windows Forms.

Hopefully, if you’ve made it this far, you’ll have a good handle on these compiler generated methods for subscribing and unsubscribing to events.

Advertisements
This entry was posted in .NET, PowerShell. Bookmark the permalink.

3 Responses to An Explanation of the .NET add_EventName / remove_EventName Methods for PowerShell Scripters

  1. Pingback: SAPIEN Technologies » Blog Archive » The Methods that Register Events

  2. Pingback: Part IV – PowerShell GUIs – how to handle events and create a Tabbed Interface – FoxDeploy.com

  3. NetPrudency says:

    Thanks a lot for this very,clear article.
    I’m looking for this information for hours…
    Sorry for my english 🙂

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s