How does hash table .Get_Item() and .Set_Item() work if Get-Member doesn't list it?
Asked Answered
B

2

5

I came across a Powershell hash table article and it used .Get_Item() and .Set_Item().

Two questions:

1) What's the mechanism that allows syntax of .Get_Item() and .Set_Item() to work?

2) What Powershell command (if any) can one run to "discover" extra properties and methods that's not listed by Get-Member?

Example program:

$h = @{}
$h | get-member
$h | get-member -static

$h.add("copper", 29)

$h["copper"]
$h.item("copper")
$h.get_item("copper")

and the output shows Item() but neither Get_Item() nor Set_Item():

   TypeName: System.Collections.Hashtable

Name              MemberType            Definition                                                            
----              ----------            ----------                                                            
Add               Method                System.Void Add(System.Object key, System.Object value)               
Clear             Method                System.Void Clear()                                                   
Clone             Method                System.Object Clone()                                                 
Contains          Method                bool Contains(System.Object key)                                      
ContainsKey       Method                bool ContainsKey(System.Object key)                                   
ContainsValue     Method                bool ContainsValue(System.Object value)                               
CopyTo            Method                System.Void CopyTo(array array, int arrayIndex)                       
Equals            Method                bool Equals(System.Object obj)                                        
GetEnumerator     Method                System.Collections.IDictionaryEnumerator GetEnumerator()              
GetHashCode       Method                int GetHashCode()                                                     
GetObjectData     Method                System.Void GetObjectData(System.Runtime.Serialization.Serializatio...
GetType           Method                type GetType()                                                        
OnDeserialization Method                System.Void OnDeserialization(System.Object sender)                   
Remove            Method                System.Void Remove(System.Object key)                                 
ToString          Method                string ToString()                                                     
Item              ParameterizedProperty System.Object Item(System.Object key) {get;set;}                      
Count             Property              System.Int32 Count {get;}                                             
IsFixedSize       Property              System.Boolean IsFixedSize {get;}                                     
IsReadOnly        Property              System.Boolean IsReadOnly {get;}                                      
IsSynchronized    Property              System.Boolean IsSynchronized {get;}                                  
Keys              Property              System.Collections.ICollection Keys {get;}                            
SyncRoot          Property              System.Object SyncRoot {get;}                                         
Values            Property              System.Collections.ICollection Values {get;}                          
    TypeName: System.Collections.Hashtable

Name            MemberType Definition                                                         
----            ---------- ----------                                                         
Equals          Method     static bool Equals(System.Object objA, System.Object objB)         
ReferenceEquals Method     static bool ReferenceEquals(System.Object objA, System.Object objB)
Synchronized    Method     static hashtable Synchronized(hashtable table)     
29
29
29
Beau answered 13/5, 2014 at 19:7 Comment(5)
$h | get-member -forceCinnabar
Thanks. The intro documentation technet.microsoft.com/en-us/library/ee176854.aspx doesn't show it but based on your comment, I notice that the library help documents -force technet.microsoft.com/en-us/library/hh849928.aspx Should I delete this question if the answer is that simple? Not sure if my question was a duplicate I'm unaware of because I used different keywords to ask it.Beau
added an answer, but I don't understand what your first question is asking...Cinnabar
My question #1 was about my guess that some inheritance hierarchy (parent class) had Get_Item() set but I didn't know which one it was. It didn't look like it was System.Object because the naked Get-Member shows Clone() of System.Object -- therefore I was missing the mechanism of how Get_Item() works without causing a syntax error.Beau
The System.Object you see next to clone is the return value. and if you look at the "item" parameterizedproperty it returns a System.object, accepts a system.object key as a parameter, and has its own get and set methods. the get and set methods are just generated by the compiler, you can still use it like $h.item("copper").. if "copper" is a valid key in the hash, it will get it, if it doesn't exist, it will set itCinnabar
C
8

The get_ and set_ methods for any object will not be shown without specifying the -force parameter of the Get-Member cmdlet https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/get-member:

-Force
Adds the intrinsic members (PSBase, PSAdapted, PSObject, PSTypeNames) and the compiler-generated get_ and set_ methods to the display. By default, Get-Member gets these properties in all views other than "Base" and "Adapted," but it does not display them

Cinnabar answered 13/5, 2014 at 19:51 Comment(0)
F
0

To complement Cole9350's helpful answer:

  1. What's the mechanism that allows .get_Item() and .set_Item() to work?

These methods underlie the .Item property of the System.Collections.Hashtable type.

It is important to note that at the level of the CIL (Common Intermediate Language), aka IL and MSIL) that .NET languages compile into, the concept of a property doesn't exist:

  • Properties are syntactic sugar provided by .NET languages and compile into method calls behind the scenes.

  • The .Item property is a special kind of property known to VB.NET and PowerShell as a parameterized property, and as an indexer to C#.

    • PowerShell's Get-Member cmdlet reports them as such (e.g. @{} | Get-Member Item), but, as noted only reports the underlying methods with -Force (e.g. @{} | Get-Member -Force *Item)
  • Each of these languages provides syntactic sugar for implicitly using this property:

    • C# provides [...] (e.g. h["copper"])
    • VB.NET provides (...) (e.g. h("copper"))
    • PowerShell provides [...] and . (e.g., $h["copper"] and $h.copper)

Among these languages:

  • Only PowerShell allows you to call the underlying .get_Item() and set_Item() methods explicitly.

  • Both PowerShell and VB.NET - unlike C# - allow you to access the .Item property explicitly (e.g. $h.Item("copper") and h.Item("copper")

Therefore the following are all equivalent in PowerShell:

$h = @{}

# Setting
$h['copper'] = 29
$h.copper = 29
$h.Item('copper') = 29
$h.set_Item('copper', 29)

# Getting
$h['copper']
$h.copper
$h.Item('copper')
$h.get_Item('copper')

Note:

  • $h.Add('copper', 29), i.e. using the regular .Add() method, has slightly different semantics:

    • It creates the entry if one with this key doesn't exist yet, and fails otherwise.

    • By contrast, all of the variations of using the parameterized property implicitly create an entry or, if one already exists, update it.

  • There is usually no good reason to resort to calling .get_*() and .set_*() methods, but there are edge cases:

    • In cases where PowerShell's ETS (Extended Type System) shadows the native properties of .NET types, they can still be invoked this way:

      • Consider the following snippet:

          $xmlElem = ([xml] '<foo><name>child element text</name></foo>').foo
        
          # Using PowerShell's ETS adaption of the XML DOM returns the 
          # text of the (simple) '<name>' *child element*
          $xmlElem.Name # -> 'child element text'
        
          # Calling the underlying .get_*() method *overrides* the ETS
          # adaptation and returns the .Name property value of the 
          # System.Xml.XmlElement instance.
          $xmlElem.get_Name() # -> 'foo'
        
      • See this answer for background information.

Fastidious answered 20/10, 2023 at 22:5 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.