Something behind yield

本文详细介绍了 C# 中的 yield 关键字,探讨了使用 yield 的优势及限制条件,包括如何用 yield 实现迭代器,以及在何种情况下不能使用 yield。通过具体的代码示例解释了 yield 的工作原理。

Today I spent quite some time on digging into C# yield keyword. It is one of the hard areas in C# for me to understand. I started by reading the C# reference but it didn’t help me too much, until I found this article on MSDN magazine.

 

 

Overview

If you need to return a collection in one function, you can choose to return a collection (such as List<T>) directly, or return an IEnumerator for the outside loop to iterate. The first one is easy to implement but there might have performance defects when the collection is huge – for every call of our function there will be a List<T> object generated on GC heap, even if you only want to process the first several objects. The 2nd solution is much simpler and more memory effective however there are several issues attached with it:

1)    Hard to implement IEnumerators for complicated data structures like binary trees. Our IEnumerator implementation has to maintain the state of the current visit and the code is really complex and error leading in this case.

2)    If you are going to provide several different iterators for a collection, our code will be bloated with various iterator implementations.

 

yield keyword (introduced in C# of .Net 2.0) is provided to address the above two issues. With yield there is no need for you to worry about remembering state for the iterator anymore. All you need to do is to tell what to yield and the compiler will automatically generate the IEnumerator implementation for you automatically.

 

public class EnumerableTest: IEnumerable<int>

{

IEnumerator<int> IEnumerable<int>.GetEnumerator()

{

yield return 0;

yield return 1;

for(int i = 2; i < 5; i++)

{

yield return i;

if (i > 3)

{

yield break;

}

}

}

IEnumerator IEnumerable.GetEnumerator()

{

return ((IEnumerable<int>)this)GetEnumerator();

}

}

 

A simple way to understand yield is as follows: Compiler generated code returns each value you yield in your code (with regards to the order they appear in the code), and pause the execution of the method from that place. When next iteration comes, the method will resume execution from where it is paused and next value is returned.

 

Iterator Implementation

The C# compiler will generate a nested class for the code containing the yield keyword. The class is an implementation of the IEnumerator<T> interface and encapsulates the state needed to iterate within the parent class – here a simple state machine is used to achieve this. When the iterator is first called a new iterator object is created and it’ll be used throughout the remaining iterations. The iterator object doesn’t persist across loops so it is safe for you to call foreach again because you’ll get a brand new iterator object to start the new iteration.

 

There are plenty of articles about this so I don’t want to put more details here.

 

Limitations Explained

yield can appear in any iterator block, where the iterator block can be function, property, indexer etc. There are some limitations where you can use yield though:

1)    You cannot have a return in the function or property where yield is used.

This is obvious because a return will break the iteration improperly.

2)    yield cannot be used in a try block which has a corresponding catch block (finally block is OK).

This is not very intuitive but not very hard to understand. It’s all about the complexity of supporting this.

IEnumerable<int> Content()

{

      try

{

      int val = CalculateVal(…);

      yield return val;       // You’ll get a compilation error here.

}

catch (SomeException e)

{

}

}

Suppose the CalculateVal throws an exception, there will be nothing to return for this iteration, which breaks the iterator contract. A possible solution is to move to calculate the next value. Remember this needs to be tracked by the state machine – you can guess out the complexity I believe. Furthermore, is this solution really the wanted behavior for everybody? I doubt.

3)    yield cannot be used within anonymous methods.

Hmm, with this limitation we lose the ability to use yield in lambda expressions. What a pity!

foreach (int sth in (x => { for (int y=0; y<4; y++) { yield return 2*y; y++; } }))  // You’ll get another 2 compilation errors here.

{

     

}

It is said that Microsoft is going to support using yield within anonymous methods in the future. I am looking forward to that.

 

Return Type of Iterator Block

You can return either IEnumerator or IEnumerable for your iterator block using yield. The hidden state machine is always an IEnumerator, and it’s exactly the same code whether you specify IEnumerator or IEnumerable.

Most of the time specifying IEnumeralbe is better because the compiler will automatically generate some kind of “outer” class and provides an implementation of GetEnumerator, which simplifies your code a lot.

 

When would you want to return IEnumerator then? The answer is: it’ll be very useful if you would like to return multiple iteration methods. For example you want to provide pre-order, in-order and post-order iteration for a binary tree, you might use following code to achieve this. This thread has more about this.

 

public class BinaryTree

{

public IEnumerator<Node> PreOrder()

{

…yield return…

}

 

public IEnumerator<Node> PreOrder()

{

…yield return…

}

 

public IEnumerator<Node> PreOrder()

{

…yield return…

}

}

 

yield.jpg

内容概要:本文围绕六自由度机械臂的人工神经网络(ANN)设计展开,重点研究了正向与逆向运动学求解、正向动力学控制以及基于拉格朗日-欧拉法推导逆向动力学方程,并通过Matlab代码实现相关算法。文章结合理论推导与仿真实践,利用人工神经网络对复杂的非线性关系进行建模与逼近,提升机械臂运动控制的精度与效率。同时涵盖了路径规划中的RRT算法与B样条优化方法,形成从运动学到动力学再到轨迹优化的完整技术链条。; 适合人群:具备一定机器人学、自动控制理论基础,熟悉Matlab编程,从事智能控制、机器人控制、运动学六自由度机械臂ANN人工神经网络设计:正向逆向运动学求解、正向动力学控制、拉格朗日-欧拉法推导逆向动力学方程(Matlab代码实现)建模等相关方向的研究生、科研人员及工程技术人员。; 使用场景及目标:①掌握机械臂正/逆运动学的数学建模与ANN求解方法;②理解拉格朗日-欧拉法在动力学建模中的应用;③实现基于神经网络的动力学补偿与高精度轨迹跟踪控制;④结合RRT与B样条完成平滑路径规划与优化。; 阅读建议:建议读者结合Matlab代码动手实践,先从运动学建模入手,逐步深入动力学分析与神经网络训练,注重理论推导与仿真实验的结合,以充分理解机械臂控制系统的设计流程与优化策略。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值