2

我有一个:

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 项目,并且我正在实现一个模型数据缓存。

4

4 回答 4

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幂等性以便每次从缓存中获取内容时都可以重新执行,那么您可能应该在将模型添加到缓存时初始化模型,或者以其他方式清理它们的生命周期。

于 2012-10-31T22:15:59.673 回答
1

你可以使用这样的List(T).ForEach方法:

var l = Cache[type].Data.Cast<T>().ToList().ForEach(InitWrapperDelegate);
于 2012-10-31T22:14:33.533 回答
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());
于 2012-10-31T22:49:12.780 回答
-1

等效的功能是:

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

请注意,您可以删除.ToList()以返回 anIEnumerable<T>并且Init在枚举列表时稍后会运行调用。

于 2012-10-31T22:14:12.530 回答