Indirectly Invoking Methods Via Variablenames

PSMDTAG:FAQ: Can I specify a methodname using a variable? e.g. $x.$y()


PSMDTAG:FAQ: Why do I get METHOD metadata when I specify a method without providing parentheses?


One of the great things about Windows PowerShell is that it is a latebound language which allows you to do all sorts of incredibly powerful operations.  Consider the following code which defines a function to display the properties of an object.  The names of the properties come from a file passed into the function:


PS> function test ($obj, $file) {
>> foreach ($prop in cat $file) {“{0,-12} : {1}” -f $prop, $obj.$prop}
>> }
>>


PS> cat properties.txt
Name
ID


PS> test (get-process notepad) properties.txt
Name         : notepad
ID           : 456


PS> cat properties2.txt
Name
WS
NPM
Handles


PS> test (get-process notepad) properties2.txt
Name         : notepad
WS           : 7483392
NPM          : 4520
Handles      : 50


This works because you can specify $Obj.$Prop  where $prop contains the name of the property you want to see.


So how about Methods?  Lets see how that works:


PS> $s=”This is a TEST”
PS> $method=”ToUpper”
PS> $s.$method()
Unexpected token ‘(‘ in expression or statement.
At line:1 char:12
+ $s.$method() <<<<


It turns out the the parser does not handle this situation. 


But now try this:


PS> $s=”This is a TEST”
PS> $s.ToUpper()
THIS IS A TEST
PS> $s.ToUpper

MemberType          : Method
OverloadDefinitions : {System.String ToUpper(), System.String ToUpper(Cultu
                      reInfo culture)}
TypeNameOfValue     : System.Management.Automation.PSMethod
Value               : System.String ToUpper(), System.String ToUpper(Cultur
                      eInfo culture)
Name                : ToUpper
IsInstance          : True


What is happening is that if you specify a METHOD with parens, we call it.  If you specify a method without parens, we return the metadata for that method.  This can be a tad non-plussing at first but it turns out to be very useful at times.  In particular, it allows you to do this:


PS> $s=”This is a TEST”
PS> $s.ToUpper.Invoke()
THIS IS A TEST
PS> foreach ($method in “ToUpper”,”ToLower”,”GetType”) {$s.$method.Invoke()}


THIS IS A TEST
this is a test


IsPublic IsSerial Name                                     BaseType
——– ——– —-                                     ——–
True     True     String                                   System.Object


Enjoy!


 


Jeffrey Snover [MSFT]
Windows PowerShell/Aspen Architect
Visit the Windows PowerShell Team blog at:   
http://blogs.msdn.com/PowerShell
Visit the Windows PowerShell ScriptCenter at:  http://www.microsoft.com/technet/scriptcenter/hubs/msh.mspx


PSMDTAG:INTERNAL: Indirectly invoking methods via variable Names


PSMDTAG:LANGUAGE: Parser does not accept directly support variable substitution for method names