#region License
/*
* Copyright 2002-2005 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#endregion
using System;
using System.Collections;
using Spring.Util;
namespace Spring.Expressions.Processors{
/// <summary>
/// Implementation of the 'order by' processor.
/// </summary>
/// <author>Aleksandar Seovic</author>
/// <author>Erich Eichinger</author>
public class OrderByProcessor : ICollectionProcessor
{
#region Comparer Helper Implementations
private class SimpleExpressionComparer : IComparer
{
private readonly IExpression _expression;
public SimpleExpressionComparer(IExpression expression)
{
_expression = expression;
}
public int Compare(object x, object y)
{
x = _expression.GetValue(x);
y = _expression.GetValue(y);
if (x==y) return 0;
if (x != null) return ((IComparable) x).CompareTo(y);
return ((IComparable)y).CompareTo(x)*-1;
}
}
private class LambdaComparer : IComparer
{
private readonly Hashtable _variables;
private readonly IExpression _fn;
public LambdaComparer(LambdaExpressionNode lambdaExpression)
{
FunctionNode functionNode = new FunctionNode();
functionNode.Text = "compare";
VariableNode x = new VariableNode();
x.Text = "x";
VariableNode y = new VariableNode();
y.Text = "y";
functionNode.addChild(x);
functionNode.addChild(y);
_fn = functionNode;
_variables = new Hashtable();
_variables.Add( "compare", lambdaExpression );
}
public int Compare(object x, object y)
{
_variables["x"] = x;
_variables["y"] = y;
return (int) _fn.GetValue(null, _variables);
}
}
private class DelegateComparer : IComparer
{
private readonly Delegate _fnCompare;
public DelegateComparer(Delegate fnCompare)
{
_fnCompare = fnCompare;
}
public int Compare(object x, object y)
{
return (int)_fnCompare.DynamicInvoke(new object[] { x, y });
}
}
#endregion
/// <summary>
/// Sorts the source collection using custom sort criteria.
/// </summary>
/// <remarks>
/// Please note that your compare function needs to take care about
/// proper conversion of types to be comparable!
/// </remarks>
/// <param name="source">
/// The source collection to sort.
/// </param>
/// <param name="args">
/// Sort criteria to use.
/// </param>
/// <returns>
/// A sorted array containing collection elements.
/// </returns>
public object Process(ICollection source, object[] args)
{
if (source == null || source.Count == 0)
{
return source;
}
if (args == null || args.Length != 1)
{
throw new ArgumentException("compare expression is a required argument for orderBy");
}
object arg = args[0];
IComparer comparer = null;
if (arg is string)
{
IExpression expCompare = Expression.Parse((string) arg);
comparer = new SimpleExpressionComparer(expCompare);
}
else if (arg is IComparer)
{
comparer = (IComparer) arg;
}
else if (arg is LambdaExpressionNode)
{
LambdaExpressionNode fnCompare = (LambdaExpressionNode)arg;
if (fnCompare.ArgumentNames.Length != 2)
{
throw new ArgumentException("compare function must accept 2 arguments");
}
comparer = new LambdaComparer(fnCompare);
}
else if (arg is Delegate)
{
comparer = new DelegateComparer((Delegate) arg);
}
AssertUtils.ArgumentNotNull(comparer, "comparer", "orderBy(comparer) argument 'comparer' does not evaluate to a supported type");
ArrayList list = new ArrayList(source);
list.Sort(comparer);
return list;
}
}
}
|