所谓的数据源就是我们这节要讨论的Enumerator。Enumerator是一种数据源:它会根据下游数据消耗方(Iteratee)的具体状态主动向下推送数据元素。 我们可以从Enumerator的类型款式看得出: trait Enumerator[E] { /** * Apply this Enumerator to an Iteratee */ from a set of values * * Example: * {{{ * val enumerator: Enumerator[String] = Enumerator 下面是一个文件读取Enumerator例子: import java.io._ val fileEnum: Enumerator[Array[Byte]] = { Enumerator.fromFile 我们可以用Enumerator.through或者Enumeratee.transform来连接Enumerator与Iteratee。
= session.Advanced.Stream(query)) { while (enumerator.MoveNext()) { User activeUser = enumerator.Current.Document; } } //lucene查询 var luceneQuery = session.Advanced.LuceneQuery<User )) { while (enumerator.MoveNext()) { User activeUser = enumerator.Current.Document; ()) { User activeUser = enumerator.Current.Document; } } // using (var enumerator = enumerator.MoveNextAsync()) { User activeUser = enumerator.Current.Document;
`0<string> enumerator, 21 [4] bool flag) 22 L_0000: nop 23 L_0001: newobj 0 [mscorlib]System.Collections.Generic.List`1/Enumerator`0<string>::get_Current() 46 L_003e: GetEnumerator() => new Enumerator((List) this); 即返回一个Enumerator泛型类,然后传入的参数是List泛型自己 this。 接下来查看 Enumerator<T>泛型类 [Serializable, StructLayout(LayoutKind.Sequential)] public struct Enumerator : 所以foreach实际上是编译器编译后先调用GetEnumerator方法返回Enumerator的实例,这个实例即是一个枚举器实例。
public enum EnabledEnum implements Enumerator { /** * Disable status enum. */ DISABLE > & Enumerator>可以解读为E必须为一个枚举类而且同时还必须实现Enumerator接口。 为什么实现Enumerator接口? > & Enumerator> Map<Integer, String> enumToOptions(Class<E> enumClazz){ // 合并时检查 key 是否重复 ::value, Enumerator::description, merge,LinkedHashMap::new)); } (enumClazz.getEnumConstants()) .filter(enumerator -> Objects.equals(enumerator.code(),value
<Object> enumerator = Linq4j.enumerator(list); return new JsonTable(jsonarr); } private }; } } public static class JsonEnumerator implements Enumerator<Object[]> { private Enumerator<Object[]> enumerator; public JsonEnumerator(JSONArray jsonarr) { = Linq4j.enumerator(objs); } public Object[] current() { return (Object []) enumerator.current(); } public boolean moveNext() { return enumerator.moveNext
也就是说:Enumerator负责发送,Iteratee负责接收。用Iteratee实现Reactive-Streams时必须实现Enumerator和Iteratee之间的双向通告机制。 在消耗数据的过程中Iteratee也必须负责与Enumerator沟通以保证数据传输的顺利进行。那么Iteratee又应该如何与Enumerator沟通呢? fold是个callback函数提供给Enumerator。 from a set of values * * Example: * {{{ * val enumerator: Enumerator[String] = Enumerator 里定义的,看看下面这个Enumerator例子: val enumerator = new Enumerator[String] { // some messages val items
FunDA的具体解决方案是把publisher转换成play-iteratee的Enumerator。 play-iteratee支持Reactive-Streams,所以这个Enumerator应该具备协调后台数据和内存缓冲之间关系(back-pressure)的功能。 play-iteratee是如下构建Enumerator的; import play.api.libs.iteratee._ val enumerator = streams.IterateeStreams.publisherToEnumerator (publisher) enumerator从后台数据库表中产生的数据源通过Iteratee把数据元素enqueue推送给一个fs2的queue: private def pushData[R] 从Enumerator转换到Stream整个过程和原理我们在FunDA(7)里已经详细介绍过了。
Enum.8: Specify enumerator values only when necessary Enum.8: 只在必要时指定枚举值 Reason(原因) It's the simplest It avoids duplicate enumerator values. Enforcement(实施建议) Flag duplicate enumerator values 标记重复的枚举值 Flag explicitly specified all-consecutive enumerator values 标记显式定义所有枚举值为连续值情况。 原文链接: https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#enum8-specify-enumerator-values-only-when-necessary
NumberOfParallelTasks) { var syncRoot = new object(); if (enumerable == null) return; var enumerator enumerator.MoveNext()) break; seedItemArray[i] = enumerator.Current; } var iAsyncResult = del.BeginInvoke(enumerator, action, seedItemArray[i], syncRoot, i, null, null); , Action<T> achtion, T item, object syncRoot, int i); static void InvokeAction<T>(IEnumerator<T> enumerator (); if (moveNext) item = enumerator.Current; } } } } 整个算法非常简洁
通用枚举范式 为了便于统一处理和规范统一的风格,建议指定一个统一的抽象接口,例如: /** * The interface Enumerator. */ public interface Enumerator return the string */ String description(); } 我们来写一个实现来标识性别: public enum GenderEnum implements Enumerator , new JsonSerializer<Enumerator>() { @Override public void serialize( Enumerator value, JsonGenerator gen, SerializerProvider serializers) throws IOException { , new JsonSerializer<Enumerator>() { @Override public void serialize(Enumerator value
IEnumerator自定义的Enumerator:EmployeeEnumerator。 Foreach的执行流程和While完全一样:首先调用EmployeeList对象的GetEnumerator获得对应的Enumerator,然后开始循环,并通过Enumerator的MoveNext方法的返回结果来确定是否中止循环 在Arraylist中使用的Enumerator是ArrayListEnumeratorSimple。 基于这两点,我们重新定义Enumerator:OptimizedEmployeeEnumerator。 不错,我们的解决方案就是使用Generic的Enumerator。所以我们重新定义我们的Enumerator:GenericEmployeeEnumerator。
enumerator = list.GetEnumerator()) { while (enumerator.MoveNext()) { int current = enumerator.Current this.Func(current); } } 初看上去似乎没有什么申请内存的地方,但是注意到这里using的使用,其最后会通过IDisposable接口调用Dispose,但是由于List的Enumerator 也会产生40字节的GC Alloc,同样的看下转换后的代码: // ForeachTest private void ForeachArrayList() { using (IEnumerator enumerator = this.m_arrayList.GetEnumerator()) { while (enumerator.MoveNext()) { object current = enumerator.get_Current foreach List是不同的,foreach List如上面所说,是由于装箱操作而引起的GC Alloc,但是foreach ArrayList则是由于GetEnumerator,因为ArrayList的Enumerator
; public BookCollectionEnumerator(IEnumerator enumerator) { _Enumerator = enumerator; } public Book Current { get { return (Book)_Enumerator.Current ; } } object IEnumerator.Current { get { return _Enumerator.Current ; } } public bool MoveNext() { return _Enumerator.MoveNext(); } public void Reset() { _Enumerator.Reset(); } public void
public List<Coroutine> coroutines = new List<Coroutine>(); 8 9 public Coroutine Creat(IEnumerator enumerator ) 10 { 11 var coroutine = StartCoroutine(enumerator); 12 coroutines.Add(coroutine ); 13 return coroutine; 14 } 15 16 public Coroutine Creat(IEnumerator enumerator, Coroutine coroutine) 17 { 18 Kill(coroutine); 19 coroutine = StartCoroutine(enumerator); 20
element.ElementSchemaType as XmlSchemaComplexType; // If the complex type has any attributes, get an enumerator if (complexType.AttributeUses.Count > ) { IDictionaryEnumerator enumerator = complexType.AttributeUses.GetEnumerator(); while (enumerator.MoveNext()) { XmlSchemaAttribute attribute = (XmlSchemaAttribute)enumerator.Value
语句的等价形式(while循环) foreach(var p in Persons){ WriteLine(p);} // 等价于一个 while 循环IEnumerator<Person> enumerator = persons.GetEnumerator();while(enumerator.MoveNext()){ Person p = enumerator.Current; WriteLine (见下文) Part3 IEnumerator 与 yield 一个集合类想要支持被迭代,最主要的是构造一个 Enumerator 类,实现 IEnumerator 接口,在 GetEnumerator 方法中返回这个 Enumerator 类。 如此,在 Enumerator 类中,需要维护 Current 属性和 MoveNext 方法,在 MoveNext 方法中,更新 Current 的值,并返回是否还有后续值的 bool 判断。
这是因为在Iteratee模式里虽然理论上由Enumerator负责主动推送数据,实现了push-model功能。 但实际上Iteratee也会根据自身情况,通过提供callback函数通知Enumerator可以开始推送数据,这从某种程度上也算是一种pull-model。 换句话讲Reactive-Streams是通过push-pull-model来实现上下游Enumerator和Iteratee之间互动的。 (1,2,3,4,5) //> enumNumbers : play.api.libs.iteratee.Enumerator[Int] = play.api.libs.iteratee.Enumerator 也就是说如果我们希望把一个Enumerator产生的数据引导到fs2 Stream的话,只能在所有数据都读入内存后才能实现了。这样就违背了使用Reactive-Streams的意愿。那我们应该怎么办?
7 8 9 10 11 public static void DoWhatYouLikeByWalterlv(DependencyObject dependencyObject) { var enumerator = dependencyObject.GetLocalValueEnumerator(); while (enumerator.MoveNext()) { var entry = enumerator.Current; var property = entry.Property; var value = entry.Value; properties overview - Microsoft Docs 本文会经常更新,请阅读原文: https://blog.walterlv.com/post/wpf-get-local-value-enumerator.html
the first frame update void Start() { Debug.Log("协程之前执行的打印"); StartCoroutine(enumerator ()); Debug.Log("协程之后执行的打印"); } public IEnumerator enumerator() { Debug.Log "); //这种开启协程可以终止 //StopCoroutine("enumerator"); //可以终止 StartCoroutine(enumerator( )); //这种开启协程终止不了 StopCoroutine(enumerator()); //终止不了 } // Start is called before the ()); //Debug.Log("协程之后执行的打印"); } public IEnumerator enumerator() { Debug.Log
public interface IEnumerable { IEnumerator GetEnumerator(); } 注意:我们经常用的foreach即是一种语法糖,实际上还是调用Enumerator foreach foreach (var buddy in list) { Console.WriteLine(buddy); } // Iterate the list by using enumerator List<string>.Enumerator enumerator = list.GetEnumerator(); while (enumerator.MoveNext()) { Console.WriteLine (enumerator.Current); } 上面的代码中用到的foreach和enumerator到IL中最后都会被翻译成enumerator的MoveNext和Current。 通过yield return 来返回 实现我们自己的IEnumerator来实现 这里给大家演示一下如何通过yield来实现返回enumerator public class BuddyList