1.Extensions介紹
擴充方法使你能夠向現有類型“添加”方法,而無需建立新的派生類型、重新編譯或以其他方式修改原始類型。 擴充方法是一種特殊的靜态方法,但可以像擴充類型上的執行個體方法一樣進行調用。 對于用 C#、F# 和 Visual Basic 編寫的用戶端代碼,調用擴充方法與調用在類型中實際定義的方法沒有明顯差別。
詳細見官方文檔:
擴充方法(C# 程式設計指南)2.文法介紹
* 需要寫在一個靜态類中
* 必須是一個靜态方法
* 通過第一個參數和this關鍵字指定擴充的目标類型
* 不同類型的擴充方法不一定要寫在同一個類中
3.事例介紹
在ABP架構原中會發現在很多地方帶有Extensions的類,其主要作用是在不改變原有接口或類的基礎上擴充自定義的方法,進而友善使用,如QueryableExtensions類是對IQueryable進行擴充,裡面添加了分頁PageBy、條件判斷WhereIf方法,代碼如下:
using System;
using System.Linq;
using System.Linq.Expressions;
using Abp.Application.Services.Dto;
namespace Abp.Linq.Extensions
{
/// <summary>
/// Some useful extension methods for <see cref="IQueryable{T}"/>.
/// </summary>
public static class QueryableExtensions
{
/// <summary>
/// Used for paging. Can be used as an alternative to Skip(...).Take(...) chaining.
/// </summary>
public static IQueryable<T> PageBy<T>(this IQueryable<T> query, int skipCount, int maxResultCount)
{
if (query == null)
{
throw new ArgumentNullException("query");
}
return query.Skip(skipCount).Take(maxResultCount);
}
/// <summary>
/// Used for paging with an <see cref="IPagedResultRequest"/> object.
/// </summary>
/// <param name="query">Queryable to apply paging</param>
/// <param name="pagedResultRequest">An object implements <see cref="IPagedResultRequest"/> interface</param>
public static IQueryable<T> PageBy<T>(this IQueryable<T> query, IPagedResultRequest pagedResultRequest)
{
return query.PageBy(pagedResultRequest.SkipCount, pagedResultRequest.MaxResultCount);
}
/// <summary>
/// Filters a <see cref="IQueryable{T}"/> by given predicate if given condition is true.
/// </summary>
/// <param name="query">Queryable to apply filtering</param>
/// <param name="condition">A boolean value</param>
/// <param name="predicate">Predicate to filter the query</param>
/// <returns>Filtered or not filtered query based on <paramref name="condition"/></returns>
public static IQueryable<T> WhereIf<T>(this IQueryable<T> query, bool condition, Expression<Func<T, bool>> predicate)
{
return condition
? query.Where(predicate)
: query;
}
/// <summary>
/// Filters a <see cref="IQueryable{T}"/> by given predicate if given condition is true.
/// </summary>
/// <param name="query">Queryable to apply filtering</param>
/// <param name="condition">A boolean value</param>
/// <param name="predicate">Predicate to filter the query</param>
/// <returns>Filtered or not filtered query based on <paramref name="condition"/></returns>
public static IQueryable<T> WhereIf<T>(this IQueryable<T> query, bool condition, Expression<Func<T, int, bool>> predicate)
{
return condition
? query.Where(predicate)
: query;
}
}
}
如上所述,對IQueryable擴充後,可以像調用原生方法一樣,使上層的調用感受不到差別和不用做過多的操作,友善對第三方的庫進行擴充,進而增加自定義需求,有效提高項目的開發效率。調用代碼如下:
public async Task<PagedResultDto<ProjectListDto>> GetProjects(GetProjectsInput input)
{
var query = _projectRepository.GetAll();
query = query
.WhereIf(!input.Name.IsNullOrWhiteSpace(), item => item.Name.Contains(input.Name))
.WhereIf(!input.Address.IsNullOrWhiteSpace(), item => item.Address.Contains(input.Address))
.WhereIf(!input.ResponbleDepart.IsNullOrWhiteSpace(), item => item.ResponbleDepart.Contains(input.ResponbleDepart))
.WhereIf(!input.Type.IsNullOrWhiteSpace(), item => item.Type.Contains(input.Type))
.WhereIf(input.ProjectDateStart.HasValue, item => item.StartTime >= input.ProjectDateStart)
.WhereIf(input.ProjectDateEnd.HasValue, item => item.EndTime <= input.ProjectDateEnd)
.WhereIf(input.ReportDateStart.HasValue, item => item.ReportTime >= input.ReportDateStart)
.WhereIf(input.ReportDateEnd.HasValue, item => item.ReportTime <= input.ReportDateEnd);
var projectCount = await query.CountAsync();
var projects = await query.OrderBy(input.Sorting).PageBy(input).ToListAsync();
var projectListDtos = ObjectMapper.Map<List<ProjectListDto>>(projects);
return new PagedResultDto<ProjectListDto>(
projectCount,
projectListDtos
);
}