public void GenerateTypeIterator(IILGen ilGenerator, Action <IILGen> pushObj, Action <IILGen> pushCtx, Type type)
{
var finish = ilGenerator.DefineLabel();
var next = ilGenerator.DefineLabel();
if (type == typeof(object))
{
type = _owner.GetPreferedType();
}
var targetIDictionary = _owner.GetInterface(type);
var targetTypeArguments = targetIDictionary.GetGenericArguments();
var keyType = _owner._typeSerializers.LoadAsType(_owner._keyDescriptor, targetTypeArguments[0]);
var valueType = _owner._typeSerializers.LoadAsType(_owner._valueDescriptor, targetTypeArguments[1]);
if (_owner._type == null)
{
_owner._type = type;
}
var isDict = type.GetGenericTypeDefinition() == typeof(Dictionary <,>);
var typeAsIDictionary = isDict ? type : typeof(IDictionary <,>).MakeGenericType(keyType, valueType);
var getEnumeratorMethod = isDict
? typeAsIDictionary.GetMethods()
.Single(
m => m.Name == nameof(IEnumerable.GetEnumerator) && m.ReturnType.IsValueType && m.GetParameters().Length == 0)
: typeAsIDictionary.GetInterface("IEnumerable`1").GetMethod(nameof(IEnumerable.GetEnumerator));
var typeAsIEnumerator = getEnumeratorMethod.ReturnType;
var currentGetter = typeAsIEnumerator.GetProperty(nameof(IEnumerator.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(nameof(IEnumerator.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();
}