powershell - ¿Cómo agrego de manera condicional una clase con Add-Type-TypeDefinition si aún no se ha agregado?
(5)
De esta forma, no se lanza ninguna excepción, es solo una base un poco lenta en la cantidad de ensamblajes cargados:
[bool]([appdomain]::CurrentDomain.GetAssemblies() | ? { $_.gettypes() -match ''myclass'' })
Considere el siguiente fragmento de PowerShell:
$csharpString = @"
using System;
public sealed class MyClass
{
public MyClass() { }
public override string ToString() {
return "This is my class. There are many others " +
"like it, but this one is mine.";
}
}
"@
Add-Type -TypeDefinition $csharpString;
$myObject = New-Object MyClass
Write-Host $myObject.ToString();
Si lo ejecuto más de una vez en el mismo dominio de la aplicación (por ejemplo, ejecuto el script dos veces en powershell.exe o powershell_ise.exe), aparece el siguiente error:
Add-Type : Cannot add type. The type name ''MyClass'' already exists.
At line:13 char:1
+ Add-Type -TypeDefinition $csharpString;
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (MyClass:String) [Add-Type],
Exception
+ FullyQualifiedErrorId :
TYPE_ALREADY_EXISTS,Microsoft.PowerShell.Commands.AddTypeCommand
¿Cómo ajuste la llamada a Add-Type -TypeDefinition para que solo se llame una vez?
En realidad, nada de esto es obligatorio. Add-Type mantiene un caché de cualquier código que le envíe, junto con el tipo resultante. Si llama a Add-Type dos veces con el mismo código, no molestará en compilar el código y solo devolverá el tipo de la última vez.
Puede verificar esto simplemente ejecutando una llamada Add-Type dos veces seguidas.
El motivo por el que recibió el mensaje de error en el ejemplo anterior es que cambió el código entre las llamadas a Agregar-Tipo. Si bien la solución anterior hace que ese error desaparezca en esta situación, también significa que está trabajando con una definición anterior del tipo que probablemente no está actuando de la manera que cree que es.
Esta técnica funciona bien para mí:
if (-not ([System.Management.Automation.PSTypeName]''MyClass'').Type)
{
Add-Type -TypeDefinition ''public class MyClass { }''
}
- El nombre del tipo puede estar entre comillas ''MyClass'', corchetes [MyClass], o ambos ''[MyClass]'' (v3 + solamente).
- La búsqueda del nombre de tipo no distingue entre mayúsculas y minúsculas.
- Debe usar el nombre completo del tipo, a menos que sea parte del espacio de nombres del sistema (por ejemplo, [System.DateTime] se puede buscar a través de ''DateTime'', pero [System.Reflection.Assembly] no se puede buscar a través de ''Assembly'' )
- Solo he probado esto en Win8.1; PowerShell v2, v3, v4.
Internamente, la clase PSTypeName llama al método LanguagePrimitives.ConvertStringToType () que maneja el trabajo pesado. Almacena en caché la cadena de búsqueda cuando tiene éxito, por lo que las búsquedas adicionales son más rápidas.
No he confirmado si se lanzan o no excepciones internamente como lo mencionaron x0n y Justin D.
Hay una forma más sencilla de hacerlo sin incurrir en el costo de las excepciones :
if (-not ("MyClass" -as [type])) {
add-type @"
public class MyClass { }
"@
}
actualización: bueno, al parecer, PowerShell señala internamente con una excepción de todos modos. Tiene una mala costumbre de hacer esto. El intérprete usa SEH para señalar con el break
y continue
palabras clave, por ejemplo.
La forma más sencilla de hacerlo es un bloque try / catch. Tienes dos opciones para hacer esto:
-
try { [MyClass] | Out-Null } catch { Add-Type -TypeDefinition $csharpString; }
-
try { Add-Type -TypeDefinition $csharpString; } catch {}