title: How can I dynamically store expressions used for Linq Orderby?
body: <p>I am trying to create a quick class so that I can make writing sorting code for a grid much easier to work with and maintain, and to keep code repetition down.  To do this I came up with the following class:</p>
  
  <pre><code>public class SortConfig&lt;TSource, TRelatedObject&gt; where TSource : class where TRelatedObject : class
  {
      public IList&lt;SortOption&gt; Options { get; protected set; }
      public SortOption DefaultOption { get; set; }
  
      public SortConfig()
      {
          Options = new List&lt;SortOption&gt;();
      }
  
      public void Add(string name, Expression&lt;Func&lt;TSource, object&gt;&gt; sortExpression, TRelatedObject relatedObject, bool isDefault = false)
      {
          var option = new SortOption
          {
              FriendlyName = name,
              SortExpression = sortExpression,
              RelatedObject = relatedObject
          };
  
          Options.Add(option);
  
          if (isDefault)
              DefaultOption = option;
      }
  
      public SortOption GetSortOption(string sortName)
      {
          if (sortName.EndsWith("asc", StringComparison.OrdinalIgnoreCase))
              sortName = sortName.Substring(0, sortName.LastIndexOf("asc", StringComparison.OrdinalIgnoreCase));
          else if (sortName.EndsWith("desc", StringComparison.OrdinalIgnoreCase))
              sortName = sortName.Substring(0, sortName.LastIndexOf("desc", StringComparison.OrdinalIgnoreCase));
  
          sortName = sortName.Trim();
  
          var option = Options.Where(x =&gt; x.FriendlyName.Trim().Equals(sortName, StringComparison.OrdinalIgnoreCase))
                              .FirstOrDefault();
          if (option == null)
          {
              if (DefaultOption == null)
                  throw new InvalidOperationException(
                      string.Format("No configuration found for sort type of '{0}', and no default sort configuration exists", sortName));
  
              option = DefaultOption;
          }
  
          return option;
      }
  
      public class SortOption
      {
          public string FriendlyName { get; set; }
          public Expression&lt;Func&lt;TSource, object&gt;&gt; SortExpression { get; set; }
          public TRelatedObject RelatedObject { get; set; }
      }
  }
  </code></pre>
  
  <p>The idea is that you create a quick configuration of the different sort options, what OrderBy expression is used for that, and optionally an object that is related to that sort option.  This allows my code to look like:</p>
  
  <pre><code>    protected void InitSortConfig()
      {
          _sortConfig = new SortConfig&lt;xosPodOptimizedSearch, HtmlAnchor&gt;();
          _sortConfig.Add("name", (x =&gt; x.LastName), lnkSortName, true);
          _sortConfig.Add("team", (x =&gt; x.SchoolName), lnkSortTeam);
          _sortConfig.Add("rate", (x =&gt; x.XosRating), lnkSortRate);
          _sortConfig.Add("pos", (x =&gt; x.ProjectedPositions), null);
          _sortConfig.Add("height", (x =&gt; x.Height), lnkSortHeight);
          _sortConfig.Add("weight", (x =&gt; x.Weight), lnkSortWeight);
          _sortConfig.Add("city", (x =&gt; x.SchoolCity), lnkSortCity);
          _sortConfig.Add("state", (x =&gt; x.SchoolState), lnkSortState);
      }
  </code></pre>
  
  <p>and then I can sort by just doing</p>
  
  <pre><code>        // Get desired sorting configuration
          InitSortConfig();
          var sortOption = _sortConfig.GetSortOption(sort);
          bool isDescendingSort = sort.EndsWith("desc", StringComparison.OrdinalIgnoreCase);
  
          // Setup columns
          InitSortLinks();
          if (sortOption.RelatedObject != null)
          {
              // Make modifications to html anchor
          }
  
          // Form query
          var query = PodDataContext.xosPodOptimizedSearches.AsQueryable();
  
          if (isDescendingSort)
              query = query.OrderByDescending(sortOption.SortExpression);
          else
              query = query.OrderBy(sortOption.SortExpression);
  </code></pre>
  
  <p>This works great when the sorted variable is a string, but when it is not a string I get the following exception: <code>Cannot order by type 'System.Object'.</code></p>
  
  <p>I'm assuming this is because I am storing the expression as <code>Expression&lt;Func&lt;TSource, object&gt;&gt;</code> and not being more specific about that 2nd generic.  I don't understand how I can keep all my different sort options (even for non-string properties) in one class.  </p>
  
  <p>I guess one of the issues is that the <code>Linq.OrderBy()</code> clause takes <code>Expression&lt;Func&lt;TSource, TKey&gt;&gt;</code> as it's parameter, but I am not wrapping my head around how <code>Linq.OrderBy()</code> is able to infer what <code>TKey</code> should be, and therefore I cannot understand how to take advantage of that inference to store these expressions with the proper <code>TKey</code>.</p>
  
  <p>Any ideas?</p>