Нет универсального метода ThenBy - PullRequest
2 голосов
/ 21 марта 2019

Я пытаюсь добавить метод ThenById(), который будет запущен после вызова OrderBy() на IOrderedQueryable:

public static IOrderedQueryable<TEntity> ThenById<TEntity>(this IQueryable<TEntity> source)
{
    if (source == null)
    {
        throw new ArgumentNullException(nameof(source));
    }

    var command = "ThenBy";
    var thenByProperty = "Id";
    var type = typeof(TEntity);

    if (type.GetProperty(thenByProperty) == null)
    {
        throw new MissingFieldException(nameof(thenByProperty));
    }

    var param = Expression.Parameter(type, "p");

    var property = type.GetProperty(thenByProperty, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);

    var propertyAccess = Expression.MakeMemberAccess(param, property);
    var orderByExpression = Expression.Lambda(propertyAccess, param);

    var resultExpression = Expression.Call(
        typeof(IOrderedQueryable),
        command,
        new Type[] { type, property.PropertyType },
        source.Expression,
        Expression.Quote(orderByExpression));
    return (IOrderedQueryable<TEntity>)source.Provider.CreateQuery<TEntity>(resultExpression);
}

Я получаю следующее сообщение об ошибке:

Нет универсального метода «ThenBy» для типа «System.Linq.IOrderedQueryable», совместимого с предоставленными аргументами и аргументами типа. Аргументы типа не должны предоставляться, если метод не является универсальным.

1 Ответ

3 голосов
/ 21 марта 2019

Метод расширения ThenBy относится к классу System.Linq.Queryable, а не к IOrderedQueryable. Вам просто нужно заменить это в своем коде:

public static IOrderedQueryable<TEntity> ThenById<TEntity>(
    this IOrderedQueryable<TEntity> source)
{
    //snip

    var resultExpression = Expression.Call(
        typeof(System.Linq.Queryable),
        command,
        new Type[] { type, property.PropertyType },
        source.Expression,
        Expression.Quote(orderByExpression));
    return (IOrderedQueryable<TEntity>)source.Provider.CreateQuery<TEntity>(resultExpression);
}

Обратите внимание, что метод должен расширяться IOrderedQueryable, а не только IQueryable.

Однако, это завершится с ошибкой во время выполнения, если TEntity не имеет свойства Id. Я бы предпочел дать всем объектам со свойством Id интерфейс и использовать здесь общее ограничение. Таким образом вы полностью избегаете выражений и получаете безопасность времени компиляции. Например:

public interface IHasId
{
    int Id { get; set; }
}

public class SomeEntity : IHasId
{
    public int Id { get; set; }
    public string Name { get; set; }
    //etc
}

Что упрощает ваш метод расширения:

public static IOrderedQueryable<TEntity> ThenById<TEntity>(
    this IOrderedQueryable<TEntity> source)
        where TEntity : IHasId
{
    return source.ThenBy(e => e.Id);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...