210 lines
6.5 KiB
C#
210 lines
6.5 KiB
C#
//------------------------------------------------------------------------------
|
|
// <copyright file="EnumerableDataTable.cs" company="Microsoft">
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
// </copyright>
|
|
// <owner current="true" primary="true">[....]</owner>
|
|
// <owner current="true" primary="false">[....]</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>
|
|
}
|