Getting the members of a type, without an instance of the type
I read Jeff Hicks’s article about “Dancing on the table with PowerShell”. The content is really quite fascinating (go read it !), but I got hung up on something.
He creates a new object of the type [System.Data.DataTable]
, pipes it to Get-Member
and shows that we can’t discover the members of this object type, like so :
C:\> $table = New-Object -TypeName 'System.Data.DataTable'
C:\> $table | Get-Member
Get-Member : You must specify an object for the Get-Member cmdlet.
At line:1 char:10
+ $table | Get-Member
+ ~~~~~~~~~~
+ CategoryInfo : CloseError: (:) [Get-Member], InvalidOperationException
+ FullyQualifiedErrorId : NoObjectInGetMember,Microsoft.PowerShell.Commands.GetMemberCommand
My understanding is that Get-Member
is complaining because at this point, $table
is not a fully formed object. Even though it has a type :
C:\> $table.GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True DataTable System.ComponentModel.MarshalByValueComponent
Anyway, my thought was :
There has to be a way to get the members of a type, even without an instance of that type
So, let’s see how we can do that.
First, we get a type object from our type name :
C:\> $TypeObj = 'System.Data.DataTable' -as [Type]
Then, this [Type]
object surely has a property or a method allowing us to view the members associated with that type.
So we can try something like this :
C:\> $TypeObj | Get-Member -Name "*Members*"
TypeName: System.RuntimeType
Name MemberType Definition
---- ---------- ----------
FindMembers Method System.Reflection.MemberInfo[] FindMembers(System.Reflection.MemberTypes memberType, Sy...
GetDefaultMembers Method System.Reflection.MemberInfo[] GetDefaultMembers(), System.Reflection.MemberInfo[] _Typ...
GetMembers Method System.Reflection.MemberInfo[] GetMembers(), System.Reflection.MemberInfo[] GetMembers(...
Yep, the GetMembers
method (if it does what it says) is what we want.
Let’s try it :
C:\> $TypeObj.GetMembers() | Select-Object -Property 'Name', 'MemberType'
Name MemberType
---- ----------
get_CaseSensitive Method
set_CaseSensitive Method
get_IsInitialized Method
set_RemotingFormat Method
get_RemotingFormat Method
get_ChildRelations Method
get_Columns Method
get_Constraints Method
get_DataSet Method
get_DefaultView Method
set_DisplayExpression Method
get_DisplayExpression Method
get_ExtendedProperties Method
get_HasErrors Method
get_PrimaryKey Method
set_PrimaryKey Method
# Ouput cut for brevity
C:\> ($TypeObj.GetMembers() | Select-Object -Property 'Name', 'MemberType').Count
159
There are a lot of members for this type.
This method also allows us to see some members that we wouldn’t see by default using Get-Member
, because it even gets non-public members.
And there are some duplicates :
C:\> ($TypeObj.GetMembers() | Select-Object 'Name', 'MemberType' -Unique).Count
120
By the way, in case we are only interested in the properties, there is another method (aptly named GetProperties
) which gets only the properties :
C:\> $TypeObj.GetProperties() | Select-Object -Property 'Name', 'MemberType'
Name MemberType
---- ----------
CaseSensitive Property
IsInitialized Property
RemotingFormat Property
ChildRelations Property
Columns Property
Constraints Property
DataSet Property
DefaultView Property
DisplayExpression Property
ExtendedProperties Property
HasErrors Property
Locale Property
MinimumCapacity Property
ParentRelations Property
PrimaryKey Property
Rows Property
TableName Property
Namespace Property
Prefix Property
Site Property
Container Property
DesignMode Property
That’s pretty much all we need to know to view the members associated with a type, without having to create an object of that type.
We can package this knowledge into a function, for convenient reuse, like so :
Function Get-MemberFromTypeName
{
[CmdletBinding()]
Param (
[Parameter(Mandatory)]
[string]$TypeName
)
$TypeObj = $TypeName -as [Type]
$RawMembers = $TypeObj.GetMembers()
[System.Collections.ArrayList]$OutputMembers = @()
Foreach ( $RawMember in $RawMembers ) {
$OutputProps = [ordered]@{
'Name'= $RawMember.Name
'MemberType'= $RawMember.MemberType
}
$OutputMember = New-Object -TypeName psobject -Property $OutputProps
$OutputMembers += $OutputMember
}
$OutputMembers | Select-Object -Property * -Unique
}
Comments
Jeff Hicks
Thanks for taking time to explain this process so clearly. I didn’t want to go off too deep into a tangent in my article.
Mathieu Buisson
Hi Jeffery,
Thanks for the comment.
I thought as much, it loses the train of thought if you go in a long tangent.
Leave a Comment
Your email address will not be published. Required fields are marked *