Type Extensions
You’d think from all of my posts on PowerShell that I was a system admin, or worked in a job that required a lot of scripting/automation. Well, the second one is partly true, I’m a .NET developer, primarily working on WinForms based applications, soon to include WPF (and hopefully Silverlight!). I think any developer worth their salt will look for ways to automate repetitive tasks. Sometimes, we even have to automate the automation! For example, build processes have become so much more well defined than they once were. There are many options for automating builds, all depending on the technology in use, and what your preferences are. Internally, we have conglomerations of perl, ruby, dmake, and all the things those can invoke (msbuild, for example). And, since we have folks internally who manage that process (and maintain the scripts), I don’t get much opportunity to incorporate PowerShell into the mix, except on my development machine as I automate my usage of those scripts to accomplish common tasks.
That’s one reason (of many) that I think PowerShell’s type extension system is so incredible. (And I’m really looking forward to Extension Methods.) I love the idea of being able to extend any type with functionality of my choice. That makes the “automate the automation” game so much more fun, and it really makes common operations I perform that much more “streamlined” to execute. There are a few good examples (not necessarily related to software development) of ideas on how to leverage this system to your advantage:
Add Base64 encoding/decoding to a string
Making Junctions/ReparsePoints visible in PowerShell
Accessing EXIF Photo Data from JPEGs with PowerShell
Anyway, a feature request recently came up in the microsoft.public.windows.powershell newsgroup that seems like a perfect candidate for the type extension system. Especially since Jeffrey Snover indicated that it’s not likely to be included as a direct language feature anytime soon.
The request was to support array slicing ala Python: “somelist[:-3]” would return “somelist” minus the last 3 elements.
Via type extensions, we can add a “Slice” method that accomplishes this same thing in nearly the same syntax. (Close enough, anyway.) Here’s a good description by Lee Holmes on how to add your custom type extensions.
<Type> <Name>System.Array</Name> <Members> <ScriptMethod> <Name>Slice</Name> <Script> if ($args[0] -eq $null) { $start = 0 } elseif ($args[0] -lt 0) { $start = $this.Length + [int]$args[0] } elseif ($args[0] -ge 0) { $start = [int]$args[0] } if ($args[1] -eq $null) { $end = $this.Length - 1 } elseif ($args[1] -lt 0) { $end = $this.Length + [int]$args[1] - 1 } elseif ($args[1] -ge 0) { $end = [int]$args[1] - 1 } if ($start -lt 0) { $start = 0 } elseif ($start -gt $this.Length) { return @() } if ($end -gt $this.Length) { $end = $this.Length } elseif ($end -lt 0) { return @() } if ($start -ge $end) { return @() } else { return $this[$start..$end] } </Script> </ScriptMethod> </Members> </Type>
(Note: I do not know Python – so my implementation of this method is based on search results like these: docs.python.org and diveintopython.org – I hope it works, if it doesn’t, please update it and let me know, or post something in the comments.)
Now, I can do this:
PS C:> $a = "one", "two", "three", "four", "five" PS C:> $aonetwothreefourfive PS C:> $a.Slice(0,-3)onetwo PS C:> $a.Slice(-3,-1)threefour PS C:>
Note that you could pass in $null for either the start or end parameters which would be the equivalent of excluding the value in Python. (i.e. “$a.Slice(5,$null)” would be this in Python: “a[5:]“)