我有一个:
public Dictionary<string,BaseModel> data { get; set; }
我希望实现与现在工作的代码等效,只使用Linq延迟执行。
foreach (KeyValuePair<string, BaseModel> item in data)
{
T model = (T)item.Value; //each item needs to be cast to T, T inherits from BaseModel
model.Init(this, personId); //Init is a function I wrote I want to call on each item
l.Add(model); //currently I am adding each item to a list, but IEnumerable<T> can work
}
我开始编写代码如下:
IEnumerable<T> l = Cache[type].Data.Cast<T>()
.Select(item => item);
但我无法弄清楚如何在每个项目上调用Init函数(每个模型都有一个,它们都从BaseModel继承)。我一直在阅读关于谓词委托等的内容,但找不到如何做某事的例子(pseduocode):
IEnumerable<T> l = Cache[type].Data.Cast<T>()
.Select(item => item)
.RunMeOnEachItemLater(InitWrapperDelegate);
如果你想知道这是为了什么,我有一个MVC项目,我正在实现一个模型数据缓存。
答案 0 :(得分:4)
别。强烈建议在功能样式中使用LINQ - 您的谓词不应该有副作用。这正是因为延迟执行 - 这意味着传递给LINQ方法的lambda只在需要时才会执行,如果有的话。
如果您想确保在IEnumerable
的元素上调用一些副作用,请使用foreach
:
foreach (var model in Cache[type].Data.Select(i=>i.Value).Cast<T>()) {
model.Init(...);
}
即便如此,如果您需要初始化的对象,我还是会考虑在字段或变量中缓存LINQ表达式的结果:
var models = Cache[type].Data.Select(i=>i.Value).Cast<T>().ToArray();
foreach (var model in models) {
...
}
原因是IEnumerable
无法保证每次枚举时都返回相同的项目。显然,如果基础类型是一个集合,但如果您知道它是,那么您应该使用ICollection
而不是IEnumerable
来表达它。
如果您不能使Init
幂等,以便每次从缓存中获取内容时都可以重新执行它,那么在将模型添加到缓存时,或者以其他方式清理其生命周期时,您应该初始化模型。
答案 1 :(得分:1)
您可以使用List(T).ForEach
方法,如下所示:
var l = Cache[type].Data.Cast<T>().ToList().ForEach(InitWrapperDelegate);
答案 2 :(得分:1)
为什么不将伪代码转换为实际代码?
public static class MyExtensions
{
public static IEnumerable<T> RunMeOnEachItemLater(this IEnumerable<T> sequence,
Action<T> action)
{
foreach(T item in sequence)
{
action(item);
yield return item;
}
}
}
现在,您可以稍后使用LINQ延迟执行为每个项执行自定义函数:
IEnumerable<BaseModel> l = Cache[type].Data.Cast<BaseModel>()
.RunMeOnEachItemLater(m => m.Init());
答案 3 :(得分:-1)
功能等同物是:
var list = data.Values.Cast<T>()
.Select(x=>
{
x.Init(this, personId);
return x;
})
.ToList();
请注意,您可以删除.ToList()
以返回IEnumerable<T>
,并在枚举列表时稍后运行Init
次调用。