2010-08-26 15 views
1

J'ont mis en œuvre des types de fortune en ajoutant dynamiquement des méthodes pour PSObjectsPouvez-vous implémenter un PSObject créé dynamiquement de sorte que l'égalité et la comparaison fonctionnent?

Je veux être en mesure de comparer deux instances de mes objets en utilisant les opérateurs « eq » « -lt » et « -gt » (Je suppose que cela J'aurais besoin de mettre en œuvre des interfaces comme IComparible et IEquatible)

Est-ce que ce genre de chose est possible? (Je ne pense peut-être pas que ces choses arrivent généralement au niveau du type et mes "types" de fortune sont tous du même type)

Sinon, y a-t-il autre chose que je puisse faire (autre que l'utilisation de C#)?

Répondre

4

Je ne pense pas que vous puissiez coller sur les interfaces du psobject que vous créez. Cependant, vous pouvez créer votre type dans une classe C# qui implémente les interfaces appropriées et remplace les méthodes appropriées. Vous pouvez même définir ce type dans une chaîne ici et utiliser Add-Type pour le compiler et le charger dans PowerShell. Ensuite, vous venez de créer ce type à la place de psobject. Il devrait avoir toutes les propriétés pertinentes qui vous intéressent ainsi que la possibilité de faire des comparaisons/égalité. Par mon commentaire, voici comment faire cela dans votre script avec un minimum de maux de tête avant d'exécuter, c'est-à-dire que vous avez seulement besoin de changer la variable typename chaque fois que vous changez le code C#.

$foo = "Foo" 

$src = @" 
using System; 
public class $foo : IComparable { 
    public string Name {get; set;} 
    public int Age {get; set;} 
    public int CompareTo(object obj) 
    { 
     $foo other = obj as $foo; 
     if (other == null) 
      throw new ArgumentException("arg must be type $foo or not null"); 
     return Age.CompareTo(other.Age); 
    } 

    public override bool Equals(object obj) 
    { 
     if (obj == null) return false; 
     if (Object.ReferenceEquals(this, obj)) return true; 

     $foo other = obj as $foo; 
     if (other == null) 
      throw new ArgumentException("arg must be type $foo or not null"); 
     return Age.Equals(other.Age) && Name.Equals(other.Name);  
    } 

    public override int GetHashCode() 
    { 
     return Age.GetHashCode()^Name.GetHashCode(); 
    } 

    public override string ToString() 
    { 
     return String.Format("Name: {0}, age: {1}", Name, Age); 
    } 
} 
"@ 

if (![Type]::GetType($foo)) 
{ 
    Add-Type -TypeDefinition $src -Language CSharpVersion3 
} 

$foo1 = New-Object $foo 
$foo1.Age = 47 
$foo1.Name = 'Keith' 
$foo1 


$foo2 = New-Object $foo 
$foo2.Age = 45 
$foo2.Name = 'John' 
$foo2 

$foo2 -gt $foo1 
+0

Comme je l'ai mentionné dans la question, je cherchais un moyen de le faire sans utiliser C# et Add-Type. Ma raison est que je ne voulais pas que mon script soit facilement débogable à partir de Powershell et je veux être capable de faire des changements sans avoir à redémarrer ma session Powershell – Willbill

+0

Désolé, doit avoir raté la partie de ne pas utiliser Add-Type. Une façon de contourner ce problème est de paramétrer le nom du type et de le changer entre les exécutions lorsque le C# a changé. Sinon, vous pouvez tester si le type existe déjà et ignorer l'appel Add-Type. –

+0

Je n'aime vraiment pas l'inflexibilité de la façon dont C# est intégré mais une bonne réponse quand même – Willbill