private IteratorTypeInfo CreateIteratorTypeInfo(Type type) { TypeInfo typeInfo = type.GetTypeInfo(); var fi = new IteratorTypeInfo { Type = type, MethodName = NameUtility.ParseOriginalName(type.Name), Constructor = typeInfo.DeclaredConstructors.FirstOrDefault(c => !c.IsStatic) }; foreach (FieldInfo field in typeInfo.DeclaredFields) { char typeChar; string suffix; string original; if (NameUtility.TryParseGeneratedName(field.Name, out typeChar, out suffix, out original)) { if (typeChar == StateTypeChar) { // Must check suffix too since <>1__managedThreadId is also used if (suffix == StateSuffix) { fi.State = field; } } else if (typeChar == CurrentTypeChar) { fi.Current = field; } else if (typeChar == ThisTypeChar) { fi.This = field; } else if (typeChar == ArgumentTypeChar) { fi.Arguments.Add(original ?? suffix, field); } else if (typeChar == HoistedVariableTypeChar) { Debug.Assert(original != null); fi.Variables.Add(original, field); } } else { Debug.Assert(!field.IsPublic); fi.Variables.Add(field.Name, field); } } if (fi.Current == null || fi.State == null || fi.Constructor == null) { return(null); } return(fi); }
/// <summary> /// Convert an IteratorState to an instance of the iterator it represents. /// </summary> /// <param name="state">An IteratorState instance.</param> /// <returns>An equivalent iterator instance.</returns> public IEnumerator FromState(IteratorState state) { if (state == null) { throw new ArgumentNullException(nameof(state)); } Type iteratorType = GetIteratorTypeChecked(state.DeclaringTypeName, state.MethodName); IteratorTypeInfo ti = GetIteratorTypeInfo(iteratorType); if (ti == null) { throw new ArgumentOutOfRangeException(nameof(state), "not an iterator state machine type"); } var iterator = (IEnumerator)ti.Constructor.Invoke(new object[] { state.State }); ti.Current.SetValue(iterator, state.Current); ti.This?.SetValue(iterator, state.This); foreach (KeyValuePair <string, object> a in state.Arguments) { FieldInfo info; if (!ti.Arguments.TryGetValue(a.Key, out info)) { continue; } info.SetValue(iterator, a.Value); } foreach (KeyValuePair <string, object> v in state.Variables) { FieldInfo info; if (!ti.Variables.TryGetValue(v.Key, out info)) { continue; } info.SetValue(iterator, v.Value); } return(iterator); }
/// <summary> /// Convert an iterator to an IteratorState. /// </summary> /// <param name="iterator">The iterator instance.</param> /// <returns>An equivalent IteratorState instance that can be serialized.</returns> /// <exception cref="ArgumentNullException">iterator is null</exception> /// <exception cref="ArgumentOutOfRangeException">iterator is not a compiler-generated iterator state machine.</exception> public IteratorState ToState(IEnumerator iterator) { if (iterator == null) { throw new ArgumentNullException(nameof(iterator)); } IteratorTypeInfo ti = GetIteratorTypeInfo(iterator.GetType()); if (ti == null) { throw new ArgumentOutOfRangeException(nameof(iterator), "not an iterator state machine type"); } var state = new IteratorState { DeclaringTypeName = NameUtility.GetSimpleAssemblyQualifiedName(ti.Type.DeclaringType), MethodName = ti.MethodName, State = (int)ti.State.GetValue(iterator), Current = ti.Current.GetValue(iterator) }; if (ti.This != null) { state.This = ti.This.GetValue(iterator); } foreach (KeyValuePair <string, FieldInfo> a in ti.Arguments) { state.Arguments.Add(a.Key, a.Value.GetValue(iterator)); } foreach (KeyValuePair <string, FieldInfo> v in ti.Variables) { state.Variables.Add(v.Key, v.Value.GetValue(iterator)); } return(state); }
private IteratorTypeInfo CreateIteratorTypeInfo(Type type) { TypeInfo typeInfo = type.GetTypeInfo(); var fi = new IteratorTypeInfo { Type = type, MethodName = NameUtility.ParseOriginalName(type.Name), Constructor = typeInfo.DeclaredConstructors.FirstOrDefault(c => !c.IsStatic) }; foreach (FieldInfo field in typeInfo.DeclaredFields) { char typeChar; string suffix; string original; if (NameUtility.TryParseGeneratedName(field.Name, out typeChar, out suffix, out original)) { if (typeChar == StateTypeChar) { // Must check suffix too since <>1__managedThreadId is also used if (suffix == StateSuffix) { fi.State = field; } } else if (typeChar == CurrentTypeChar) { fi.Current = field; } else if (typeChar == ThisTypeChar) { fi.This = field; } else if (typeChar == ArgumentTypeChar) { fi.Arguments.Add(original ?? suffix, field); } else if (typeChar == HoistedVariableTypeChar) { Debug.Assert(original != null); fi.Variables.Add(original, field); } } else { Debug.Assert(!field.IsPublic); fi.Variables.Add(field.Name, field); } } if (fi.Current == null || fi.State == null || fi.Constructor == null) return null; return fi; }