Home >Backend Development >C++ >Can Dynamic LINQ Ordering Be Applied to `IEnumerable` as Well as `IQueryable`?

Can Dynamic LINQ Ordering Be Applied to `IEnumerable` as Well as `IQueryable`?

Patricia Arquette
Patricia ArquetteOriginal
2025-02-02 22:41:10391browse

Can Dynamic LINQ Ordering Be Applied to `IEnumerable` as Well as `IQueryable`?

Dynamic LINQ OrderBy on IEnumerable / IQueryable

In dynamic LINQ, you can use a SQL-like string (e.g., "OrderBy("Name, Age DESC")") to order the results. However, the examples available so far only work with IQueryable. This raises the question: is it possible to extend this functionality to IEnumerable?

Extending to IEnumerable

To achieve this, you can create wrapper methods that utilize AsQueryable. However, the code below serves as the core expression logic required:

public static IOrderedQueryable<T> OrderBy<T>(
    this IQueryable<T> source,
    string property)
{
    return ApplyOrder<T>(source, property, "OrderBy");
}

public static IOrderedQueryable<T> OrderByDescending<T>(
    this IQueryable<T> source,
    string property)
{
    return ApplyOrder<T>(source, property, "OrderByDescending");
}

public static IOrderedQueryable<T> ThenBy<T>(
    this IOrderedQueryable<T> source,
    string property)
{
    return ApplyOrder<T>(source, property, "ThenBy");
}

public static IOrderedQueryable<T> ThenByDescending<T>(
    this IOrderedQueryable<T> source,
    string property)
{
    return ApplyOrder<T>(source, property, "ThenByDescending");
}

static IOrderedQueryable<T> ApplyOrder<T>(
    IQueryable<T> source,
    string property,
    string methodName)
{
    string[] props = property.Split('.');
    Type type = typeof(T);
    ParameterExpression arg = Expression.Parameter(type, "x");
    Expression expr = arg;
    foreach (string prop in props)
    {
        // use reflection to mirror LINQ
        PropertyInfo pi = type.GetProperty(prop);
        expr = Expression.Property(expr, pi);
        type = pi.PropertyType;
    }
    Type delegateType = typeof(Func<,>).MakeGenericType(typeof(T), type);
    LambdaExpression lambda = Expression.Lambda(delegateType, expr, arg);

    object result = typeof(Queryable).GetMethods().Single(
            method => method.Name == methodName
                    && method.IsGenericMethodDefinition
                    && method.GetGenericArguments().Length == 2
                    && method.GetParameters().Length == 2)
            .MakeGenericMethod(typeof(T), type)
            .Invoke(null, new object[] { source, lambda });
    return (IOrderedQueryable<T>)result;
}

Incorporating Dynamic Functionality

For dynamic LINQ-to-Objects scenarios, you can leverage System.Dynamic for more flexibility.

using Microsoft.CSharp.RuntimeBinder;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;

/// <summary>
/// OrderBy for dynamic IEnumerable operations
/// </summary>
public static IOrderedEnumerable<dynamic> OrderBy(
    this IEnumerable<dynamic> source,
    string property)
{
    return Enumerable.OrderBy<dynamic, object>(
        source,
        AccessorCache.GetAccessor(property),
        Comparer<object>.Default);
}

/// <summary>
/// OrderByDescending for dynamic IEnumerable operations
/// </summary>
public static IOrderedEnumerable<dynamic> OrderByDescending(
    this IEnumerable<dynamic> source,
    string property)
{
    return Enumerable.OrderByDescending<dynamic, object>(
        source,
        AccessorCache.GetAccessor(property),
        Comparer<object>.Default);
}

/// <summary>
/// ThenBy for dynamic IEnumerable operations
/// </summary>
public static IOrderedEnumerable<dynamic> ThenBy(
    this IOrderedEnumerable<dynamic> source,
    string property)
{
    return Enumerable.ThenBy<dynamic, object>(
        source,
        AccessorCache.GetAccessor(property),
        Comparer<object>.Default);
}

/// <summary>
/// ThenByDescending for dynamic IEnumerable operations
/// </summary>
public static IOrderedEnumerable<dynamic> ThenByDescending(
    this IOrderedEnumerable<dynamic> source,
    string property)
{
    return Enumerable.ThenByDescending<dynamic, object>(
        source,
        AccessorCache.GetAccessor(property),
        Comparer<object>.Default);
}

The above is the detailed content of Can Dynamic LINQ Ordering Be Applied to `IEnumerable` as Well as `IQueryable`?. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn