在我的应用程序中,有相当数量的现有&#34;服务命令&#34;通常返回List<TEntity>
。但是,我以这样的方式编写它们,直到最后一个语句,当它们被转换为ToList<TEntity>
时(或者至少我认为我这样做),才会对任何查询进行求值。
现在我需要开始获取一些特定于上下文的&#34;来自命令的信息,我正在考虑做以下事情:
IEnumerable<TEntity>
而不是IList<TEntity>
。IEnumerable<TResult>
的新命令,其中TResult
不是实体,而是视图模型,结果模型等 - 对应用程序有用的数据的某种表示我需要这个的第一个案例是在搜索Group
实体时。在我的架构中,Group
带有User
- 特定权限,但在我的结果中吐出整个用户和权限列表是不现实的 - 首先,因为可能有很多用户,第二,因为有许多权限,第三,因为该信息不应该对权限不足的用户可用(即&#34;访客&#34;不应该能够看到&#34;成员&#34 ;可以)。
所以,我希望能够获取原始命令IEnumerable<Group>
的结果,并描述每个Group
应如何转换为GroupResult
,具体如下输入User
(在这种情况下为Username
)。
如果我尝试用ForEach
迭代原始命令的结果,我知道这将强制执行结果,因此可能导致不必要的更长的执行时间。如果我想进一步撰写&#34; new&#34;的结果怎么办?命令(返回GroupResult
)并过滤掉某些组?那么也许我会为输入的用户计算大量的权限,只是为了以后过滤出父GroupResult
个对象!
我想我的问题归结为......我如何告诉C#我如何转换IEnumerable
的每个成员而不必在运行该方法时执行此操作?
答案 0 :(得分:1)
懒惰地将一个类型从一种类型转换为另一种类型,你可以这样做:
IEnumerable<TResult> result = source.Cast<TResult>();
这假设源枚举的元素可以强制转换为TResult
。如果他们不能,则需要使用.Select(x => ... )
的标准投影。
另外,请小心从服务或数据库返回IEnumerable<T>
,因为通常需要打开资源来获取数据,所以现在您需要确保在尝试评估可枚举时打开这些资源。保持数据库连接打开是一个坏主意。我更倾向于返回一个你投射为IEnumerable<>
的数组。
但是,如果你真的想从一个真正懒惰的服务或数据库中获得IEnmerable<>
并且会自动刷新数据,那么你需要尝试使用Microsoft的Reactive Framework Team的“Interactive Extensions”来帮助它。
他们有一个很好的IEnumerable<>
扩展名为Using
,它创建了一个“热”枚举,可以为每次迭代打开一个资源。
它看起来像这样:
var d =
EnumerableEx
.Using(
() => new DB(),
db => db.Data.Where(x => x == 2));
每次迭代枚举时都会创建一个新的DB
实例,并在枚举完成后处理数据库。值得考虑的事情。
使用NuGet并为Interactive Extensions查找“Ix-Main”。
答案 1 :(得分:0)
您正在寻找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!
}