function New-Generic { [CmdletBinding()] param( [Parameter(Mandatory=$true, Position=0)] [ValidateNotNullOrEmpty()] [string]$type, [Parameter(Mandatory=$true, Position=1)] [ValidateNotNullOrEmpty()] [string[]]$typeParameter, [Parameter(Mandatory=$false, Position=3)] [array]$constructorParameters=$null ) $genericType = [type]($type + ‘`’ + $typeParameter.Count) [type[]] $tParameters = $typeParameter $closedType = $genericType.MakeGenericType($tParameters) Write-Verbose "Creating object $closedType with parameters $constructorParameters" return ,([Activator]::CreateInstance($closedType, [Object[]]$constructorParameters)) }Najwięcej czasu w napisaniu tej funkcji zajęło mi dodanie przecinka po słowie return. Ponad jeden dzień spędziłem w szukaniu dlaczego kastuje mi do zwyczajnego obiektu. Ten przecinek robi jakąś magię :)
Powyższa funkcja tworzy obiekt, który jest generyczny. Postanowiłem owrappować tą funkcję z najczęściej używanymi kolekcjami generycznymi:
function New-List { [CmdletBinding()] param( [Parameter(Mandatory=$true, Position=0)] [ValidateNotNullOrEmpty()] [string] $typeParameter ) return ,( New-Generic -type 'System.Collections.Generic.List' -typeParameter $typeParameter ) } function New-LinkedList { [CmdletBinding()] param( [Parameter(Mandatory=$true, Position=0)] [ValidateNotNullOrEmpty()] [string] $typeParameter ) return ,( New-Generic -type 'System.Collections.Generic.LinkedList' -typeParameter $typeParameter ) } function New-Queue { [CmdletBinding()] param( [Parameter(Mandatory=$true, Position=0)] [ValidateNotNullOrEmpty()] [string] $typeParameter ) return ,( New-Generic -type 'System.Collections.Generic.Queue' -typeParameter $typeParameter ) } function New-SortedSet { [CmdletBinding()] param( [Parameter(Mandatory=$true, Position=0)] [ValidateNotNullOrEmpty()] [string] $typeParameter ) return ,( New-Generic -type 'System.Collections.Generic.SortedSet' -typeParameter $typeParameter ) } function New-Stack { [CmdletBinding()] param( [Parameter(Mandatory=$true, Position=0)] [ValidateNotNullOrEmpty()] [string] $typeParameter ) return ,( New-Generic -type 'System.Collections.Generic.Stack' -typeParameter $typeParameter ) } function New-HashSet { [CmdletBinding()] param( [Parameter(Mandatory=$true, Position=0)] [ValidateNotNullOrEmpty()] [string] $typeParameter ) return ,( New-Generic -type 'System.Collections.Generic.HashSet' -typeParameter $typeParameter ) } function New-Dictionary { [CmdletBinding()] param( [Parameter(Mandatory=$true, Position=0)] [ValidateNotNullOrEmpty()] [string]$keyType, [Parameter(Mandatory=$true, Position=1)] [ValidateNotNullOrEmpty()] [string]$valueType ) return ,(New-Generic -type 'System.Collections.Generic.Dictionary' -typeParameter $keyType,$valueType) } function New-SortedDictionary { [CmdletBinding()] param( [Parameter(Mandatory=$true, Position=0)] [ValidateNotNullOrEmpty()] [string]$keyType, [Parameter(Mandatory=$true, Position=1)] [ValidateNotNullOrEmpty()] [string]$valueType ) return ,(New-Generic -type 'System.Collections.Generic.SortedDictionary' -typeParameter $keyType,$valueType) } function New-SortedList { [CmdletBinding()] param( [Parameter(Mandatory=$true, Position=0)] [ValidateNotNullOrEmpty()] [string]$keyType, [Parameter(Mandatory=$true, Position=1)] [ValidateNotNullOrEmpty()] [string]$valueType ) return ,(New-Generic -type 'System.Collections.Generic.SortedList' -typeParameter $keyType,$valueType) } function New-KeyValuePair { [CmdletBinding()] param( [Parameter(Mandatory=$true, Position=0)] [ValidateNotNullOrEmpty()] [string]$keyType, [Parameter(Mandatory=$true, Position=1)] [ValidateNotNullOrEmpty()] [string]$valueType ) return ,(New-Generic -type 'System.Collections.Generic.KeyValuePair' -typeParameter $keyType,$valueType) }Przykład użycia dla listy jest poniżej. Można zauważyć rzucenie wyjątku kiedy będziemy chcieli dodać obiekt do listy, który nie może być kastowany do int:
$list = New-List "int" -Verbose $list.GetType() $list.Add(1) $list.Add('2') $list.Add("three") #throw exceptionRównież można zainicjalizować stos doubli:
$stack= New-Stack -typeParameter 'double' $stack.getType() $stack.Push(1) $stack.Push(20000) $stack.Push(-1.123) $stack.Pop()A tworzenie słownika wygląda następująco:
$dic = New-Dictionary -keyType 'string' -valueType 'int' $dic.Add("one",1) $dic.Add("two",2)Zanim stworzy się funkcję dla tupli to będzie potrzebna funkcja zwracająca domyślne wartości:
function Get-DefaultValue { param( [Parameter(Position=0,Mandatory=$true,ValueFromPipeline=$true)] [type]$type ) process{ if($type.IsValueType) { return [Activator]::CreateInstance($type) } return $null } }Wynik dla boola:
Get-DefaultValue 'bool' #FalseA funkcja do tworzenia tupli jest następująca:
function New-Tuple { [CmdletBinding()] param( [Parameter(Mandatory=$true, Position=0)] [ValidateNotNullOrEmpty()] [string[]] $typeParameter , [Parameter(Mandatory=$false, Position=1)] [array]$constructorParameters ) if(-not($constructorParameters)) { $constructorParameters = $typeParameter |Get-DefaultValue } return ,( New-Generic -type 'System.Tuple' -typeParameter $typeParameter -constructorParameters $constructorParameters ) }Oczywiście można stworzyć tuple dla dowolnej (o ile pozwoli konstruktor) ilości parametrów
$tuple3= new-Tuple -typeParameter 'int', 'object', 'string' $tuple3.GetType(); $tuple3.Item1 $tuple3= new-Tuple -typeParameter 'int', 'bool', 'string' -constructorParameters 1,$true, "SuperString" $tuple3.Item2 $tuple3.Item3
Brak komentarzy:
Prześlij komentarz