我需要基于扩展方法(即我必须使用静态非泛型类)实现一个API。该API应与LINQ流畅API平稳地工作,并且大多数情况下应与IQueryable参数一起使用。像这样:
public static class SomeExtensions
{
public static IQueryable<TEntity> SomeMethod<TEntity>(this IQueryable<TEntity> set, ... some arguments)
{
}
}
现在,假设该方法应该带有一些参数以及一个Expression<Func<TEntity, TResult>>
参数:
public static IQueryable<TEntity> SomeMethod<TEntity, TResult>(
this IQueryable<TEntity> set,
...,
Expression<Func<TEntity, TResult>> orderByExpression)
{
}
我希望将orderByExpression传递给流畅API的OrderBy方法,如果orderByExpression == null,则执行其他操作。
自然而然地,我想要像这样的东西:
public static IQueryable<TEntity> SomeMethod<TEntity, TResult>(
this IQueryable<TEntity> set,
...,
Expression<Func<TEntity, TResult>> orderByExpression = null)
{
}
...但是在调用此方法时,如果没有可选参数,我必须隐式传递泛型类型,因为编译器不知道TResult的类型。
我看到一些可能的方法,但我不太喜欢它们。
定义两个方法:一个带有这个参数,一个没有,并从第二个调用第一个。我不喜欢这个方法,因为实际上,在API中有很多这样的方法,我将不得不为每个方法定义一个额外的方法。
使用
Expression<Func<TEntity, object>>
代替Expression<Func<TEntity, TResult>>
(目前是这样)。我摆脱了泛型类型,但是对于像int这样的简单(值)类型存在问题:当尝试将System.Int32转换为System.Object时,LINQ会引发异常。也许(还没有尝试过)我可以使用
Expression<Func<TEntity, dynamic>>
——但我认为这不是一个好方法。
还有其他想法吗?
Enumerable
和Queryable
类是设计此类API的良好示例。无论需要添加多少重载,解决方案都是选项(2)。 - Ivan StoevOrderBy
的功能,而调用方可以在调用您的方法之前使用query.SomeMethod()
或query.OrderBy(...).SomeMethod()
而不会破坏“流畅”的语法。 - Ivan Stoev