列表结果开闭原则

Open-closed principle for list result

我正在练习如何使用 C# 创建开闭原则以 return 信息列表。但问题是我的主要服务出现错误 class.

这些是我的示例代码:

我有这个界面:

public interface ISelectInfo{
    bool Rule(string rule);
    IQueryable<FoodDto> ReturnSearchResult(string query);
}

我有实现此接口的class。

public class Fruit : ISelectInfo {
    public bool Rule(string rule){ 
        return "fruit".Equals(rule); 
    }
    public IQueryable<FoodDto> ReturnSearchResult(string query){
        // returns a list of FoodDto
    }
}

我有这个主要服务class

public class SelectTypeOFoodService {
    private readonly IList<ISelectInfo> selectInfo;
    public SelectTypeOfFruitService (IList<ISelectInfo> selectInfo){
        this.selectInfo = selectInfo;
    }

    public async IEnumerable<FoodDto> SelectFood(string rule, string query){
        return await selectInfo.ToList().Where(x=>x.Rule(rule)).Select(x=>x.ReturnSearchResult(query)).AsQueryable().TolistAsync();
    }
}

我的 return await selectInfo.ToList()...

上出现错误和红色波浪线

我正在努力实现 return 基于开放封闭原则的 FoodDto 列表。

这是显示 Cannot convert expression type 'System.Collections.Generic.List<System.Linq.IQueryable<FoodDto>>' to return type 'System.Collections.Generic.IEnumerable<FoodDto>'

的红色波浪线的示例结果

我希望有人能帮助我。

或者,您可以在 IQueryable<FoodDto 上使用 async 检查下面我的重构代码。

public class Fruit : ISelectInfo {
    public bool Rule(string rule){ 
        return "fruit".Equals(rule); 
    }
    public async Task<IEnumerable<FoodDto>> ReturnSearchResult(string query){
        // returns a list of FoodDto
    }
}

为您效劳,

... 
public async Task<IEnumerable<FoodDto>> SelectFood(string rule, string query){
    return await selectInfo.FirstOrDefault(x=>x.Rule(rule)).Select(x=>x.ReturnSearchResult(query));
}
...

此外,不要忘记在您的中间件或启动 class 上注册您的接口和 class。

希望这对其他人也有帮助。

我一直纳闷为什么提问者给了一些代码就说代码不行,没有给出具体要求

在我看来,您想向 class SelectTypeOFoodService 添加一个异步函数,该函数将两个参数作为输入:string rulestring query

输出应该是 this.selectInfos 中所有具有 this.selectInfos.Rule(rule)

真实 return 值的项目的 ReturnSearchResult(query)

注意:我冒昧地将您的 collections 的标识符复数化,因为这样可以方便阅读答案。

可能是您简化了您的要求,但在我看来您不需要为此使用异步函数。

IQueryable<FoodDto> QueryFood(string rule, string query)
{
    return this.selectInfos
        .Where(selectInfo => selectInfo.Rule(rule))
        .Select(selectInfo => selectInfo.ReturnSearchResult(query);
}

IEnumerable<FootDto> SelectFood(string rule, string query)
{
     return this.QueryFood(rule, query).AsEnumerable();
}

我选择使用 AsEnumerable 而不是 ToList,因为显然你想要 return 和 IEnumerable。如果您的呼叫者在呼叫您的 SelectFood 后使用 FirstOrDefault,那么将您所有的千种食物转换成一个列表然后只使用第一个是一种浪费。

如果您确实需要调用 ToList,例如因为您要处理可查询的 object,请考虑 return 使用 List 而不是 IEnumerable。这将防止用户调用额外的 ToList,导致您的项目的第二个 list-ification。

List<FoodDto> SelectFood(string rule, string query)
{
     return this.QueryFood(rule, query).ToList()
}

现在创建一个异步版本是有意义的,因为 ToList 是一个实际执行查询的函数,如果查询是由可等待的进程执行的(如数据库查询、互联网获取数据,一个文件读取),那么创建一个异步函数可能是有意义的:

Task<List<FoodDto>> SelectFoodAsync((string rule, string query)
{
     return this.QueryFood(rule, query).ToListAsync();
}

再次重申:如果没有什么可等待的,请不要在class中引入async-await,那样只会降低你的代码效率。

有时,您的 classes 没有什么可等待的,但您确实需要创建一个异步函数,例如实现一个 return 是任务的接口,或者模拟中的功能用于测试使用 async-await.

功能的单元测试

在那种情况下,让异步函数调用同步函数并使用 Task.FromResult 组成 return 值

Task<List<FoodDto>> SelectFoodAsync((string rule, string query)
{
    List<FoodDto> selectedFoods = this.SelectFoods(rule, query);
    return Task.FromResult(selectedFoods);
}