20

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

Jaime
  • 5,770
  • 4
  • 23
  • 50
Ivan Prodanov
  • 34,634
  • 78
  • 176
  • 248
  • 4
    Take a look here, it may helps you [EXTENSION METHODS IN WINDOWS POWERSHELL](http://community.bartdesmet.net/blogs/bart/archive/2007/09/06/extension-methods-in-windows-powershell.aspx) – SomeCode.NET Sep 18 '14 at 14:44
  • The C# code doesn't compile and doesn't work. You're missing a `;` at the end of `using System` and there should be a `using System.Collections.Generic;`. And the code results in an infinite loop. You could replace the whole `for` loop with just `yield return (int)Math.Pow(number, powerOf);`. – Keith Hill Sep 18 '14 at 15:03

3 Answers3

18

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
mklement0
  • 382,024
  • 64
  • 607
  • 775
Raf
  • 9,681
  • 1
  • 29
  • 41
  • 8
    Nice. Just to spell it out: while PowerShell doesn't allow you to call extension methods directly, on an _instance_ of a type for which it is defined, you can call them as _static_ methods on the _type_, and pass the instance as the 1st argument. – mklement0 Jan 06 '18 at 15:40
9

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>
Stroniax
  • 718
  • 5
  • 15
2

If you really want it to read closer to dot syntax, you could use an implicit or explicit conversion operator on your IntEx type and use it as a POCO instead of as a static extension.

It might look something like this...

$code=@'
public class MyExtClass {

    public string TheStringValue {get; set;}

    public MyExtClass(string theString){
        TheStringValue = theString;
    }

    public int NumberOf(string target)
    {
        return TheStringValue.Length - TheStringValue.Replace(target, "").Length;
    }

    public static implicit operator MyExtClass(string value){
        return new MyExtClass(value);
    }
}
'@
add-type -TypeDefinition $code

$str_eee = "TheTheThe"
$numberOfEs = ([MyExtClass]$str_eee).NumberOf("e")

if(3 -eq $numberOfEs){Write-Host PASS; exit 0}

Write-Host "FAIL";
exit 1
Josh Gust
  • 4,102
  • 25
  • 41