public void GenerateTypeIterator(IILGen ilGenerator, Action<IILGen> pushObj, Action<IILGen> pushCtx, Type type)
{
var finish = ilGenerator.DefineLabel();
var next = ilGenerator.DefineLabel();
var keyType = _owner._typeSerializers.LoadAsType(_owner._keyDescriptor);
var valueType = _owner._typeSerializers.LoadAsType(_owner._valueDescriptor);
if (_owner._type == null) _owner._type = type;
var isDict = _owner._type != null && _owner._type.GetGenericTypeDefinition() == typeof(Dictionary<,>);
var typeAsIDictionary = isDict ? _owner._type : typeof(IDictionary<,>).MakeGenericType(keyType, valueType);
var getEnumeratorMethod = isDict
? typeAsIDictionary.GetMethods()
.Single(
m => m.Name == "GetEnumerator" && m.ReturnType.IsValueType && m.GetParameters().Length == 0)
: typeAsIDictionary.GetInterface("IEnumerable`1").GetMethod("GetEnumerator");
var typeAsIEnumerator = getEnumeratorMethod.ReturnType;
var currentGetter = typeAsIEnumerator.GetProperty("Current").GetGetMethod();
var typeKeyValuePair = currentGetter.ReturnType;
var localEnumerator = ilGenerator.DeclareLocal(typeAsIEnumerator);
var localPair = ilGenerator.DeclareLocal(typeKeyValuePair);
ilGenerator
.Do(pushObj)
.Castclass(typeAsIDictionary)
.Callvirt(getEnumeratorMethod)
.Stloc(localEnumerator)
.Try()
.Mark(next)
.Do(il =>
{
if (isDict)
{
il
.Ldloca(localEnumerator)
.Call(typeAsIEnumerator.GetMethod("MoveNext"));
}
else
{
il
.Ldloc(localEnumerator)
.Callvirt(() => default(IEnumerator).MoveNext());
}
})
.Brfalse(finish)
.Do(il =>
{
if (isDict)
{
il
.Ldloca(localEnumerator)
.Call(currentGetter);
}
else
{
il
.Ldloc(localEnumerator)
.Callvirt(currentGetter);
}
})
.Stloc(localPair);
if (!_owner._keyDescriptor.Sealed)
{
ilGenerator
.Do(pushCtx)
.Ldloca(localPair)
.Call(typeKeyValuePair.GetProperty("Key").GetGetMethod())
.Callvirt(() => default(IDescriptorSerializerLiteContext).StoreNewDescriptors(null));
}
if (!_owner._valueDescriptor.Sealed)
{
ilGenerator
.Do(pushCtx)
.Ldloca(localPair)
.Call(typeKeyValuePair.GetProperty("Value").GetGetMethod())
.Callvirt(() => default(IDescriptorSerializerLiteContext).StoreNewDescriptors(null));
}
ilGenerator
.Br(next)
.Mark(finish)
.Finally()
.Do(il =>
{
if (isDict)
{
il
.Ldloca(localEnumerator)
.Constrained(typeAsIEnumerator);
}
else
{
il.Ldloc(localEnumerator);
}
})
.Callvirt(() => default(IDisposable).Dispose())
.EndTry();
}