|
//------------------------------------------------------------------------------
// <copyright file="EnumerableDataTable.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
// <owner current="true" primary="true">Microsoft</owner>
// <owner current="true" primary="false">Microsoft</owner>
//------------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Collections;
using System.Text;
using System.Data;
using System.Linq;
using System.Diagnostics;
namespace System.Data
{
/// <summary>
/// This class represents a combined sort expression build using mutiple sort expressions.
/// </summary>
/// <typeparam name="T"></typeparam>
internal class SortExpressionBuilder<T> : IComparer<List<object>>
{
/**
* This class ensures multiple orderby/thenbys are handled correctly. Its semantics is as follows:
*
* Query 1:
* orderby a
* thenby b
* orderby c
* orderby d
* thenby e
*
* is equivalent to:
*
* Query 2:
* orderby d
* thenby e
* thenby c
* thenby a
* thenby b
*
**/
//Selectors and comparers are mapped using the index in the list.
//E.g: _comparers[i] is used with _selectors[i]
LinkedList<Func<T, object>> _selectors = new LinkedList<Func<T, object>>();
LinkedList<Comparison<object>> _comparers = new LinkedList<Comparison<object>>();
LinkedListNode<Func<T, object>> _currentSelector = null;
LinkedListNode<Comparison<object>> _currentComparer = null;
/// <summary>
/// Adds a sorting selector/comparer in the correct order
/// </summary>
internal void Add(Func<T, object> keySelector, Comparison<object> compare, bool isOrderBy)
{
Debug.Assert(keySelector != null);
Debug.Assert(compare != null);
//Inputs are assumed to be valid. The burden for ensuring it is on the caller.
if (isOrderBy)
{
_currentSelector = _selectors.AddFirst(keySelector);
_currentComparer = _comparers.AddFirst(compare);
}
else
{
//ThenBy can only be called after OrderBy
Debug.Assert(_currentSelector != null);
Debug.Assert(_currentComparer != null);
_currentSelector = _selectors.AddAfter(_currentSelector, keySelector);
_currentComparer = _comparers.AddAfter(_currentComparer, compare);
}
}
/// <summary>
/// Represents a Combined selector of all selectors added thusfar.
/// </summary>
/// <returns>List of 'objects returned by each selector'. This list is the combined-selector</returns>
public List<object> Select(T row)
{
List<object> result = new List<object>();
foreach (Func<T, object> selector in _selectors)
{
result.Add(selector(row));
}
return result;
}
/// <summary>
/// Represents a Comparer (of IComparer) that compares two combined-selectors using
/// provided comparers for each individual selector.
/// Note: Comparison is done in the order it was Added.
/// </summary>
/// <returns>Comparison result of the combined Sort comparer expression</returns>
public int Compare(List<object> a, List<object> b)
{
Debug.Assert(a.Count == Count);
int i = 0;
foreach (Comparison<object> compare in _comparers)
{
int result = compare(a[i], b[i]);
if (result != 0)
{
return result;
}
i++;
}
return 0;
}
internal int Count
{
get
{
Debug.Assert(_selectors.Count == _comparers.Count); //weak now that we have two dimensions
return _selectors.Count;
}
}
/// <summary>
/// Clones the SortexpressionBuilder and returns a new object
/// that points to same comparer and selectors (in the same order).
/// </summary>
/// <returns></returns>
internal SortExpressionBuilder<T> Clone()
{
SortExpressionBuilder<T> builder = new SortExpressionBuilder<T>();
foreach (Func<T, object> selector in _selectors)
{
if (selector == _currentSelector.Value)
{
builder._currentSelector = builder._selectors.AddLast(selector);
}
else
{
builder._selectors.AddLast(selector);
}
}
foreach (Comparison<object> comparer in _comparers)
{
if (comparer == _currentComparer.Value)
{
builder._currentComparer = builder._comparers.AddLast(comparer);
}
else
{
builder._comparers.AddLast(comparer);
}
}
return builder;
}
/// <summary>
/// Clones the SortExpressinBuilder and casts to type TResult.
/// </summary>
internal SortExpressionBuilder<TResult> CloneCast<TResult>()
{
SortExpressionBuilder<TResult> builder = new SortExpressionBuilder<TResult>();
foreach (Func<T, object> selector in _selectors)
{
if (selector == _currentSelector.Value)
{
builder._currentSelector = builder._selectors.AddLast(r => selector((T)(object)r));
}
else
{
builder._selectors.AddLast(r => selector((T)(object)r));
}
}
foreach (Comparison<object> comparer in _comparers)
{
if (comparer == _currentComparer.Value)
{
builder._currentComparer = builder._comparers.AddLast(comparer);
}
else
{
builder._comparers.AddLast(comparer);
}
}
return builder;
}
} //end SortExpressionBuilder<T>
}
|