简体   繁体   中英

Generic type of Generic Type in Powershell

Well generics in Powershel are quite confusing. To instantiate a simple List you need to dance around with a tambourine:

$type = ("System.Collections.Generic.List"+'`'+"1") -as "Type"
$type= $type.MakeGenericType("System.string" -as "Type")
$o = [Activator]::CreateInstance($type)

But what if I need something a bit more complex like: <Dictionary<string,List<Foo>> for example

or for example here: Dictionary<string,List<string>>

$listType = ("System.Collections.Generic.List"+'`'+"1") -as "Type"
$listType = $listType.MakeGenericType("System.string" -as "Type")
$L = [Activator]::CreateInstance($listType)

$dicType = ("System.Collections.Generic.Dictionary"+'`'+"2") -as "Type"

#the next line is problematic
$dicType = $dicType.MakeGenericType( 
     @( ("system.string" -as "Type"), 
        ("System.Collections.Generic.List" as "Type)) # and that's of course wrong
      )

$D = [Activator]::CreateInstance($dicType )

While you can delve into CLR internal representations and make life hard for yourself, you don't have to:

$dict = new-object 'collections.generic.dictionary[string,int]'
$dict.add("answer", 42)

Want a type literal representation?

[collections.generic.dictonary[string,int]]

Done. How about generic type parameters?

$dictOfList = new-object 'collections.generic.dictionary[string,
    [collections.generic.list[int]]]'

Done.

However, there's an unfortunate catch. In PowerShell 2.0, there's a bug when you mix and match BCL and 3rd party types as type parameters. The latter need to be assembly qualified:

# broken over two lines for clarity with backtick escape
$o = new-object ('collections.generic.dictionary[[{0}],[{1}]]' -f `
        [type1].fullname, [type2].fullname)

Hope this helps. In PowerShell 3.0, this has been fixed.

Yeah, seems it's possible, but as almost everything else in PS, this is darn ugly too. Here's the real world example:

$requestItemsType is a Dictionary<string, List<Amazon.DynamoDB.Model.WriteRequest>>

$wrt = ("System.Collections.Generic.List``1" -as "Type") 
$wrt = $wrt.MakeGenericType( @( ("Amazon.DynamoDB.Model.WriteRequest" -as "Type")))

$requestItemsType = ("System.Collections.Generic.Dictionary"+'`'+"2") -as "Type"
$requestItemsType = $requestItemsType.MakeGenericType( @( ("System.string" -as "Type"), ($wrt)))
$ri = [Activator]::CreateInstance($requestItemsType)
$ri.Add("TaskLog",$writeRequests)

The example above doesn't have to be as complicated if you're creating a dictionary with a custom type defined:

$propertiesType = ("System.Collections.Generic.Dictionary"+'`'+"2") -as "Type"
$propertiesType = $propertiesType.MakeGenericType( @( ("System.string" -as "Type"), ("Namespace.CustomType" -as "Type")))
$properties = [Activator]::CreateInstance($propertiesType)

我知道这可能有点陈旧,但是此解决方法在PowerShell 2中似乎很好用,几乎可以用作直接替代方法。

$foo = [activator]::CreateInstance(([System.Collections.Generic.List[string]] -as 'Type'))

Weird. I've always just done like this:

$dict = [system.collections.generic.dictionary[string, int]]::new()

$dict.add("my string", 42)

I always thought it was odd seeing people use New-Object and other unnecessary stuff when the constructor overloads are all exposed in a much more convenient way.

Though I only started with PS 3.0, admittedly.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM