Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use Extension methods in Powershell?

I have the following code:

using System
public static class IntEx
{
    /// <summary>
    /// Yields a power of the given number
    /// </summary>
    /// <param name="number">The base number</param>
    /// <param name="powerOf">the power to be applied on te base number</param>
    /// <returns>Powers applied to  the base number</returns>
    public static IEnumerable<int> ListPowersOf(this int number, int powerOf)
    {
        for (var i = number; ; i <<= powerOf)
        {
            yield return i;
        }
    }
}

I've loaded the dll in Powershell(Windows 8). I try to use it the following way:

$test = 1.ListPowersOf(2)

Should return @(1, 2, 4, 8, 16...)

Instead it says there is no such method.

I tried the following:

[BaseDllNamespace]::ListPowersOf(1,2)

Still nothing. I have no namespace in the IntEx class.

How do I make it work

like image 693
Ivan Prodanov Avatar asked Sep 18 '14 14:09

Ivan Prodanov


2 Answers

Try this:

[IntEx]::ListPowersOf(1,2)

or

[IntEx] | gm -Static -Type Method

to list available static methods.

You can also use reflection to obtain list of exported types to see if yours is available:

[Reflection.Assembly]::LoadFile('C:path\to.dll')|select -ExpandProperty ExportedTypes
like image 185
Raf Avatar answered Oct 06 '22 05:10

Raf


I realize this isn't likely to apply to OP at this point, but this question was the first result for my search so I'll post what I figured out here.

I'm pretty surprised this one isn't already mentioned, but CodeMethods in PowerShell are essentially compiled extension methods for a given type. They're pretty easy to write, too - especially when you already have the extension method.

public static class MyStringExtensions
{
    public static string Append(this string source, params char[] characters)
    {
        foreach (var c in characters)
        {
            source += c;
        }
        return source;
    }
    // named PSAppend instead of Append. This is just a naming convention I like to use,
    // but it seems some difference in name is necessary if you're adding the type data 
    // via a types.ps1xml file instead of through the Update-TypeData command
    public static string PSAppend(PSObject source, params char[] characters)
    {
        if (source.BaseObject is string sourceString)
        {
            return sourceString.Append(characters);
        }
        else throw new PSInvalidOperationException();
    }
    private static string Example() {
        var myString = "Some Value.";
        Console.WriteLine(myString.Append(" and then some more.".ToCharArray()));
        // console output: 
        // Some Value. and then some more.
    }
}

After loading the type definition into PowerShell:

$method = [MyStringExtensions].GetMethod('PSAppend')
Update-TypeData -TypeName System.String -MemberName Append -MemberType CodeMethod -Value $method
# now you can use the method the same way you'd use an extension method in C#
PS:\> $myString = "Some Value."
PS:\> $myString.Append(" and then some more.")
Some value. and then some more.

Documentation for code methods is less than ideal. If you're building this into a module and defining a CodeMethod in your Types.ps1xml file referenced by your manifest (.psd1), you'll need to include the assembly that defines the code method in the RequiredAssemblies of the manifest. (Including it as RootModule is insufficient because the assemblies of the type(s) must be loaded before the type file(s) are loaded.)

Here's how you'd include this type definition in a Types.ps1xml file:

<?xml version="1.0" encoding="utf-8" ?>
<Types>
    <Type>
        <Name>System.String</Name>
        <Members>
            <CodeMethod>
                <Name>Append</Name>
                <CodeReference>
                    <TypeName>MyStringExtensions</TypeName>
                    <MethodName>PSAppend</MethodName>
                </CodeReference>
            </CodeMethod>
        </Members>
    </Type>
</Types>
like image 42
Stroniax Avatar answered Oct 06 '22 05:10

Stroniax