是否可以确定IEnumerable <T>是否已将执行挂起?

Jas*_*dez 10 c# linq deferred-execution

我有一个接受Enumerable的函数.我需要确保对枚举数进行评估,但是如果它在List或其他"冻结"集合中已经准备就绪,我宁愿不创建它的副本(例如,通过ToList()或ToArray()).冻结我指的是已经建立了一组项目的集合,例如List,Array,FsharpSet,Collection等,而不是像Select()和where()这样的linq.

是否有可能创建一个函数"ForceEvaluation",可以确定枚举是否已将执行挂起,然后评估可枚举?

 public void Process(IEnumerable<Foo> foos)
 {
      IEnumerable<Foo> evalutedFoos = ForceEvaluation(foos)
      EnterLockedMode(); // all the deferred processing needs to have been done before this line. 
      foreach (Foo foo in foos) 
      {
           Bar(foo);
      }  
}

 public IEnumerable ForceEvaluation(IEnumerable<Foo> foos)
 {
      if(??????)
      { return foos}
      else
      {return foos.ToList()}

 }
Run Code Online (Sandbox Code Playgroud)

}

经过一些研究后,我意识到这在任何实际意义上都是不可能的,并且需要对每个迭代器进行复杂的代码检查.

所以我将使用Mark的答案的变体并创建一个已知安全类型的白名单,并且只需调用ToList()不在白名单上的任何内容.

感谢大家的帮助.

编辑*经过更多的反思,我意识到这相当于停止问题.所以非常不可能.

小智 6

对我有用的东西:

IEnumerable<t> deffered = someArray.Where(somecondition);

if (deffered.GetType().UnderlyingSystemType.Namespace.Equals("System.Linq"))
{
  //this is a deffered executin IEnumerable
}
Run Code Online (Sandbox Code Playgroud)


Mar*_*ell 5

可以尝试一个充满希望的对证IList<T>ICollection<T>,但要注意的是,这些仍然可以懒洋洋地实现-但它是非常罕见,和LINQ没有做到这一点-它只是使用迭代器(不懒惰集合).所以:

var list = foos as IList<Foo>;
if(list != null) return list; // unchanged
return foos.ToList();
Run Code Online (Sandbox Code Playgroud)

请注意,这与常规.ToList()不同,每次都会返回不同的列表,以确保不会发生任何意外情况.

大多数具体的集合类型(包括T[]List<T>)都满足IList<T>.我不熟悉F#集合 - 您需要检查它.