2009-06-26 5 views
63

Quando uso un altro oggetto in .net-Framework in C# posso risparmiare molto digitando usando la direttiva using.Equivalente alla parola chiave "using" di C# in powershell?

using FooCompany.Bar.Qux.Assembly.With.Ridiculous.Long.Namespace.I.Really.Mean.It; 

... 


    var blurb = new Thingamabob(); 

... 

Quindi c'è un modo in Powershell per fare qualcosa di simile? Sto accedono a un sacco di oggetti .NET e non sono felice di dover digitare

$blurb = new-object FooCompany.Bar.Qux.Assembly.With.Ridiculous.Long.Namespace.I.Really.Mean.It.Thingamabob; 

tutto il tempo.

risposta

11

Dai un'occhiata a questo post sul blog da un paio di anni fa: http://blogs.msdn.com/richardb/archive/2007/02/21/add-types-ps1-poor-man-s-using-for-powershell.aspx

Ecco add-types.ps1, tratto da tale articolo:

param(
    [string] $assemblyName = $(throw 'assemblyName is required'), 
    [object] $object 
) 

process { 
    if ($_) { 
     $object = $_ 
    } 

    if (! $object) { 
     throw 'must pass an -object parameter or pipe one in' 
    } 

    # load the required dll 
    $assembly = [System.Reflection.Assembly]::LoadWithPartialName($assemblyName) 

    # add each type as a member property 
    $assembly.GetTypes() | 
    where {$_.ispublic -and !$_.IsSubclassOf([Exception]) -and $_.name -notmatch "event"} | 
    foreach { 
     # avoid error messages in case it already exists 
     if (! ($object | get-member $_.name)) { 
      add-member noteproperty $_.name $_ -inputobject $object 
     } 
    } 
} 

E, si usa:

RICBERG470> $tfs | add-types "Microsoft.TeamFoundation.VersionControl.Client" 
RICBERG470> $itemSpec = new-object $tfs.itemspec("$/foo", $tfs.RecursionType::none) 

Fondamentalmente quello che faccio è scansionare l'assembly per tipi non banali, quindi scrivere un structor "che usa Add-Member aggiungerli (in modo strutturato) agli oggetti a cui tengo.

Vedi anche questo post followup: http://richardberg.net/blog/?p=38

+0

Sembra che sia necessario utilizzare il nome dell'assembly (ad es. Mscorlib) anziché il nome di un tipo (ad es. System.IO.Path). –

+0

Se non si dispone di un oggetto in giro per passarlo alla funzione, è possibile crearne uno usando 'Nuovo oggetto PSObject'. –

53

Non c'è davvero nulla a livello di spazio dei nomi come quello. Mi capita spesso di assegnare i tipi comunemente usati per le variabili e quindi un'istanza di:

$thingtype = [FooCompany.Bar.Qux.Assembly.With.Ridiculous.Long.Namespace.I.Really.Mean.It.Thingamabob]; 
$blurb = New-Object $thingtype.FullName 

Probabilmente non vale la pena se il tipo non viene utilizzato più volte, ma credo che sia la migliore che si può fare.

+0

A volte ho bisogno di convertire SecureStrings di nuovo in testo normale. Quanto segue è utile: '$ ns = [System.Runtime.InteropServices.Marshal]' allora puoi '$ ns :: PtrToStringAuto ($ ns :: SecureStringToBSTR ($ ss))'. – petrsnd

+0

Nota per coloro che guardano la risposta più votata: PowerShell 5.0 risolve questo problema. –

6

questo è solo uno scherzo, scherzo ...

$fullnames = New-Object ([System.Collections.Generic.List``1].MakeGenericType([String])); 

function using ($name) { 
foreach ($type in [Reflection.Assembly]::LoadWithPartialName($name).GetTypes()) 
    { 
     $fullnames.Add($type.fullname); 
    } 
} 

function new ($name) { 
    $fullname = $fullnames -like "*.$name"; 
    return , (New-Object $fullname[0]); 
} 

using System.Windows.Forms 
using FooCompany.Bar.Qux.Assembly.With.Ridiculous.Long.Namespace.I.Really.Mean.It 
$a = new button 
$b = new Thingamabob 
+0

Qualcuno può spiegare il doppio '' 1 nel tipo, trovo difficile cercare. – Pete

+0

Ciò equivale all'istruzione using C#, non alla direttiva using. –

+0

Mi piace il modo in cui questo sembra. Se ti dovessi impegnare, questa mi sembra una soluzione piuttosto elegante. La flessibilità di PowerShell nel creare una nuova sintassi mi rende molto felice. –

2

Grazie a tutti per il vostro input. Ho contrassegnato il contributo di Richard Berg come una risposta, perché ricorda più da vicino ciò che sto cercando.

Tutte le vostre risposte mi hanno portato sulla pista che sembra più promettente: Nel his blog post Keith Dahlby propone un comando Get-Type che consente una facile consuasione dei tipi per metodi generici.

Penso che non vi sia alcun motivo per non esagerare con la ricerca di un percorso predefinito di assiemi per un tipo.

Disclaimer: non hanno costruito che - ancora ...

Ecco come si potrebbe usarlo:

$path = (System.Collections.Generic, FooCompany.Bar.Qux.Assembly.With.Ridiculous.Long.Namespace.I.Really.Mean.It) 

$type = get-type -Path $path List Thingamabob 
$obj = new-object $type 
$obj.GetType() 

questo si tradurrebbe in un bel generica Elenco dei thingamabob. Ovviamente mi piacerebbe riassumere tutto senza la definizione del percorso in un'altra funzione di utilità. Il get-type esteso includerebbe un passo per risolvere qualsiasi tipo di dato sul percorso.

5

Ecco un codice che funziona in PowerShell 2.0 per aggiungere alias tipo. Ma il problema è che non è definito. Con un po 'di lavoro extra potresti "non importare" gli spazi dei nomi, ma questo dovrebbe portarti a un buon inizio.

############################################################################## 
#.SYNOPSIS 
# Add a type accelerator to the current session. 
# 
#.DESCRIPTION 
# The Add-TypeAccelerator function allows you to add a simple type accelerator 
# (like [regex]) for a longer type (like [System.Text.RegularExpressions.Regex]). 
# 
#.PARAMETER Name 
# The short form accelerator should be just the name you want to use (without 
# square brackets). 
# 
#.PARAMETER Type 
# The type you want the accelerator to accelerate. 
# 
#.PARAMETER Force 
# Overwrites any existing type alias. 
# 
#.EXAMPLE 
# Add-TypeAccelerator List "System.Collections.Generic.List``1" 
# $MyList = New-Object List[String] 
############################################################################## 
function Add-TypeAccelerator { 

    [CmdletBinding()] 
    param(

     [Parameter(Position=1,Mandatory=$true,ValueFromPipelineByPropertyName=$true)] 
     [String[]]$Name, 

     [Parameter(Position=2,Mandatory=$true,ValueFromPipeline=$true)] 
     [Type]$Type, 

     [Parameter()] 
     [Switch]$Force 

    ) 

    process { 

     $TypeAccelerators = [Type]::GetType('System.Management.Automation.TypeAccelerators') 

     foreach ($a in $Name) { 
      if ($TypeAccelerators::Get.ContainsKey($a)) { 
       if ($Force) { 
        $TypeAccelerators::Remove($a) | Out-Null 
        $TypeAccelerators::Add($a,$Type) 
       } 
       elseif ($Type -ne $TypeAccelerators::Get[$a]) { 
        Write-Error "$a is already mapped to $($TypeAccelerators::Get[$a])" 
       } 
      } 
      else { 
       $TypeAccelerators::Add($a, $Type) 
      } 
     } 

    } 

} 
+0

Josh, grazie non avevo ancora deciso di estendere gli acceleratori di tipo. Questo è molto interessante, penso che giocherò un po 'con esso. – froh42

+0

È comodo ma usalo con cautela. Niente di peggio di scrivere uno script che non funziona sulla macchina di qualcun altro. Per questo motivo non ho mai inserito questi acceleratori nel mio profilo. Se mai, li metterò all'inizio di uno script in questo modo fallirà subito con Add-TypeAccelerator. – Josh

4

Se avete solo bisogno di creare un'istanza del vostro tipo, è possibile memorizzare il nome del lungo spazio dei nomi in una stringa:

$st = "System.Text" 
$sb = New-Object "$st.StringBuilder" 

Non è così potente come la direttiva using in C#, ma almeno è molto facile da usare.

-2

mi rendo conto che è un vecchio post, ma che stavo cercando la stessa cosa e sono imbattuto in questo: http://weblogs.asp.net/adweigert/powershell-adding-the-using-statement

Edit: Suppongo che dovrei specificare che esso consente di utilizzare la sintassi familiare di ...

using ($x = $y) { ... } 
+1

Ciò equivale all'istruzione using C#, non alla direttiva using. –

+0

Touche '. Ho letto male la domanda. – haliphax

24

PowerShell 5.0 (incluso in WMF5 o Windows 10 in su), aggiunge la using namespace costruire alla lingua. Si può utilizzare nello script in questo modo:

#Require -Version 5.0 
using namespace FooCompany.Bar.Qux.Assembly.With.Ridiculous.Long.Namespace.I.Really.Mean.It 
$blurb = [Thingamabob]::new() 

(La #Require dichiarazione sulla prima linea non è necessario utilizzare using namespace, ma sarà evitare che l'esecuzione dello script in PS 4.0 e sotto dove using namespace è una sintassi errore.)

0
#Requires -Version 5 
using namespace System.Management.Automation.Host 
#using module