'Can't seem to use generic collection with a PowerShell class
I'm trying to invoke the List[T](IEnumerable) directly adding an item to the initial List like so, where T is a PowerShell class I've written (the below example uses the class name Thing:
$someObject = Get-Thing # returns a single object
$list = [List[Thing]]::new(@( $someObject ))
However, this yields an error suggesting it can't find the overload for this constructor:
Cannot find an overload for "List`1" and the argument count: "1".
Setting List[T] to the Object class works, however:
$someObject = Get-Thing
$list = [List[Object]]::new(@( $someObject ))
While this works, I'm unsure why I'm unable to use my PowerShell class as the type. My understanding is that only context-bound types and (by default) nested types are unable to be used with generics, but the following shows that my class is not a ContextBoundObject:
class Thing {
$Name
Thing($name) {
$this.Name = $name
}
}
$thing = [Thing]::new('Bender')
$thing -is [System.ContextBoundObject] # ==> False
I'm not certain if a PowerShell class would be a nested type of some sort, and about_Classes does not mention nested types.
Solution 1:[1]
To complement Mathias R. Jessen's helpful answer, which explains the problem well and offers an effective solution:
PowerShell's casts are not only syntactically more convenient, but also more flexible when it comes to on-demand type conversions.
Indeed, using a cast instead of calling a constructor, via the static ::new() method, does work:
using namespace System.Collections.Generic
class Thing { [string] $Name; Thing([string] $name) { $this.Name = $name } }
# Both of the following work:
# Single [Thing] instance.
$list = [List[Thing]] [Thing]::new('one')
# Multiple [Thing] instances, as an array, via the grouping operator, (...)
# @(...), the array subexpression operator, works too, but is unnecessary.
$list = [List[Thing]] ([Thing]::new('one'), [Thing]::new('two'))
PowerShell's automatic type conversions, as also used in casts:
Unfortunately, as of this writing the rules aren't documented, but a comment in the source-code provides a high-level overview, as does the (pretty low-level) ETS type converters documentation, which can be summarized as follows, in descending order of precedence:
First, engine-internal, fixed conversion rules may be applied (see source-code link above).
A notable internal rule concerns to-string conversions: while any .NET type supports it by an explicit call to its
.ToString()method (inherited from the root of the object hierarchy,System.Object), PowerShell applies custom rules:If a type has a culture-sensitive
.ToString(<IFormatProvider>)overload, PowerShell passes the invariant culture deliberately, to achieve a culture-invariant representation, whereas a direct.ToString()call would yield a culture-sensitive representation - see this answer for details; e.g., in a culture where,is the decimal mark,[string] 1.2returns'1.2'(period), whereas(1.2).ToString()returns'1,2'(comma).Collections, including arrays, are stringified by concatenating their (stringified) elements with a space as the separator (by default, can be overridden with preference variable
$OFS); e.g.,[string] (1, 2)returns1 2, whereas(1, 2).ToString()returns merelySystem.Object[].
Also, PowerShell converts freely:
- between different number types (when possible).
- between numbers and strings (in a culture-invariant manner, recognizing only
.as the decimal mark when converting from a string). - and allows any data type to be converted to (interpreted as) as Boolean - see the bottom section of this answer for the rules.
Next,
TypeConverteror (PSTypeConverter) classes that implement custom conversions for specific types are considered.If the input type is a string (
[string]), a static::Parse()method is considered, if present: first, one with a culture-sensitive signature,::Parse(<string>, <IFormatProvider>), in which case the invariant culture is passed, and, otherwise one with signature::Parse(<string>).Next, a single-argument constructor is considered, if the input type matches the argument's type or is convertible to it.
If an implicit or explicit conversion operator exists for conversion between the input and the target type.
Finally, if the input object implements the
System.IConvertibleinterface and the target type is a supported-by-the-implementation primitive .NET type except[IntPtr]and[UIntPtr]or one of the following types:[datetime],[DBNull],[decimal].
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
