Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>Bummer! I must learn how to read the specifications from end to end :-(</p> <p>However, now that I have spent too much time fooling around rather than working, I will post my results anyway hoping this will inspire people to read, think, understand (important) and then act. Or how to be too clever with generics, lambdas and funny Linq stuff.</p> <blockquote> <p>A neat trick I discovered during this exercise, are those private inner classes which derives from <code>Dictionary</code>. Their whole purpose is to remove all those angle brackets in order to improve readability.</p> </blockquote> <p>Oh, almost forgot the code:</p> <p><strong>UPDATE: Made the code generic and to use <code>IQueryable</code> instead of <code>IEnumerable</code></strong></p> <pre><code>using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using NUnit.Framework; using NUnit.Framework.SyntaxHelpers; namespace StackOverflow.StrongTypedLinqSort { [TestFixture] public class SpecifyUserDefinedSorting { private Sorter&lt;Movie&gt; sorter; [SetUp] public void Setup() { var unsorted = from m in Movies select m; sorter = new Sorter&lt;Movie&gt;(unsorted); sorter.Define("NAME", m1 =&gt; m1.Name); sorter.Define("YEAR", m2 =&gt; m2.Year); } [Test] public void SortByNameThenYear() { var sorted = sorter.SortBy("NAME", "YEAR"); var movies = sorted.ToArray(); Assert.That(movies[0].Name, Is.EqualTo("A")); Assert.That(movies[0].Year, Is.EqualTo(2000)); Assert.That(movies[1].Year, Is.EqualTo(2001)); Assert.That(movies[2].Name, Is.EqualTo("B")); } [Test] public void SortByYearThenName() { var sorted = sorter.SortBy("YEAR", "NAME"); var movies = sorted.ToArray(); Assert.That(movies[0].Name, Is.EqualTo("B")); Assert.That(movies[1].Year, Is.EqualTo(2000)); } [Test] public void SortByYearOnly() { var sorted = sorter.SortBy("YEAR"); var movies = sorted.ToArray(); Assert.That(movies[0].Name, Is.EqualTo("B")); } private static IQueryable&lt;Movie&gt; Movies { get { return CreateMovies().AsQueryable(); } } private static IEnumerable&lt;Movie&gt; CreateMovies() { yield return new Movie {Name = "B", Year = 1990}; yield return new Movie {Name = "A", Year = 2001}; yield return new Movie {Name = "A", Year = 2000}; } } internal class Sorter&lt;E&gt; { public Sorter(IQueryable&lt;E&gt; unsorted) { this.unsorted = unsorted; } public void Define&lt;P&gt;(string name, Expression&lt;Func&lt;E, P&gt;&gt; selector) { firstPasses.Add(name, s =&gt; s.OrderBy(selector)); nextPasses.Add(name, s =&gt; s.ThenBy(selector)); } public IOrderedQueryable&lt;E&gt; SortBy(params string[] names) { IOrderedQueryable&lt;E&gt; result = null; foreach (var name in names) { result = result == null ? SortFirst(name, unsorted) : SortNext(name, result); } return result; } private IOrderedQueryable&lt;E&gt; SortFirst(string name, IQueryable&lt;E&gt; source) { return firstPasses[name].Invoke(source); } private IOrderedQueryable&lt;E&gt; SortNext(string name, IOrderedQueryable&lt;E&gt; source) { return nextPasses[name].Invoke(source); } private readonly IQueryable&lt;E&gt; unsorted; private readonly FirstPasses firstPasses = new FirstPasses(); private readonly NextPasses nextPasses = new NextPasses(); private class FirstPasses : Dictionary&lt;string, Func&lt;IQueryable&lt;E&gt;, IOrderedQueryable&lt;E&gt;&gt;&gt; {} private class NextPasses : Dictionary&lt;string, Func&lt;IOrderedQueryable&lt;E&gt;, IOrderedQueryable&lt;E&gt;&gt;&gt; {} } internal class Movie { public string Name { get; set; } public int Year { get; set; } } } </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload