YieldEnumerator Class

public abstract class YieldEnumerator : IEnumerator<YieldInstruction>

A custom implementation of IEnumerator<YieldInstruction> which you can derive from in order to implement reusable enumerators. By default, when you have a method that returns IEnumerator (or IEnumerator<YieldInstruction> in our case), with yield statements in the method body, the .Net compiler will auto generate a class behind the scenes that serves as a state machine. When your method is called, this class is created anew, generating garbage.

As an alternative, you can create your own implementation of IEnumerator that can be reused, however the drawback is that you need to implement all of the state machine logic yourself, as well as create the fields to store any arguments that are passed into the original method. I cannot help with the former issue, however the YieldEnumerator and other generic alternatives of it provide a means of taking care of some common coding necessities, such as the fields for storing the arguments and nulling out these fields after the enumerator is finished.

Note that you also need to ensure that the enumerator is only in use by one caller at a time. You can use the InUse property for this, as it will be set to true when PrepareForIteration is called, and set to false once MoveNextImplementation returns false. Typically you will run into this issue if using multiple Worlds, however you should take the issue into account and create a new enumerator if your current enumerator is in use. The ClearFields and ResetImplementation methods are called automatically within the MoveNext method once MoveNextImplementation returns false. The Reset method is not implemented.

Every time the enumerator is called for, PrepareForIteration should be called to ensure correct functioning, whether the enumerator is a reused object or a new object.

Only a single YieldEnumerator class is shown here, however the DeepSpaceLabs.SAM namespace contains multiple generic YieldEnumerators. The generic parameters should match the input parameters of your method that returns IEnumerator<YieldInstruction>. If you cannot find a class that contains the generic parameters you need, you can create your own class that derives from YieldEnumerator. This class should have fields matching the method parameters your method takes as arguments, which you will need to set. You should also null out any reference fields by implementing the NullRefFields method, which is called after once the MoveNextImplementation returns false.

You will not be able to access the parent instance fields or methods from within MoveNextImplementation using this as a base for your custom enumerator. If you need this ability, please derive from the YieldEnumeratorWithParent (or one of its child generic classes) instead. When doing this, make sure to assign the Parent property. If you are reusing the same enumerator with multiple parent different instances, you can assign the Parent before the enumerator is used, and null it out in your NullRefFields method.

Properties

Name Type Description
Current YieldInstruction

The current YieldInstruction. By default it is null, which wil yield for a single frame. If that suits your code, you don't need to set it to anything else, however if you want to yield on a different time frame, set this value before returning true from your MoveNextInternal method.

InUse bool

Tells you whether this enumerator is in use by some caller.

MoveNextCalls int

How many times MoveNext has been called by whatever is using this enumerator, before the current MoveNext. Will be 0 the first time MoveNext (and thus MoveNextImplementation) is called, then 1, then 2, and so on. The value is also reset to 0 in the Reset method which will be called after SAM is finished using the enumerator, so that the next time it is used, it will be 0 for the first call.

If your enumerator needs to simply iterate over a list or array, you can use this for the index, assuming you want to start processing the list or array upon the first call to MoveNextImplementation.

Phase int

In general, enumerators make use of state machine logic, which operates in phases (Phase 1, do this, phase 2, do that, etc.). This is a convenience property since most enumerators will use a phase, so this avoids you needing to type out a phase variable. You do not need to use it. The Phase is reset to DefaultInitialPhase when PrepareForIteration is called, which is 1 unless overriden. After that, you should set the phase yourself in your MoveNextImplementation. By default the Phase will always start at 1, however you can override this behavour by setting it to a different value in your PerformAdditionalIterationPreparation method.

Methods

Not implemented


Not implemented


MoveNext()

public bool MoveNext()

Iterates the enumerator, which first calls MoveNextImplementation, then increments MoveNextCalls, and finally calls Resets the enumerator if MoveNextImplementation returned false (this sets InUse to false, MoveNextCalls to 0, and then calls the ClearFields and ResetImplementation methods).

Returns

bool
True if the enumerator was advanced to the next Yield Statement (and thus there is more code to exeucte), false if not. Current should only be called when this returns true. Once MoveNext returns false, as the caller you should not use it again. Also note, Current will automatically be set to null once it returns false, so you don't have to.

Exceptions

Type Condition
InvalidOperationException Thrown when this method has been called before PrepareForIteration is called.

MoveNextImplementation()

public abstract bool MoveNextImplementation()

Override to provide an actual implemntation of the MoveNext method, which advances the enumeration. Under normal circumstances, you would put in here whatever you would have put in the MoveNext method, however the MoveNext method is reserved to perform some additional actions.

Returns

bool
True if the enumerator was advanced to the next Yield Statement (and thus there is more code to exeucte), false if not. Current should only be called when this returns true. Once MoveNext returns false, the caller you should not use it again until calling the method that returned the enumerator again.


NullRefFields()

public virtual void NullRefFields()

Called automatically once MoveNextImplementation returns false, you need only worry about implementing this method if not deriving from one of the Generic implementations of YieldEnumerator and only when you have reference fields that should be nulled out after the enumerator has finished iterating. Note, the method is implemented by the generic types, which is why you don't need to worry about it if deriving from one of them. The generic types that have a Parent will also null out the parent, which is why the PrepareForIteration method needs to pass in the Parent instance each call.

If you are deriving from one of the generics, any reference fields indicated by the type parameters will be nulled out automatically (and also the Parent). Any addditional fields you want to null out should be nulled out in your ResetImplementation method.

Also note that this method is called after ResetImplementation, so you can still access the references if needed in order to perform the reset (although note this is unlikely).


PerformAdditionalIterationPreparation()

public virtual void PerformAdditionalIterationPreparation()

You can override this to perform additional initialization each time the enumerator will be used. When PrepareForIteration is called (automatically when you are deriving from one of the generic YieldEnumerators and you call the PrepareForIteration method with the arguments for your fields, or manually if not deriving from one of those but instead from YieldEnumerator or YieldEnumeratorWithParent directly), this is called by it.


PrepareForIteration()

public YieldEnumerator PrepareForIteration()

Prepares the enumerator for iteration. Should be called before returning the enumerator to whatever caller is going to iterate over it. If you are deriving from YieldEnumerator or YieldEnumeratorWithParent directly, you should call this method manually before returning the enumerator to the caller. This method will call PerformAdditionalIterationPreparation, so if you are deriving from one of the generic YieldEnumerators, which calls PrepareForIteration automatically, and you need to perform some sort of setup or initialization each time the enumerator is about to be used, override PerformAdditionalIterationPreparation.

If you are deriving from one of the generic implementations of YieldEnumerator, do not call this method yourself, instead call the PrepareForIteration method that uitilizes the generic types you are making use of as parameters.

Also note that PerformAdditionalIterationPreparation is called before the DefaultInitialPhase is queried, so you can setup data that manipulates the value of DefaultInitialPhase if you so choose.

Returns


Returns itself, which is just intendend to make one line initialization and returns possible


ResetImplementation()

public virtual void ResetImplementation(

Called automatically by the base YieldEnumerator once MoveNextImplementation returns false. You don't have to to implement this; only do so if you have some cleanup that needs to be performed outside of nulling reference fields. Note that nulling reference fields, including the Parent if deriving from YieldEnumeratorWithParent, is done after this method is called, so you can still access those fields to perform the reset if needed.