强制转换IEnumerable< tenty >到IEnumerable< result >同时确保延迟执行
本文关键字:IEnumerable 确保 延迟 执行 result tenty 转换 | 更新日期: 2023-09-27 18:03:42
在我的应用程序中,有相当数量的现有"服务命令"通常返回List<TEntity>
。然而,我以这样一种方式编写它们,任何查询都不会被评估,直到最后一条语句,当它们被转换为ToList<TEntity>
(或者至少我认为我做了)。
现在我需要开始从命令中获取一些"特定于上下文"的信息,我正在考虑做以下事情:
- 保持现有的命令大致相同,但确保它们返回
IEnumerable<TEntity>
而不是IList<TEntity>
。 - 创建调用旧命令的新命令,但返回
IEnumerable<TResult>
,其中TResult
不是实体,而是视图模型,结果模型等-对应用程序有用的数据的一些表示。
我需要的第一个案例是在搜索Group
实体时。在我的模式中,Group
具有特定于User
的权限,但是在我的结果中吐出用户和权限的整个列表是不现实的——首先,因为可能有很多用户,其次,因为有很多权限,第三,因为这些信息不应该提供给没有足够特权的用户(即"guest"不应该能够看到"member"可以做什么)。
因此,我希望能够获得原始命令IEnumerable<Group>
的结果,并描述如何将每个Group
转换为GroupResult
,给定User
的特定输入(在本例中为Username
)。
如果我尝试用ForEach
遍历原始命令的结果,我知道这将强制执行结果,因此可能导致不必要的更长的执行时间。如果我想进一步组合"new"命令(返回GroupResult
)的结果并过滤掉某些组,该怎么办?然后,我可能会为输入的用户计算大量的特权,无论如何,只是为了过滤掉父GroupResult
对象!
IEnumerable
的每个成员,而不必在方法运行时进行转换?
要将一个可枚举对象从一种类型惰性强制转换为另一种类型,可以这样做:
IEnumerable<TResult> result = source.Cast<TResult>();
假设源枚举对象的元素可以强制转换为TResult
。如果他们不能,你需要使用.Select(x => ... )
的标准投影。
另外,要小心从服务或数据库返回IEnumerable<T>
,因为通常需要打开资源来获取数据,所以现在您需要确保每当尝试计算枚举值时这些资源都是打开的。保持数据库连接是一个坏主意。我更倾向于返回一个你已经转换为IEnumerable<>
的数组。
然而,如果你真的想从一个服务或数据库中获得一个真正懒惰的IEnmerable<>
,并且会自动刷新数据,那么你需要尝试微软的响应式框架团队的"交互式扩展"来帮助它。
他们有一个很好的IEnumerable<>
扩展名为Using
,它创建了一个"热"可枚举对象,为每次迭代打开一个资源。
它看起来像这样:
var d =
EnumerableEx
.Using(
() => new DB(),
db => db.Data.Where(x => x == 2));
每次迭代可枚举对象时,它都会创建一个新的DB
实例,并在可枚举对象完成时释放数据库。值得考虑的事情。
使用NuGet查找"Ix-Main"作为交互式扩展
您正在查找yield return
命令。
当您定义一个返回IEnumerable
的方法,并通过yield return
返回它的数据时,返回值将在消费方法中迭代。这就是它的样子:
IEnumerable<GroupResult> GetGroups(string userName)
{
foreach(var group in context.Groups.Where(g => <some user-specific condition>))
{
var result = new GroupResult()
... // Further compose the result.
yield return result;
}
}
在消费代码:
var groups = GetGroups("tacos");
// At this point no eumeration has occurred yet. Any breakpoints in GetGroups
// have not been hit.
foreach(var g in groups)
{
// Now iteration in GetGroups starts!
}