2010-07-30 14 views
53

Actualmente estoy escribiendo una biblioteca en C# y estaba usando PowerShell para probarla rápidamente en algunas ocasiones. Sin embargo, esto me impide reconstruir el proyecto ya que PowerShell obviamente todavía tiene la DLL abierta.¿Se puede eliminar un tipo agregado en PowerShell nuevamente?

¿Hay alguna forma de volver a descargar el archivo DLL después de agregarlo con Add-Type? La documentación no parece tener pistas sobre eso y el candidato obvio sería Remove-Type (que no existe; solo hay un comando de todos modos con Type como sustantivo). Resulta engorroso cerrar PowerShell y hacer todo lo posible para navegar hasta el directorio de compilación y agregar el tipo nuevamente cada vez que quiero reconstruir.

Respuesta

49

Al igual que los otros dicen, se trata de un comportamiento .NET. Los ensamblados cargados en un AppDomain no se pueden descargar. Solo el AppDomain puede descargarse y powershell usa un solo appdomain. Publiqué un poco sobre esto hace algunos años: http://www.nivot.org/2007/12/07/WhyAppDomainsAreNotAMagicBullet.aspx

Cuando pruebo así, suelo mantener un caparazón abierto y usar un caparazón anidado para hacer las pruebas. Inicie powershell, cd en la ubicación del contenedor y luego ejecute "powershell" para iniciar el shell anidado (nuevo proceso). "exit" para comenzar nuevamente, y ejecute "powershell" nuevamente.

0

Me he enfrentado a un problema similar. No es posible descargar un tipo/ensamblaje (eso es porque se aplica a .NET framework).

En .NET puede resolverlo si crea un nuevo dominio de aplicación (System.AppDomain) y carga el ensamblado en ese dominio. Es posible descargar el dominio de la aplicación y eso descarga todos los dlls también.

No lo he intentado aún, porque para mí es mucho más simple cerrar una pestaña en Console y abrir una nueva.

+0

Powershell solo usa un solo dominio de aplicación, creando un nuevo dominio de aplicación, cargando tipos en ese dominio de aplicación y luego descargando el dominio de aplicación no descarga el tipo. –

20

Si su montaje no requiere una binding context usted puede hacer esto:

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

y cómo esto haría posible descargar el conjunto? –

+5

No podrá descargar, pero OTOH la DLL no se mantendrá abierta y bloqueada ya que la lectura ha sido independiente de la carga ('ReadAllBytes' no mantiene el archivo abierto o bloqueado). Entonces depende de lo que quiere el OP; esto solucionará el problema de "No puedo construir", que parecía ser el motor para querer descargar. –

+2

Te debo una pinta. – samaspin

31

La forma más sencilla de evitar este problema es ajustar el Add-Type y el código de prueba dentro de un Start-Job. Start-Job creará un proceso en segundo plano y el tipo se cargará allí. Una vez que haya terminado, el proceso desaparecerá y podrá volver a intentarlo.

Aquí hay un ejemplo de cómo se ve:

$job = Start-Job -ScriptBlock { 

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

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

La salida del método de prueba se hizo eco de la consola.

+1

Me gusta este método, aunque en mi caso necesito el resultado de un conjunto de variables en el trabajo de fondo. Sin escribirlo en un archivo, no estoy seguro de cómo obtendría esa información. Sin embargo, creo que se merece un +1 –

+1

@SlogmeisterExtraordinaire En el trabajo, repita el resultado. En el script principal, llame a 'Receive-Job' para recuperarlo. –

+1

Agregué un ejemplo de cómo hacer esto. Cualquier error tipográfico o error en el ejemplo es mío solo, y no de @ Start-Automating. –

2

Aquí es un ejemplo completo que permite ejecutar el comando Add-Type como un trabajo de fondo para que se descarga el montaje una vez que se 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 se asegurará de que la salida del trabajo se recibe desde de lo contrario, se perderá.

Cuestiones relacionadas