2010-07-30 11 views
53

Attualmente sto scrivendo una libreria in C# e stavo usando PowerShell per testarlo rapidamente in alcune occasioni. Tuttavia, questo mi impedisce di ricostruire il progetto in quanto PowerShell ovviamente ha ancora la DLL aperta.È possibile rimuovere di nuovo un tipo aggiuntivo in PowerShell?

C'è un modo per scaricare nuovamente la DLL dopo averlo aggiunto con Add-Type? La documentazione non sembra avere indizi su questo e il candidato ovvio sarebbe Remove-Type (che non esiste - esiste comunque un solo comando con Type come suo nome). Diventa complicato chiudere PowerShell e fare tutto il necessario per navigare nella directory di costruzione e aggiungere di nuovo il tipo ogni volta che voglio ricostruire.

risposta

49

Come gli altri dicono, questo è un comportamento NET. Gli assembly caricati in un AppDomain non possono essere scaricati. Solo AppDomain può essere scaricato e powershell utilizza un singolo appdomain. Alcuni anni fa ne ho parlato un po 'di questo: http://www.nivot.org/2007/12/07/WhyAppDomainsAreNotAMagicBullet.aspx

Quando provo in questo modo, di solito mantengo una shell aperta e uso una shell nidificata per fare dei test. avviare powershell, cd in posizione bin, quindi eseguire "powershell" per avviare la shell nidificata (nuovo processo). "exit" per ricominciare ed eseguire nuovamente "powershell".

0

Ho riscontrato problemi simili. Non è possibile scaricare un tipo/assembly (perché si applica a .NET framework).

In .NET è possibile risolverlo se si crea un nuovo dominio applicazione (System.AppDomain) e si carica l'assembly in tale dominio. È possibile scaricare il dominio dell'app e che scarica anche tutte le DLL.

Non l'ho ancora provato, perché per me è molto più semplice chiudere una scheda in Console e aprirne una nuova.

+0

PowerShell utilizza solo un singolo appdomain, creando un nuovo appdomain, caricando i tipi in tale appdomain e quindi scaricando l'appdomain non scarica il tipo. –

20

Se il montaggio non richiede una binding context si può fare questo:

$bytes = [System.IO.File]::ReadAllBytes("Path_To_Your_Dll.dll") 
[System.Reflection.Assembly]::Load($bytes) 
+0

e come questo avrebbe reso possibile scaricare l'assemblaggio? –

+5

Non saresti in grado di scaricare, ma OTOH la DLL non verrà mantenuta aperta e bloccata in quanto la lettura è stata indipendente dal carico ('ReadAllBytes' non mantiene il file aperto o bloccato). Quindi dipende da ciò che l'OP vuole; questo risolverà il problema di "I can not build" che sembrava essere il driver per volere uno scaricamento. –

+2

Ti devo una pinta. – samaspin

31

Trovo che il modo più semplice per ovviare a questo problema è quello di avvolgere il codice Add-Type e il codice di prova all'interno di uno Start-Job. Start-Job creerà un processo in background e il tipo verrà caricato lì. Una volta che hai finito, il processo va via e sei libero di riprovare.

Ecco un esempio di come appare:

$job = Start-Job -ScriptBlock { 

    Add-Type -path 'my.dll' 
    $myObj = new-object My.MyTestClassName 

    $result = $myObj.TestMethod 
    $result 
} 
Wait-Job $job 
Receive-Job $job 

L'uscita dal metodo di prova sarà fatto eco alla console.

+1

Mi piace questo metodo, anche se nel mio caso ho bisogno del risultato di una variabile impostata nel lavoro in background. Senza scriverlo in un file, non sono sicuro di come otterrei quell'informazione. Tuttavia, penso che meriti un +1 –

+1

@SlogmeisterExtraordinaire Nel lavoro, echo il risultato. Nello script principale, chiama 'Receive-Job' per recuperarlo. –

+1

Ho aggiunto un esempio su come farlo. Qualsiasi errore di battitura nell'esempio è solo mio, e non @ Start-Automating. –

2

Ecco un esempio completo che permette di eseguire il comando Add-Type come processo in background in modo che il gruppo viene scaricato una volta termina:

# Start-Job will not preserve the working directory, so do it manually 
# Other arguments can also be passed to the job this way 
$cd = Split-Path $MyInvocation.MyCommand.Path 
$jobParams = @{ 
    'cd' = $cd 
} 

Start-Job -InputObject $jobParams -ScriptBlock { 
    cd $Input.cd 
    Add-Type -Path assembly.dll 
} | Receive-Job -Wait -AutoRemoveJob 

Receive-Job -Wait farà in modo che l'uscita del lavoro viene ricevuto dal altrimenti sarà perso.

Problemi correlati