I have been using built-in "CaseInsensitiveComparer" which implements
IComparer, but I would like to pass in my own comparison
I don't think it's possible with PS because you can't create new types
(aka classes) with powershell at this time. You can of course create new
pseudo types (see PSCustomObject) but AFAICS you can't implement specfic
interfaces. What might be possible is to create a generic Comparer in C#
or whatever .NET language that actually does not compare but calls a
delegate via event mechanism. So theroetically it should then be
possible to write something like this:
$cmp=new-object "MyComparer"
$cmp.CompareCallback={Perform your comparison here}
arrayListObject.Sort( $cmp)
But I haven't tried this myself.
cu
Max
$a=ls
$cmp=new-Comparer {$args[0].Name.CompareTo($args[1].Name)}
[Array]::Sort($a, $cmp)
Please note however that in this case it's much easier to use the
sort-object:
ls | Sort Name
However, in case you have some very, very special needs, something like
a New-Comparer CmdLet might become handy. So here's the (not very well
tested) code:
//
namespace YourNamespace.Commands
{
using System;
using System.Management.Automation;
using System.Collections.ObjectModel;
using Microsoft.PowerShell.Commands;
using System.Collections.Generic;
using System.Collections;
[Cmdlet(VerbsCommon.New, "Comparer")]
public class NewComparerCommand:PSCmdlet
{
ScriptBlock m_CompareScript;
[Parameter(Mandatory=true, Position=0)]
public ScriptBlock CompareScript
{
get { return m_CompareScript; }
set { m_CompareScript=value; }
}
protected override void BeginProcessing()
{
WriteVerbose(String.Format("CompareScript: {0}",
CompareScript.ToString()));
WriteObject(new CustomComparer(CompareScript));
}
}
public sealed class CustomComparer:IComparer
{
ScriptBlock m_CompareScript;
public CustomComparer(ScriptBlock compareScript)
{
if(null==compareScript)
throw new ArgumentNullException("compareScript");
m_CompareScript=compareScript;
}
public ScriptBlock CompareScript
{
get { return m_CompareScript; }
set
{
if(null==value)
throw new ArgumentNullException("CompareScript");
m_CompareScript=value;
}
}
#region IComparer Members
public int Compare(object x, object y)
{
Collection<PSObject> res=CompareScript.Invoke(x,y);
return (int)(res[0].BaseObject);
}
#endregion
}
}
//eof
hth
Max
I guess I would have to look into your suggestion and using reflection
to create a custom type on the fly ~~~ ;)
Thank you for providing the cmdlet source that I can play around with.
I did create a simple snapin and ...
> $a=ls
> $cmp=new-Comparer {$args[0].Name.CompareTo($args[1].Name)}
> [Array]::Sort($a, $cmp)
Ok, with the NewComparerCommand cmdlet,
$a = @("c", "b", "x", "z", "a", "e")
$cmp = new-comparer { $args[0].CompareTo($args[1]) }
[System.Array]::Sort($a, $cmp)
$a
Now displays:
a
b
c
e
x
z
And if i just simply changes the arg order,
>From "$args[0].CompareTo($args[1])" to "$args[1].CompareTo($args[0])"
$a is sorted as followed
z
x
e
c
b
a
It is working just as I expected and how I wanted the cmdlet to work ;)
Thanks~
> Please note however that in this case it's much easier to use the
> sort-object:
>
> ls | Sort Name
:-) Beh~ But it's not as fun as creating a cmdlet though ;)