Considérez l'extrait de code PowerShell suivant:
$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 je l'exécute plusieurs fois dans le même AppDomain (par exemple, exécutez le script deux fois dans powershell.exe ou powershell_ise.exe), j'obtiens l'erreur suivante:
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
Comment encapsuler l'appel à Add-Type -TypeDefinition afin qu'il ne soit appelé qu'une seule fois?
Cette technique fonctionne bien pour moi:
if (-not ([System.Management.Automation.PSTypeName]'MyClass').Type)
{
Add-Type -TypeDefinition 'public class MyClass { }'
}
En interne, la classe PSTypeName appelle la méthode LanguagePrimitives.ConvertStringToType () qui gère le gros du travail. Il met en cache la chaîne de recherche en cas de succès, afin que les recherches supplémentaires soient plus rapides.
Je n'ai pas confirmé si oui ou non des exceptions sont levées en interne comme mentionné par x0n et Justin D.
En fait, rien de tout cela n'est requis. Add-Type conserve un cache de tout code que vous lui soumettez, ainsi que le type résultant. Si vous appelez Add-Type deux fois avec le même code, cela ne dérangera pas de compiler le code et renverra simplement le type de la dernière fois.
Vous pouvez le vérifier en exécutant simplement un appel Add-Type deux fois de suite.
La raison pour laquelle vous avez reçu le message d'erreur dans l'exemple ci-dessus est que vous avez changé le code entre les appels en Add-Type. Bien que la solution ci-dessus fasse disparaître cette erreur dans cette situation, cela signifie également que vous travaillez avec une ancienne définition du type qui n'agit probablement pas comme vous le pensez.
Il y a une meilleure façon de le faire sans encourir le coût des exceptions:
if (-not ("MyClass" -as [type])) {
add-type @"
public class MyClass { }
"@
}
mise à jour: bien, apparemment les signaux PowerShell en interne avec une exception de toute façon. Il a une mauvaise habitude de le faire. L'interpréteur utilise SEH pour signaler avec les mots clés break
et continue
, par exemple.
La façon la plus simple de le faire est un bloc try/catch. Vous avez deux options pour ce faire:
try { [MyClass] | Out-Null } catch { Add-Type -TypeDefinition $csharpString; }
try { Add-Type -TypeDefinition $csharpString; } catch {}
De cette façon, aucune exception n'est levée, c'est juste une petite base lente sur le nombre d'assemblages chargés:
[bool]([appdomain]::CurrentDomain.GetAssemblies() | ? { $_.gettypes() -match 'myclass' })