简体   繁体   English

以后如何使用linq延迟执行为每个项目执行自定义功能?

[英]how to execute custom function for each item later using linq deferred execution?

I have a: 我有一个:

public Dictionary<string,BaseModel> data  { get; set; }

and I would like to achieve the equivalent of this code which I have working now, only using Linq deferred execution. 并且我想仅使用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
}

I started writing code like: 我开始写如下代码:

IEnumerable<T> l = Cache[type].Data.Cast<T>()
                                   .Select(item => item);

but I can't figure out how to call the Init function (each model has one, they all inherit from BaseModel) on every item. 但我不知道如何在每个项目上调用Init函数(每个模型都有一个,它们都继承自BaseModel)。 I have been reading about predicate delegates and the like but can't find an example of how to do something like (pseduocode): 我一直在阅读有关谓词委托之类的内容,但找不到如何执行类似(pseduocode)的示例:

IEnumerable<T> l = Cache[type].Data.Cast<T>()
                                   .Select(item => item)
                                   .RunMeOnEachItemLater(InitWrapperDelegate);

In case you are wondering what this is for, I have an MVC project and I am implementing a model data cache. 如果您想知道这是干什么的,我有一个MVC项目,并且正在实现模型数据缓存。

Don't. 别。 It is strongly encouraged to use LINQ in a functional style - your predicates shouldn't have side effects. 强烈建议以功能样式使用LINQ-您的谓词不应有副作用。 This is precisely because of deferred execution - what that means is that the lambdas you pass to LINQ methods only get executed when they are needed, if at all. 正是由于延迟执行-这意味着传递给LINQ方法的lambda仅在需要时才执行(如果有的话)。

If you want to have sure some side-effect gets called on elements of your IEnumerable , use foreach : 如果要确保对IEnumerable元素调用某些副作用,请使用foreach

foreach (var model in Cache[type].Data.Select(i=>i.Value).Cast<T>()) {
    model.Init(...);
}

Even then I'd consider caching the result of the LINQ expression in a field or a variable if you need objects you know are initialised: 即使这样,如果您需要初始化的对象也可以考虑将LINQ表达式的结果缓存在字段或变量中:

var models = Cache[type].Data.Select(i=>i.Value).Cast<T>().ToArray();
foreach (var model in models) {
    ...
}

The reason for this is that an IEnumerable isn't guaranteed to return the same items every time it's enumerated. 原因是不能保证IEnumerable每次枚举都返回相同的项。 Obviously it will if the underlying type is a collection, but if you know it is you should use ICollection instead of IEnumerable to express this. 显然,如果基础类型是集合,则可以,但是如果您知道它是,则应使用ICollection而不是IEnumerable来表达这一点。

If you can't make Init idempotent so that it can be reexecuted everytime you fetch things from the cache, you should probably init your models when you add them to the cache, or otherwise clean up their lifecycle. 如果您无法使Init幂等,因此每次您从高速缓存中获取内容时都可以重新执行它,则可能应该在将模型添加到高速缓存中时初始化模型,否则清理它们的生命周期。

您可以像这样使用List(T).ForEach方法:

var l = Cache[type].Data.Cast<T>().ToList().ForEach(InitWrapperDelegate);

Why not to convert your pseudo-code to real code? 为什么不将您的伪代码转换为真实代码?

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;
      }
  }
}

Now you can execute custom function for each item later using LINQ deferred execution: 现在,您可以稍后使用LINQ延迟执行为每个项目执行自定义功能:

IEnumerable<BaseModel> l = Cache[type].Data.Cast<BaseModel>()
                                           .RunMeOnEachItemLater(m => m.Init());

The functional equivalent would be: 功能上的等效项为:

var list = data.Values.Cast<T>()
    .Select(x=>
    {
        x.Init(this, personId); 
        return x;
    })
    .ToList();

Note that you can remove the .ToList() to return an IEnumerable<T> and Init calls would run later when the list is being enumerated. 请注意,您可以删除.ToList()以返回IEnumerable<T>并且在枚举列表时稍后将运行Init调用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM