[NoBrainer] Create C# extension methods via Add-Type and Update-TypeData in PowerShell

In this post I present a quick refresher on how to make C# extension methods available to objects and classes in PowerShell sessions.

C# allows you to extend classes with methods you define yourself via Extension Methods. This means you can add methods to arbitrary classes which you do not have written yourself or do not own the code for it and then call these methods as if they were part of the class. Unfortunately PowerShell does not really understand this concept but provides a workaround towards this.

You will find that just importing your extension method via Add-Type will not be sufficient to call the method, in our case ‘theAnswer()’:

PS > [string] $s = "tralala";
PS > $TypeDefinition = @"
using System;

namespace biz.dfch.CS
{
	public static class StringExtension
	{
		public static int theAnswer(this System.String s)
		{
			return 42;
		}
	}
}
"@

PS > Add-Type $TypeDefinition;
PS > $s.theAnswer();
Method invocation failed because [System.String] doesn't contain a method named 'theAnswer'.
At line:1 char:1
+ [string]::theAnswer()
+ ~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : MethodNotFound

To get this actually working, you additional have to include this method in the PowerShell defined types via Update-TypeData:

PS > $TypeData = @"
<?xml version="1.0" encoding="utf-8" ?> 
<Types> 
 <Type> 
  <Name>System.String</Name> 
  <Members> 
   <ScriptMethod> 
    <Name>theAnswer</Name> 
     <Script> 
     [biz.dfch.CS.StringExtension]::theAnswer(`$this) 
    </Script> 
   </ScriptMethod> 
  </Members> 
 </Type> 
</Types>
"@

PS > $PowerShellTypesFileAndPath = '{0}.ps1xml' -f [System.IO.Path]::GetTempFileName();
PS > $TypeData | Out-File $PowerShellTypesFileAndPath -Encoding default;
PS > Update-TypeData $PowerShellTypesFileAndPath;
PS > Remove-Item $PowerShellTypesFileAndPath;
PS > $s.theAnswer();
42

So now everything works just as expected, except that our method shows up as a ‘script method’ (as we imported it via ‘Update-TypeData’):

PS > # theAnswer is shown as e (non-static) script method
PS > $s | gm -Name theAnswer;

   TypeName: System.String

Name      MemberType   Definition
----      ----------   ----------
theAnswer ScriptMethod System.Object theAnswer();

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

%d bloggers like this: