我正在玩弄yield和IEnumerable,我现在好奇为什么或如何以下代码段工作:
public class FakeList : IEnumerable<int>
{
private int one;
private int two;
public IEnumerator<int> GetEnumerator()
{
yield return one;
yield return two;
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
Run Code Online (Sandbox Code Playgroud)
现在编译器如何转变:
public IEnumerator<int> GetEnumerator()
{
yield return one;
yield return two;
}
Run Code Online (Sandbox Code Playgroud)
变成了IEnumerator<int>?
当你想递归枚举一个分层对象,根据一些标准选择一些元素时,有许多技术的例子,如"展平",然后使用Linq进行过滤:如下所示:
但是,当您枚举类似Form的Controls集合或TreeView的Nodes集合时,我一直无法使用这些类型的技术,因为它们似乎需要一个参数(对于扩展方法),这是一个IEnumerable集合:传入SomeForm.Controls不编译.
我发现最有用的是:
哪个为您提供Control.ControlCollection的扩展方法,其中包含IEnumerable结果,然后您可以使用Linq.
我修改了上面的例子来解析TreeView的节点没有问题.
public static IEnumerable<TreeNode> GetNodesRecursively(this TreeNodeCollection nodeCollection)
{
foreach (TreeNode theNode in nodeCollection)
{
yield return theNode;
if (theNode.Nodes.Count > 0)
{
foreach (TreeNode subNode in theNode.Nodes.GetNodesRecursively())
{
yield return subNode;
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
这是我现在使用扩展方法编写的代码:
var theNodes = treeView1.Nodes.GetNodesRecursively();
var filteredNodes =
(
from n in theNodes
where n.Text.Contains("1")
select n
).ToList();
Run Code Online (Sandbox Code Playgroud)
而且我认为在传递约束的地方可能会有更优雅的方法.
我想知道是否可以一般性地定义这样的过程,以便:在运行时我可以将集合类型以及实际集合传递给泛型参数,因此代码与是否无关它是TreeNodeCollection或Controls.Collection.
我还有兴趣知道是否有任何其他方式(更便宜?fastser?)比第二个链接(上面)中所示,以获得Linq可用的形式的TreeNodeCollection或Control.ControlCollection.
Leppie关于'在第一个(上图)链接的SO帖子中的SelectMany的评论似乎是一个线索.
我对SelectMany的实验是:好吧,称之为"灾难".:)
感谢任何指针.我已经花了几个小时阅读我发现的那些触及这些区域的SO帖子,然后漫无目的地进入像"y-combinator"这样的exotica.一个"谦卑"的经历,我可能会补充:)
简单的例子 - 你有一个返回IEnumerable的方法或属性,调用者在foreach()循环中迭代它.你应该总是在你的IEnumerable方法中使用'yield return'吗?有没有理由不去?虽然我明白它可能并不总是有必要,甚至"更好"(例如,它可能是一个非常小的集合),但有没有理由主动避免这样做?
让我思考这个问题的代码是我写的一个函数非常类似于这个帖子中接受的答案 - 我如何遍历日期范围?
我有一些像这样的代码:
public class EffectValues : IEnumerable<object>
{
public object [ ] Values { get; set; }
public IEnumerator<object> GetEnumerator ( )
{
return this.Values.GetEnumerator ( );
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator ( )
{
return this.GetEnumerator ( );
}
}
Run Code Online (Sandbox Code Playgroud)
但编译器抱怨说:
"无法将类型'System.Collections.IEnumerator'隐式转换为'System.Collections.Generic.IEnumerator'.存在显式转换(您是否错过了转换?)"
我以为Array类型实现了IEnumerable接口,不是吗?因为我可以直接在Values实例上使用Linq功能.
提供itemsq LINQ表达式的结果:
var items = from item in ItemsSource.RetrieveItems()
where ...
Run Code Online (Sandbox Code Playgroud)
假设每个项目的生成需要一些不可忽略的时间.
有两种操作模式:
使用foreach将允许开始使用集合开头的项目,而不是最终可用的项目.但是,如果我们想稍后再次处理相同的集合,我们将不得不复制保存它:
var storedItems = new List<Item>();
foreach(var item in items){
Process(item);
storedItems .Add(item);
}
// Later
foreach(var item in storedItems){
ProcessMore(item);
}
Run Code Online (Sandbox Code Playgroud)
因为如果我们刚刚制作的foreach(... in items)话temsSource.RetrieveItems()会再次被召唤.
我们可以直接使用.ToList(),但这会迫使我们等待最后一项检索,然后才能开始处理第一项.
问题:是否有一个IEnumerable实现会像常规的LINQ查询结果一样首次迭代,但会在进程中实现,以便第二次foreach迭代存储的值?
我有一个这样的调查员
IEnumerable<System.Windows.Documents.FixedPage> page;
Run Code Online (Sandbox Code Playgroud)
如何添加页面(例如:D:\newfile.txt)?我已经试过Add,Append,Concat等但没有为我工作.
我想通过a枚举List<int>并调用异步方法.
如果我这样做:
public async Task NotWorking() {
var list = new List<int> {1, 2, 3};
using (var enumerator = list.GetEnumerator()) {
Trace.WriteLine(enumerator.MoveNext());
Trace.WriteLine(enumerator.Current);
await Task.Delay(100);
}
}
Run Code Online (Sandbox Code Playgroud)
结果是:
True
0
Run Code Online (Sandbox Code Playgroud)
但我希望它是:
True
1
Run Code Online (Sandbox Code Playgroud)
如果我删除using或await Task.Delay(100):
public void Working1() {
var list = new List<int> {1, 2, 3};
using (var enumerator = list.GetEnumerator()) {
Trace.WriteLine(enumerator.MoveNext());
Trace.WriteLine(enumerator.Current);
}
}
public async Task Working2() {
var list = new List<int> {1, 2, 3};
var enumerator = list.GetEnumerator(); …Run Code Online (Sandbox Code Playgroud) 我正在搞乱泛型和IEnumerable abit,但我有点卡住了.这是我正在尝试做的事情:我希望有一个返回任何集合类型的方法 - 实现IEnumerable(?) - (例如:List,Stack,Queue,...)
此外,我希望能够返回任何数据类型的任何集合类型.所以我希望这种方法能够返回一个List<string>,以及一个Stack<int>,以及List<double>...等等.
public IEnumerable<T> returnSomething()
{
Stack<int> stackOfInts = new Stack<int>();
List<string> listOfStrings = new List<string>();
return stackOfInts;
}
Run Code Online (Sandbox Code Playgroud)
这是我到目前为止所尝试的.这不起作用,我得到这个错误:
Cannot implicitly convert type 'System.Collections.Generic.Stack<int>' to 'System.Collections.Generic.IEnumerable<T>'. An explicit conversion exists (are you missing a cast?)
Run Code Online (Sandbox Code Playgroud)
但是,如果我将IEnumerable<T>方法签名替换为IEnumerable<int>,我可以返回int类型的任何集合.这意味着,现在我不能再回来ListOfStrings了.
会很感激任何建议或想法:)
我需要设计自己的自定义GenericCollection类.现在我有很多选择使用以获得它IEnumerable,ICollection和IList,在后来提供了一些附加功能.
我很困惑,如果我和我一起去,IEnumerable<T>我可能需要声明对象实际上像这种情况一样持有集合_list.
public class GenericCollection<T> : IEnumerable<T>
{
private List<T> _list;
//...
}
Run Code Online (Sandbox Code Playgroud)
但是如果我使用ICollection<T>或者IList<T>,我不需要声明List对象,因为它是隐式可用的.
public class GenericCollection<T> : IList<T>
{
// no need for List object
//private List<T> _list;
//...
}
Run Code Online (Sandbox Code Playgroud)
这两种方法在性能方面有何不同?
在哪种情况下,每个人都是首选,特别是在设计自己的集合时.我对轻量级收藏感兴趣,性能良好.我认为这可以通过使用,IEnumerable<T>但是如何与一些强有力的理由一起使用呢?
我已经审查了一些现有的帖子,但没有提供所需的信息.
我刚看了.NET Framework 的Skip/ Takeextension方法的源代码(在IEnumerable<T>类型上),发现内部实现正在使用该GetEnumerator方法:
// .NET framework
public static IEnumerable<TSource> Skip<TSource>(this IEnumerable<TSource> source, int count)
{
if (source == null) throw Error.ArgumentNull("source");
return SkipIterator<TSource>(source, count);
}
static IEnumerable<TSource> SkipIterator<TSource>(IEnumerable<TSource> source, int count)
{
using (IEnumerator<TSource> e = source.GetEnumerator())
{
while (count > 0 && e.MoveNext()) count--;
if (count <= 0)
{
while (e.MoveNext()) yield return e.Current;
}
}
}
Run Code Online (Sandbox Code Playgroud)
假设我有IEnumerable<T>1000个元素(底层类型是List<T>).如果我正在做list.Skip(990)会怎么样.拿(10)?在进入最后十个元素之前,它是否会通过990首元素进行迭代?(这就是我的理解).如果是,那么我不明白为什么微软没有实现这样的Skip方法:
// Not tested... just to show the …Run Code Online (Sandbox Code Playgroud) c# ×10
ienumerable ×10
linq ×4
.net ×2
yield-return ×2
add ×1
arrays ×1
async-await ×1
generics ×1
icollection ×1
ilist ×1
list ×1
performance ×1
skip-take ×1
treeview ×1