Question [Astuce]Cmt savoir si 1 objet est une collection ?
- Laurent Dardenne
- Auteur du sujet
- Hors Ligne
- Modérateur
Réduire
Plus d'informations
- Messages : 6302
- Remerciements reçus 68
il y a 16 ans 3 mois - il y a 3 ans 5 mois #2498
par Laurent Dardenne
Tutoriels PowerShell
Je viens de passer qq temps à rechercher une solution, voici comment on peut faire :On peut donc ensuite effectuer un Foreach sur la collection sans problème.
Cela peut être utile, par exemple, dans un traitement utilisant le pipeline.
L'opérateur -is/-isnot permet d'interroger la classe de l'objet et les interfaces qu'il implémente.
$Tab=@(1,2)
$I=10
#Est-ce que l'object est une collection ? (On teste si l'objet implémente l'interface IEnumerable)
$Tab -is [System.Collections.IEnumerable]
$I -is [System.Collections.IEnumerable]
Cela peut être utile, par exemple, dans un traitement utilisant le pipeline.
L'opérateur -is/-isnot permet d'interroger la classe de l'objet et les interfaces qu'il implémente.
Tutoriels PowerShell
Dernière édition: il y a 3 ans 5 mois par Laurent Dardenne.
Connexion ou Créer un compte pour participer à la conversation.
- Arnaud Petitjean
- Hors Ligne
- Modérateur
il y a 16 ans 3 mois #2499
par Arnaud Petitjean
MVP PowerShell et créateur de ce magnifique forum
Auteur de 6 livres PowerShell aux éditions ENI
Fondateur de la société Start-Scripting
Besoin d'une formation PowerShell ?
Réponse de Arnaud Petitjean sur le sujet Re:[Astuce]Cmt savoir si 1 objet est une collection ?
Merci Laurent pour ta contribution. Je vais la déplacer dans la section Articles/Tuto.
Arnaud
Arnaud
MVP PowerShell et créateur de ce magnifique forum
Auteur de 6 livres PowerShell aux éditions ENI
Fondateur de la société Start-Scripting
Besoin d'une formation PowerShell ?
Connexion ou Créer un compte pour participer à la conversation.
- Laurent Dardenne
- Auteur du sujet
- Hors Ligne
- Modérateur
Réduire
Plus d'informations
- Messages : 6302
- Remerciements reçus 68
il y a 16 ans 1 jour - il y a 3 ans 5 mois #2880
par Laurent Dardenne
Tutoriels PowerShell
Réponse de Laurent Dardenne sur le sujet Re:[Astuce]Cmt savoir si 1 objet est une collection ?
Un petit complément à propos du test d'une interface générique :<br><br>Message édité par: Laurent Dardenne, à: 16/11/08 18:57
#Test si $Str implémente System.IEquatable<String>
$Str="Test"
$Str -is [System.IEquatable``1[System.String]]
#True
#Test si $Str implémente System.IEquatable<Int32>
$Str -is [System.IEquatable``1[System.Int32]]
#False
#Liste des interfaces supportées par le type de la variable $Str
$Str.GetType().GetInterfaces()
Tutoriels PowerShell
Dernière édition: il y a 3 ans 5 mois par Laurent Dardenne.
Connexion ou Créer un compte pour participer à la conversation.
- Laurent Dardenne
- Auteur du sujet
- Hors Ligne
- Modérateur
Réduire
Plus d'informations
- Messages : 6302
- Remerciements reçus 68
il y a 15 ans 3 mois - il y a 3 ans 5 mois #4853
par Laurent Dardenne
Tutoriels PowerShell
Réponse de Laurent Dardenne sur le sujet Re:[Astuce]Cmt savoir si 1 objet est une collection ?
Comment savoir si une collection est accessible par un index ?La fonction de test :Pour tester un type la syntaxe suivante ne fonctionne pas car PS cast le paramètre en un paramètre de type String :On doit forcer le type ainsi :Dans la fonction on teste sur les noms d'interfaces car une classe peut implémenter soit l'interface IList, soit l'interface IList génerique ( IList<T> ), ou les deux.
Dans le cas de l'interface générique on ne peut pas l'utiliser avec le paramètre -is car il nécessite de préciser le type complet ( [System.IList``1[System.String]] ).
Mais comme on ne connait pas le type utilisé lors de la construction de la collection à tester, bien qu'on puisse le rechercher via le système de réflexion de dotnet, on testera donc sur le nom de l'interface et pas sur son type, ce qui simplifie le code :
#Collection indexée
[system.array].GetInterfaces()
#Collection indexé
[object[]].GetInterfaces()
#Collection sans index
[System.Management.ManagementObjectCollection].GetInterfaces()
function Test-AccessedByIndex($Object)
{ #Renvoi true si $Object est une collection accessible par un index
if ($object -is [type])
{
#Object =[System.Array]
$Interfaces=$Object.GetInterfaces()
}
else
{
#Object ="String"
$Interfaces=$Object.GetType().GetInterfaces()
}
#on force le résultat en un tableau
@($Interfaces|Where-Object {$_.name -match "IList"}).count -gt 0
}
$a=@(1,2,3)
Test-AccessedByIndex $a
#True
Test-AccessedByIndex [system.Array]
#False
Test-AccessedByIndex ([system.Array] -as [type])
#True
#ou
Test-AccessedByIndex ("system.Array" -as [type])
$T="system.Array"
Test-AccessedByIndex ($T -as [type])
Dans le cas de l'interface générique on ne peut pas l'utiliser avec le paramètre -is car il nécessite de préciser le type complet ( [System.IList``1[System.String]] ).
Mais comme on ne connait pas le type utilisé lors de la construction de la collection à tester, bien qu'on puisse le rechercher via le système de réflexion de dotnet, on testera donc sur le nom de l'interface et pas sur son type, ce qui simplifie le code :
[System.array],[object[]],[System.Management.ManagementObjectCollection]|
% { "Le type {0} est-il une collection indexée ? {1}" -F $_.Name, (Test-AccessedByIndex $_)}
# Le type Array est-il une collection indexée ? True
# Le type Object[] est-il une collection indexée? True
# Le type ManagementObjectCollection est-il une collection indexée ? False
Tutoriels PowerShell
Dernière édition: il y a 3 ans 5 mois par Laurent Dardenne.
Connexion ou Créer un compte pour participer à la conversation.
- Laurent Dardenne
- Auteur du sujet
- Hors Ligne
- Modérateur
Réduire
Plus d'informations
- Messages : 6302
- Remerciements reçus 68
il y a 3 ans 5 mois #30834
par Laurent Dardenne
Tutoriels PowerShell
Réponse de Laurent Dardenne sur le sujet Re:[Astuce]Cmt savoir si 1 objet est une collection ?
Une fonction permettant de vérifier si un objet implémente l'interface générique IEnumerable et ce sans avoir à tester un type fermé :On crée une closure pour ne pas avoir à reconstruire le type genrique ouvert.
L'usage d'un module simplifierait ce code :
Quelques exemples avec les types les plus courant :
${Function:Test-GenericIEnumerable}=.{
#On recherche le type ouvert de l'interface générique IEnumerable
$GenericIEnumerable=[Type]'System.Collections.Generic.IEnumerable`1'
Return {
#La variable $InputObject implémente-t-elle l'interface générique IEnumerable ?
param(
[ValidateNotNull()]
$InputObject
)
foreach ($Interface in $InputObject.GetType().GetInterfaces())
{
if ($Interface.IsGenericType)
{
#On suppose une seule implémentation de l'interface générique IEnumerable (https://stackoverflow.com/a/7852650)
if ($Interface.GetGenericTypeDefinition() -eq $GenericIEnumerable)
{return $true}
}
}
return $false
}.GetNewClosure()
}
L'usage d'un module simplifierait ce code :
$script:GenericIEnumerable=[Type]'System.Collections.Generic.IEnumerable`1'
Function Test-GenericIEnumerable{
#La variable $InputObject implémente-t-elle l'interface générique IEnumerable ?
param(
[ValidateNotNull()]
$InputObject
)
foreach ($Interface in $InputObject.GetType().GetInterfaces())
{
if ($Interface.IsGenericType)
{
#On suppose une seule implémentation de l'interface générique IEnumerable (https://stackoverflow.com/a/7852650)
if ($Interface.GetGenericTypeDefinition() -eq $GenericIEnumerable)
{return $true}
}
}
return $false
}
Quelques exemples avec les types les plus courant :
[void][Reflection.Assembly]::LoadWithPartialName("System.Data.DataSetExtensions");
$Dt = New-Object System.Data.DataTable
[void]$Dt.Columns.Add( 'C1')
[void]$Dt.Columns.Add( 'C2')
[void]$Dt.Rows.Add( '1','2')
[void]$Dt.Rows.Add( 'Y','Z')
$Dt.Rows -is [System.Collections.IEnumerable]
Test-GenericIEnumerable $Dt.Rows
$A = New-Object System.Collections.ArrayList
$A.Addrange((1..5))
$A -is [System.Collections.IEnumerable]
Test-GenericIEnumerable $A
$H=@{'A'=1;'B'=2}
$H -is [System.Collections.IEnumerable]
Test-GenericIEnumerable $H
#----
$T=1..5
$T -is [System.Collections.IEnumerable]
Test-GenericIEnumerable $T
$SL = new-object 'system.collections.Generic.SortedList[String,Int]'
$SL.Add("Un", 1)
$SL.Add("Deux", 2)
$SL.Add("Trois", 3)
$SL -is [System.Collections.IEnumerable]
Test-GenericIEnumerable $SL
Tutoriels PowerShell
Connexion ou Créer un compte pour participer à la conversation.
- Laurent Dardenne
- Auteur du sujet
- Hors Ligne
- Modérateur
Réduire
Plus d'informations
- Messages : 6302
- Remerciements reçus 68
il y a 3 ans 5 mois #30842
par Laurent Dardenne
Tutoriels PowerShell
Réponse de Laurent Dardenne sur le sujet Re:[Astuce]Cmt savoir si 1 objet est une collection ?
Un complément, la fonction 'Test-GenericIEnumerable' recherche à partir d'un objet, mais pas à partir d'un type qui n'implémente pas d'interface.
Pour tester un type on procédera ainsi :On recherche toutes les méthodes d'extension générique renvoyant un IEnumerable`1 (opérateurs LINQ)
Pour tester un type on procédera ainsi :
Import-Module ExtensionMethod
#recherche les méthodes d'extension LINQ génériques ou pas
$t=[Linq.Enumerable].Assembly.ExportedTypes|Find-ExtensionMethod
#On recherche les méthodes d'extension 'Where'
$l=$t|? {$_.IsGenericMethod -and $_.name -eq 'Where'}
#Ici l'élément 2 est la méthode Where envoyant un IEnumerable`1
"$($l[2])"
#System.Collections.Generic.IEnumerable`1[TSource] Where[TSource](System.Collections.Generic.IEnumerable`1[TSource], System.Func`2[TSource,System.Boolean])
#Teste le type et pas l'objet Method
$l[2].ReturnType.GetGenericTypeDefinition() -eq $GenericIEnumerable
#True
$Methods=Foreach ($Method in $t)
{
$ReturnType=$Method.ReturnType
if ($Method.IsGenericMethod -and $ReturnType.IsGenericType -and $ReturnType.GetGenericTypeDefinition() -eq $GenericIEnumerable)
{Write-Output $Method}
}
$Groups=$Methods|Group-Object -Property Name
$Groups[0].Group.foreach({$_.tostring()})
#System.Collections.Generic.IEnumerable`1[TSource] Where[TSource](System.Collections.Generic.IEnumerable`1[TSource], System.Func`2[TSource,System.Boolean])
#System.Collections.Generic.IEnumerable`1[TSource] Where[TSource](System.Collections.Generic.IEnumerable`1[TSource], System.Func`3[TSource,System.Int32,System.Boolean])
$Groups
Tutoriels PowerShell
Connexion ou Créer un compte pour participer à la conversation.
Temps de génération de la page : 0.116 secondes
- Vous êtes ici :
- Accueil
- forum
- PowerShell
- Contributions à la communauté
- [Astuce]Cmt savoir si 1 objet est une collection ?