Search code examples
c#powershellgenericsflaui

How to call a generic method in PowerShell?


I created a dll in C# and then called this dll in PowerShell. Below I have a method called TypeName<T>()

public class ClassTest
{
    public string TypeName<T>() where T : FlaUI.Core.AutomationElements.AutomationElement
    {
        return typeof(T).FullName;
    }
}

I'm using the FlaUI.Core reference from Nuget, that is, I'm just going to expect types from this reference:

where T : FlaUI.Core.AutomationElements.AutomationElement

In Powershell, how do I call this generic method? I've tried this and it doesn't work:

add-type -path C:\Users\unknow\source\repos\AutomationDLL\AutomationDLL\bin\Debug\My.dll
add-type -path C:\Users\unknow\source\repos\AutomationDLL\AutomationDLL\bin\Debug\FlaUI.Core.dll
add-type -path C:\Users\unknow\source\repos\AutomationDLL\AutomationDLL\bin\Debug\FlaUI.UIA3.dll

$instance = new-object ClassTest    
$instance.TypeName[[FlaUI.Core.AutomationElements.Button]]();

It is giving this error:

On line:7 character:59
+ $instance.TypeName[[FlaUI.Core.AutomationElements.Button]]();
+ ~
Unexpected token '(' in expression or statement.
On line:7 character:60
+ $instance.TypeName[[FlaUI.Core.AutomationElements.Button]]();
+~
An expression was expected after '('.
    + CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException
    + FullyQualifiedErrorId : UnexpectedToken

Solution

  • Only PowerShell (Core) 7.3+ supports calling generic methods with explicit type arguments - however, use only enclosing […] - do not also enclose the type argument(s) in […]:

    # PS 7.3+ only
    # Note: Only *one* set of [...], around the list of all type arguments,
    #       not also around the individual type(s).
    [ClassTest]::new().TypeName[FlaUI.Core.AutomationElements.Button]()
    

    See the conceptual about_Calling_Generic_Methods help topic.


    In PowerShell 7.2- (including in Windows PowerShell), direct calls to generic methods are only possible if the type argument(s) can be inferred from the parameter values (arguments), because these versions have no syntax for specifying type arguments explicitly.

    Otherwise - such as in your case, given that your method has no parameters (other than a type parameter) - you must use reflection:

    $instance = [ClassTest]::new()
    [ClassTest].
      GetMethod('TypeName', [type[]] @()).
      MakeGenericMethod([FlaUI.Core.AutomationElements.Button]).
      Invoke($instance, @())
    
    • .GetMethod('TypeName', [type[]] @()) finds the overload of method TypeName that has no parameters ([type[]] @()) - since there is only one overload in your case, you could omit the second argument.

    • .MakeGenericMethod([…]) instantiates the method with the desired type argument.

    • .Invoke($instance, @()) then invokes the type-instantiated method on instance $instance with no arguments (@(), the empty array).