private void ReadCollection(CollectionDataContract collectionContract)
{
Type type = collectionContract.UnderlyingType;
Type itemType = collectionContract.ItemType;
bool isArray = (collectionContract.Kind == CollectionKind.Array);
ConstructorInfo constructor = collectionContract.Constructor;
if (type.GetTypeInfo().IsInterface)
{
switch (collectionContract.Kind)
{
case CollectionKind.GenericDictionary:
type = Globals.TypeOfDictionaryGeneric.MakeGenericType(itemType.GetGenericArguments());
constructor = type.GetConstructor(BindingFlags.Instance | BindingFlags.Public, Array.Empty<Type>());
break;
case CollectionKind.Dictionary:
type = Globals.TypeOfHashtable;
constructor = XmlFormatGeneratorStatics.HashtableCtor;
break;
case CollectionKind.Collection:
case CollectionKind.GenericCollection:
case CollectionKind.Enumerable:
case CollectionKind.GenericEnumerable:
case CollectionKind.List:
case CollectionKind.GenericList:
type = itemType.MakeArrayType();
isArray = true;
break;
}
}
string itemName = collectionContract.ItemName;
string itemNs = collectionContract.StableName.Namespace;
_objectLocal = _ilg.DeclareLocal(type, "objectDeserialized");
if (!isArray)
{
if (type.GetTypeInfo().IsValueType)
{
_ilg.Ldloca(_objectLocal);
_ilg.InitObj(type);
}
else
{
_ilg.New(constructor);
_ilg.Stloc(_objectLocal);
_ilg.Call(_contextArg, XmlFormatGeneratorStatics.AddNewObjectMethod, _objectLocal);
}
}
LocalBuilder size = _ilg.DeclareLocal(Globals.TypeOfInt, "arraySize");
_ilg.Call(_contextArg, XmlFormatGeneratorStatics.GetArraySizeMethod);
_ilg.Stloc(size);
LocalBuilder objectId = _ilg.DeclareLocal(Globals.TypeOfString, "objectIdRead");
_ilg.Call(_contextArg, XmlFormatGeneratorStatics.GetObjectIdMethod);
_ilg.Stloc(objectId);
bool canReadPrimitiveArray = false;
if (isArray && TryReadPrimitiveArray(type, itemType, size))
{
canReadPrimitiveArray = true;
_ilg.IfNot();
}
_ilg.If(size, Cmp.EqualTo, -1);
LocalBuilder growingCollection = null;
if (isArray)
{
growingCollection = _ilg.DeclareLocal(type, "growingCollection");
_ilg.NewArray(itemType, 32);
_ilg.Stloc(growingCollection);
}
LocalBuilder i = _ilg.DeclareLocal(Globals.TypeOfInt, "i");
object forLoop = _ilg.For(i, 0, Int32.MaxValue);
IsStartElement(_memberNamesArg, _memberNamespacesArg);
_ilg.If();
_ilg.Call(_contextArg, XmlFormatGeneratorStatics.IncrementItemCountMethod, 1);
LocalBuilder value = ReadCollectionItem(collectionContract, itemType, itemName, itemNs);
if (isArray)
{
MethodInfo ensureArraySizeMethod = XmlFormatGeneratorStatics.EnsureArraySizeMethod.MakeGenericMethod(itemType);
_ilg.Call(null, ensureArraySizeMethod, growingCollection, i);
_ilg.Stloc(growingCollection);
_ilg.StoreArrayElement(growingCollection, i, value);
}
else
StoreCollectionValue(_objectLocal, value, collectionContract);
_ilg.Else();
IsEndElement();
_ilg.If();
_ilg.Break(forLoop);
_ilg.Else();
HandleUnexpectedItemInCollection(i);
_ilg.EndIf();
_ilg.EndIf();
_ilg.EndFor();
if (isArray)
{
MethodInfo trimArraySizeMethod = XmlFormatGeneratorStatics.TrimArraySizeMethod.MakeGenericMethod(itemType);
_ilg.Call(null, trimArraySizeMethod, growingCollection, i);
_ilg.Stloc(_objectLocal);
_ilg.Call(_contextArg, XmlFormatGeneratorStatics.AddNewObjectWithIdMethod, objectId, _objectLocal);
}
_ilg.Else();
_ilg.Call(_contextArg, XmlFormatGeneratorStatics.IncrementItemCountMethod, size);
if (isArray)
{
_ilg.NewArray(itemType, size);
_ilg.Stloc(_objectLocal);
_ilg.Call(_contextArg, XmlFormatGeneratorStatics.AddNewObjectMethod, _objectLocal);
}
LocalBuilder j = _ilg.DeclareLocal(Globals.TypeOfInt, "j");
_ilg.For(j, 0, size);
IsStartElement(_memberNamesArg, _memberNamespacesArg);
_ilg.If();
LocalBuilder itemValue = ReadCollectionItem(collectionContract, itemType, itemName, itemNs);
if (isArray)
_ilg.StoreArrayElement(_objectLocal, j, itemValue);
else
StoreCollectionValue(_objectLocal, itemValue, collectionContract);
_ilg.Else();
HandleUnexpectedItemInCollection(j);
_ilg.EndIf();
_ilg.EndFor();
_ilg.Call(_contextArg, XmlFormatGeneratorStatics.CheckEndOfArrayMethod, _xmlReaderArg, size, _memberNamesArg, _memberNamespacesArg);
_ilg.EndIf();
if (canReadPrimitiveArray)
{
_ilg.Else();
_ilg.Call(_contextArg, XmlFormatGeneratorStatics.AddNewObjectWithIdMethod, objectId, _objectLocal);
_ilg.EndIf();
}
}