gpt4 book ai didi

c# - .ThenBy 是如何实现的?

转载 作者:太空狗 更新时间:2023-10-29 18:32:01 25 4
gpt4 key购买 nike

灵感来自 this我做了这个:

ISortable

public interface ISortable<T>
{
IPageable<T> OrderBy<U>(Expression<Func<T, U>> orderBy);
IPageable<T> OrderByDescending<U>(Expression<Func<T, U>> orderBy);
}

IPageable

public interface IPageable<T> : ISortable<T>, IEnumerable<T>
{
IPageable<T> Page(int pageNumber, int pageSize);
List<T> ToList();
int TotalPages { get; }
int TotalItemCount { get; }
int PageNumber { get; }
int? PageSize { get; }
}

可分页

public class Pageable<T> : IPageable<T>
{
private readonly IQueryable<T> _countQuery;
private IQueryable<T> _sourceQuery;

/// <summary>
/// A pageable result
/// </summary>
/// <param name="sourceQuery">Query which holdes all relevant items.</param>
public Pageable(IQueryable<T> sourceQuery)
{
_sourceQuery = sourceQuery;
_countQuery = sourceQuery;
PageNumber = 1;
}

/// <summary>
/// A pageable result
/// </summary>
/// <param name="sourceQuery">Query which holdes all relevant items.</param>
/// <param name="countQuery">
/// Alternative query optimized for counting.
/// <see cref="countQuery"/> is required to give the same count as <see cref="sourceQuery"/> else paging will break.
/// <remarks>No checks if <see cref="sourceQuery"/> and <see cref="countQuery"/> return the same count are appiled.</remarks>
/// </param>
public Pageable(IQueryable<T> sourceQuery, IQueryable<T> countQuery)
: this (sourceQuery)
{
_countQuery = countQuery;
}

#region Implementation of IEnumerable

/// <summary>
/// Returns an enumerator that iterates through the collection.
/// </summary>
/// <returns>
/// A <see cref="T:System.Collections.Generic.IEnumerator`1"/> that can be used to iterate through the collection.
/// </returns>
/// <filterpriority>1</filterpriority>
public IEnumerator<T> GetEnumerator()
{
return _sourceQuery.GetEnumerator();
}

/// <summary>
/// Returns an enumerator that iterates through a collection.
/// </summary>
/// <returns>
/// An <see cref="T:System.Collections.IEnumerator"/> object that can be used to iterate through the collection.
/// </returns>
/// <filterpriority>2</filterpriority>
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}

#endregion

#region Implementation of ISortable

public IPageable<T> OrderBy<U>(Expression<Func<T, U>> orderBy)
{
_sourceQuery = _sourceQuery.OrderBy(orderBy);
return this;
}

public IPageable<T> OrderByDescending<U>(Expression<Func<T, U>> orderBy)
{
_sourceQuery = _sourceQuery.OrderByDescending(orderBy);
return this;
}

#endregion

#region Implementation of IPageable

public int PageNumber { get; private set; }
public int? PageSize { get; private set; }
public int TotalItemCount
{
get { return _countQuery.Count(); }
}
public int TotalPages
{
get { return (int) (Math.Ceiling((double) TotalItemCount/PageSize ?? 1)); }
}

/// <summary>
/// Chop a query result into pages.
/// </summary>
/// <param name="pageNumber">Page number to fetch. Starting from 1.</param>
/// <param name="pageSize">Items per page.</param>
/// <returns></returns>
public IPageable<T> Page(int pageNumber, int pageSize)
{
PageNumber = pageNumber;
PageSize = pageSize;

_sourceQuery = _sourceQuery
.Skip((pageNumber - 1) * pageSize)
.Take(pageSize);

return this;
}

public List<T> ToList()
{
return _sourceQuery.ToList();
}

#endregion
}

以上作品。巨大的成功! :)

但是,我在实现方法 .ThenBy() 时遇到了问题。问题是 .ThenBy() 应该只有在调用 .OrderBy() 时才可以访问。

我注意到 IQueryable.OrderBy返回一个 IOrderedQueryable,这就是访问 .ThenBy() 的来源。但是为了使我当前的解决方案工作,我需要制作一个 IOrderedPageable 和一个新的 OrderedPagable 来配合它。 OrderedPagable 几乎是 Pageable 的副本,这是非常糟糕的设计。

我非常怀疑 LINQ 是如何做到的。所以我的问题是,他们是怎么做到的?我很好奇:)

我注意到的一件事是几乎所有的 LINQ 方法都是扩展方法,这是“技巧”的一部分 :)?

最佳答案

听起来您的类 OrderedPageable 可能是 Pageable 的子类并且另外实现了 IOrderedPageable 接口(interface)。

继承方法似乎很有意义,因为任何处理 Pageable 的东西都应该能够以相同的方式处理 OrderedPageable


通过稍微更改您的接口(interface)并使用与上述类似的接口(interface)继承方法,您可以使用不可变的可查询类和扩展方法实现您正在寻找的功能。

在我看来,用法更清晰,更符合LINQ。

例子:

query.AsPageable(100).Page(1);
query.AsPageable(100).OrderBy(x => x.Name).ThenBy(x => x.Age).Page(1).ToList();

我还没有对此进行测试,但这个概念应该可行。请注意:

  • 项目总数是根据原始查询计算的(不是任何排序查询)
  • 项目总数是惰性的,只计算一次
  • 根据您的查询提供者,您可能必须公开 IPageableQuerySourceQuery 属性以便在 PageableExtensions 中使用,因为您的查询提供者可能未能成功翻译针对这种新的 PageableQuery 类型的查询。

接口(interface):

public interface IPageableQuery<T> : IQueryable<T>
{
int TotalPages { get; }
int TotalItemCount { get; }

int PageSize { get; }
}

public interface IOrderedPageableQuery<T> : IPageableQuery<T>, IOrderedQueryable<T>
{
}

实现:

public class PageableQuery<T> : IPageableQuery<T>
{
readonly IQueryable<T> _sourceQuery;
readonly Lazy<int> _totalItemCount;

public int TotalPages { get { return (int)Math.Ceiling((double)TotalItemCount / PageSize); } }
public int TotalItemCount { get { return _totalItemCount.Value; } }
public int PageSize { get; private set; }

public PageableQuery(IQueryable<T> sourceQuery, int pageSize)
{
_sourceQuery = sourceQuery;
_totalItemCount = new Lazy<int>(() => _sourceQuery.Count());

PageSize = pageSize;
}

public IEnumerator<T> GetEnumerator() { return _sourceQuery.GetEnumerator();}
IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }

public Expression Expression { get { return _sourceQuery.Expression; } }
public Type ElementType { get { return _sourceQuery.ElementType; } }
public IQueryProvider Provider { get { return _sourceQuery.Provider; } }
}

public class OrderedPageableQuery<T> : IOrderedPageableQuery<T>
{
readonly IPageableQuery<T> _sourcePageableQuery;
readonly IOrderedQueryable<T> _sourceQuery;

public int TotalPages { get { return (int)Math.Ceiling((double)TotalItemCount / PageSize); } }
public int TotalItemCount { get { return _sourcePageableQuery.TotalItemCount; } }
public int PageSize { get { return _sourcePageableQuery.PageSize; } }

public OrderedPageableQuery(IPageableQuery<T> sourcePageableQuery, IOrderedQueryable<T> newSourceQuery)
{
_sourcePageableQuery = sourcePageableQuery;
_sourceQuery = newSourceQuery;
}

public IEnumerator<T> GetEnumerator() { return _sourceQuery.GetEnumerator();}
IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }

public Expression Expression { get { return _sourceQuery.Expression; } }
public Type ElementType { get { return _sourceQuery.ElementType; } }
public IQueryProvider Provider { get { return _sourceQuery.Provider; } }
}

扩展方法:

public static class PageableExtension
{
public static IPageableQuery<T> AsPageable<T>(this IQueryable<T> sourceQuery, int pageSize)
{
return new PageableQuery<T>(sourceQuery, pageSize);
}

public static IOrderedPageableQuery<T> OrderBy<T, U>(this IPageableQuery<T> sourcePageableQuery, Expression<Func<T, U>> orderBy)
{
return new OrderedPageableQuery<T>(sourcePageableQuery, Queryable.OrderBy(sourcePageableQuery, orderBy));
}

public static IOrderedPageableQuery<T> OrderByDescending<T, U>(this IPageableQuery<T> sourcePageableQuery, Expression<Func<T, U>> orderBy)
{
return new OrderedPageableQuery<T>(sourcePageableQuery, Queryable.OrderByDescending(sourcePageableQuery, orderBy));
}

public static IOrderedPageableQuery<T> ThenBy<T, U>(this IOrderedPageableQuery<T> sourcePageableQuery, Expression<Func<T, U>> orderBy)
{
return new OrderedPageableQuery<T>(sourcePageableQuery, Queryable.ThenBy(sourcePageableQuery, orderBy));
}

public static IOrderedPageableQuery<T> ThenByDescending<T, U>(this IOrderedPageableQuery<T> sourcePageableQuery, Expression<Func<T, U>> orderBy)
{
return new OrderedPageableQuery<T>(sourcePageableQuery, Queryable.ThenByDescending(sourcePageableQuery, orderBy));
}

public static IQueryable<T> Page<T>(this IPageableQuery<T> sourceQuery, int pageNumber)
{
return sourceQuery.Skip((pageNumber - 1) * sourceQuery.PageSize)
.Take(sourceQuery.PageSize);
}
}

关于c# - .ThenBy 是如何实现的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18163043/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com