C# 在IEnumerable中创建泛型方法
好的,给我一点背景资料。 我有一个方法看起来像这样:C# 在IEnumerable中创建泛型方法,c#,entity-framework,linq,generics,C#,Entity Framework,Linq,Generics,好的,给我一点背景资料。 我有一个方法看起来像这样: private static IEnumerable<T> Yield<T>(this IEnumerable<T> models, int numberResults) => numberResults > 0 ? models.Take(numberResults) : models; public async Task<List<UserViewModel>> L
private static IEnumerable<T> Yield<T>(this IEnumerable<T> models, int numberResults) => numberResults > 0 ? models.Take(numberResults) : models;
public async Task<List<UserViewModel>> ListByQueryAsync(string query, int yield)
{
// Put our query in lowercase
var loweredQuery = query.ToLower();
// Get our users and search
var users = base.Users.Where(m => m.UserName.ToLower().Contains(loweredQuery) || m.FirstName.ToLower().Contains(loweredQuery) || m.LastName.ToLower().Contains(loweredQuery)); //.Yield(yield);
// Return our users as a list
return await users.Select(m => UserFactory.Create(m)).ToListAsync();
}
public static class LinqExtensions
{
public static IEnumerable<T> Yield<T>(this IEnumerable<T> models, int numberResults) => models.AsQueryable().YieldQueryable(numberResults);
public static IQueryable<T> Yield<T>(this IQueryable<T> models, int numberResults) => models.YieldQueryable(numberResults);
/// <summary>
/// Lists database entities by a number of results or lists them all
/// </summary>
/// <typeparam name="T">The generic entity to list</typeparam>
/// <param name="models">The query to yield</param>
/// <param name="numberResults">The number of results to yield</param>
/// <returns></returns>
private static IQueryable<T> YieldQueryable<T>(this IQueryable<T> models, int numberResults) => numberResults > 0 ? models.Take(numberResults) : models;
}
私有静态IEnumerable产量(此IEnumerable模型,int numberResults)=>numberResults>0?模型。获取(numberResults):模型;
这对我的项目很有效。我的项目不是使用实体框架的。但是现在它有身份框架,因此它现在使用实体框架
我现在需要列出一些用户,但使用上面相同的功能。
我的方法如下所示:
private static IEnumerable<T> Yield<T>(this IEnumerable<T> models, int numberResults) => numberResults > 0 ? models.Take(numberResults) : models;
public async Task<List<UserViewModel>> ListByQueryAsync(string query, int yield)
{
// Put our query in lowercase
var loweredQuery = query.ToLower();
// Get our users and search
var users = base.Users.Where(m => m.UserName.ToLower().Contains(loweredQuery) || m.FirstName.ToLower().Contains(loweredQuery) || m.LastName.ToLower().Contains(loweredQuery)); //.Yield(yield);
// Return our users as a list
return await users.Select(m => UserFactory.Create(m)).ToListAsync();
}
public static class LinqExtensions
{
public static IEnumerable<T> Yield<T>(this IEnumerable<T> models, int numberResults) => models.AsQueryable().YieldQueryable(numberResults);
public static IQueryable<T> Yield<T>(this IQueryable<T> models, int numberResults) => models.YieldQueryable(numberResults);
/// <summary>
/// Lists database entities by a number of results or lists them all
/// </summary>
/// <typeparam name="T">The generic entity to list</typeparam>
/// <param name="models">The query to yield</param>
/// <param name="numberResults">The number of results to yield</param>
/// <returns></returns>
private static IQueryable<T> YieldQueryable<T>(this IQueryable<T> models, int numberResults) => numberResults > 0 ? models.Take(numberResults) : models;
}
公共异步任务ListByQueryAsync(字符串查询,int-yield)
{
//用小写字母表示我们的查询
var loweredQuery=query.ToLower();
//获取我们的用户并进行搜索
var users=base.users.Where(m=>m.UserName.ToLower().Contains(loweredQuery)| | m.FirstName.ToLower().Contains(loweredQuery)| | m.LastName.ToLower().Contains(loweredQuery));/.Yield(Yield);
//以列表形式返回我们的用户
return wait users.Select(m=>UserFactory.Create(m)).toListSync();
}
users变量是IQueryable,它(如果我正确的话)实现了IEnumerable,而且,如果它被转换成任何具体的类,它将执行SQL。因此,我希望获得一个用户列表,然后使用我的静态方法生成结果量。
起初,我只是简单地复制了上面的方法,并写了以下内容:
private static IQuerable<T> Yield<T>(this IQuerable<T> models, int numberResults) => numberResults > 0 ? models.Take(numberResults) : models;
public static class LinqExtensions
{
public static IEnumerable<T> Yield<T>(this IEnumerable<T> models, int numberResults) => models.YieldEnumerable(numberResults);
public static IQueryable<T> Yield<T>(this IQueryable<T> models, int numberResults) => models.YieldEnumerable(numberResults);
/// <summary>
/// Lists database entities by a number of results or lists them all
/// </summary>
/// <typeparam name="T">The generic entity to list</typeparam>
/// <param name="models">The query to yield</param>
/// <param name="numberResults">The number of results to yield</param>
/// <returns></returns>
private static IEnumerable<T> YieldEnumerable<T>(this IEnumerable<T> models, int numberResults) => numberResults > 0 ? models.Take(numberResults) : models;
}
私有静态可变现收益率(此可变现模型,int numberResults)=>numberResults>0?模型。获取(numberResults):模型;
这很好,但作为干式原则的拥护者,我决定重复同样的方法,因此我认为因为IQuerable实现了IEumerable我将能够编写一个私有方法来处理bot-public方法。所以我写了这个:
private static IQuerable<T> Yield<T>(this IQuerable<T> models, int numberResults) => numberResults > 0 ? models.Take(numberResults) : models;
public static class LinqExtensions
{
public static IEnumerable<T> Yield<T>(this IEnumerable<T> models, int numberResults) => models.YieldEnumerable(numberResults);
public static IQueryable<T> Yield<T>(this IQueryable<T> models, int numberResults) => models.YieldEnumerable(numberResults);
/// <summary>
/// Lists database entities by a number of results or lists them all
/// </summary>
/// <typeparam name="T">The generic entity to list</typeparam>
/// <param name="models">The query to yield</param>
/// <param name="numberResults">The number of results to yield</param>
/// <returns></returns>
private static IEnumerable<T> YieldEnumerable<T>(this IEnumerable<T> models, int numberResults) => numberResults > 0 ? models.Take(numberResults) : models;
}
公共静态类LinqExtensions
{
公共静态IEnumerable收益率(此IEnumerable models,int numberResults)=>models.YieldEnumerable(numberResults);
公共静态IQueryable收益率(此IQueryable模型,int numberResults)=>models.YieldEnumerable(numberResults);
///
///按多个结果列出数据库实体或将其全部列出
///
///要列出的通用实体
///该查询将自动生成
///要产生的结果数
///
私有静态IEnumerable YieldEnumerable(此IEnumerable模型,int numberResults)=>numberResults>0?模型。取(numberResults):模型;
}
现在我得到一个错误声明:
无法将类型“System.Collections.Generic.IEnumerable”隐式转换为“System.Linq.IQuerable”
我可以将IQueryable转换为列表或其他内容,但这意味着我的Yield方法将实际执行SQL,我不希望它这样做。
有人知道我如何解决这个问题吗?我想我可以通过改变一些类似的方法来解决这个问题:
private static IEnumerable<T> Yield<T>(this IEnumerable<T> models, int numberResults) => numberResults > 0 ? models.Take(numberResults) : models;
public async Task<List<UserViewModel>> ListByQueryAsync(string query, int yield)
{
// Put our query in lowercase
var loweredQuery = query.ToLower();
// Get our users and search
var users = base.Users.Where(m => m.UserName.ToLower().Contains(loweredQuery) || m.FirstName.ToLower().Contains(loweredQuery) || m.LastName.ToLower().Contains(loweredQuery)); //.Yield(yield);
// Return our users as a list
return await users.Select(m => UserFactory.Create(m)).ToListAsync();
}
public static class LinqExtensions
{
public static IEnumerable<T> Yield<T>(this IEnumerable<T> models, int numberResults) => models.AsQueryable().YieldQueryable(numberResults);
public static IQueryable<T> Yield<T>(this IQueryable<T> models, int numberResults) => models.YieldQueryable(numberResults);
/// <summary>
/// Lists database entities by a number of results or lists them all
/// </summary>
/// <typeparam name="T">The generic entity to list</typeparam>
/// <param name="models">The query to yield</param>
/// <param name="numberResults">The number of results to yield</param>
/// <returns></returns>
private static IQueryable<T> YieldQueryable<T>(this IQueryable<T> models, int numberResults) => numberResults > 0 ? models.Take(numberResults) : models;
}
公共静态类LinqExtensions
{
公共静态IEnumerable收益率(此IEnumerable models,int numberResults)=>models.AsQueryable().YieldQueryable(numberResults);
公共静态IQueryable收益率(此IQueryable models,int numberResults)=>models.YieldQueryable(numberResults);
///
///按多个结果列出数据库实体或将其全部列出
///
///要列出的通用实体
///该查询将自动生成
///要产生的结果数
///
私有静态IQueryable YieldQueryable(此IQueryable模型,int numberResults)=>numberResults>0?模型。获取(numberResults):模型;
}
它编译后,用户仍然返回为IQuerable,因此它看起来很有效。它不起作用的原因是您实际上正在从两个不同的类调用两个不同的
Take
方法
您的Yield(此IEnumerable models,int numberResults)
正在从类调用
您的Yield(此iquirable models,int numberResults)
正在从类调用
注意返回类型不同,您得到的错误是因为您的第二个函数需要返回一个IQueryable
,但是YieldEnumerable
只返回一个IEnumerable
。虽然您可以将IQueryable
隐式转换为IEnumerable
,但您不能走另一条路
你在回答中发布的工作是迫使这两种方法都通过Queryable.Take
,内部Queryable.Take
创建一个包装器,最终调用Enumerable.Take
作为你的IEnumable
版本
然而,就我个人而言,我将把它作为两个方法,您没有违反DRY,因为您正在调用两个独立的方法
Enumerable.Yield
和Queryable.Yeild
。DRY的要点是降低代码复杂度,使用包装器只会引入额外的开销,并通过引入50%的代码(3行而不是2行)来增加代码复杂度。注意:执行公共静态IQueryable产量(此IQueryable models,int numberResults)=>models.YieldEnumerable(numberResults).AsQueryable()代码>也不好做。这将导致数据库将所有行返回到客户端,然后在内存中执行。Take
。此外,任何。其中
,。选择(
或其他IQueryable
操作,在产生
之后发生,也不会成为服务器上发生的SQL查询的一部分。