| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848 |
- //-----------------------------------------------------------------------------
- // Copyright (c) Microsoft Corporation. All rights reserved.
- //-----------------------------------------------------------------------------
- namespace System.Runtime.Serialization
- {
- using System;
- using System.Collections;
- using System.Collections.Generic;
- using System.Reflection;
- #if !NO_DYNAMIC_CODEGEN
- using System.Reflection.Emit;
- #endif
- using System.Security;
- using System.Security.Permissions;
- using System.Runtime.Serialization.Diagnostics.Application;
- using System.Xml;
- #if USE_REFEMIT
- public delegate void XmlFormatClassWriterDelegate(XmlWriterDelegator xmlWriter, object obj, XmlObjectSerializerWriteContext context,ClassDataContract dataContract);
- public delegate void XmlFormatCollectionWriterDelegate(XmlWriterDelegator xmlWriter, object obj, XmlObjectSerializerWriteContext context, CollectionDataContract dataContract);
- public sealed class XmlFormatWriterGenerator
- #else
- internal delegate void XmlFormatClassWriterDelegate(XmlWriterDelegator xmlWriter, object obj, XmlObjectSerializerWriteContext context, ClassDataContract dataContract);
- internal delegate void XmlFormatCollectionWriterDelegate(XmlWriterDelegator xmlWriter, object obj, XmlObjectSerializerWriteContext context, CollectionDataContract dataContract);
- internal sealed partial class XmlFormatWriterGenerator
- #endif
- {
- [Fx.Tag.SecurityNote(Critical = "Holds instance of CriticalHelper which keeps state that was produced within an assert.")]
- [SecurityCritical]
- CriticalHelper helper;
- [Fx.Tag.SecurityNote(Critical = "Initializes SecurityCritical field 'helper'.")]
- [SecurityCritical]
- public XmlFormatWriterGenerator()
- {
- helper = new CriticalHelper();
- }
- [Fx.Tag.SecurityNote(Critical = "Accesses SecurityCritical helper class 'CriticalHelper'.")]
- [SecurityCritical]
- internal XmlFormatClassWriterDelegate GenerateClassWriter(ClassDataContract classContract)
- {
- try
- {
- if (TD.DCGenWriterStartIsEnabled())
- {
- TD.DCGenWriterStart("Class", classContract.UnderlyingType.FullName);
- }
- return helper.GenerateClassWriter(classContract);
- }
- finally
- {
- if (TD.DCGenWriterStopIsEnabled())
- {
- TD.DCGenWriterStop();
- }
- }
- }
- [Fx.Tag.SecurityNote(Critical = "Accesses SecurityCritical helper class 'CriticalHelper'.")]
- [SecurityCritical]
- internal XmlFormatCollectionWriterDelegate GenerateCollectionWriter(CollectionDataContract collectionContract)
- {
- try
- {
- if (TD.DCGenWriterStartIsEnabled())
- {
- TD.DCGenWriterStart("Collection", collectionContract.UnderlyingType.FullName);
- }
- return helper.GenerateCollectionWriter(collectionContract);
- }
- finally
- {
- if (TD.DCGenWriterStopIsEnabled())
- {
- TD.DCGenWriterStop();
- }
- }
- }
- #if !NO_DYNAMIC_CODEGEN
- [Fx.Tag.SecurityNote(Miscellaneous = "RequiresReview - Handles all aspects of IL generation including initializing the DynamicMethod."
- + " Changes to how IL generated could affect how data is serialized and what gets access to data,"
- + " therefore we mark it for review so that changes to generation logic are reviewed.")]
- partial class CriticalHelper
- {
- CodeGenerator ilg;
- ArgBuilder xmlWriterArg;
- ArgBuilder contextArg;
- ArgBuilder dataContractArg;
- LocalBuilder objectLocal;
- // Used for classes
- LocalBuilder contractNamespacesLocal;
- LocalBuilder memberNamesLocal;
- LocalBuilder childElementNamespacesLocal;
- int typeIndex = 1;
- int childElementIndex = 0;
- internal XmlFormatClassWriterDelegate GenerateClassWriter(ClassDataContract classContract)
- {
- ilg = new CodeGenerator();
- bool memberAccessFlag = classContract.RequiresMemberAccessForWrite(null);
- try
- {
- ilg.BeginMethod("Write" + classContract.StableName.Name + "ToXml", Globals.TypeOfXmlFormatClassWriterDelegate, memberAccessFlag);
- }
- catch (SecurityException securityException)
- {
- if (memberAccessFlag && securityException.PermissionType.Equals(typeof(ReflectionPermission)))
- {
- classContract.RequiresMemberAccessForWrite(securityException);
- }
- else
- {
- throw;
- }
- }
- InitArgs(classContract.UnderlyingType);
- DemandSerializationFormatterPermission(classContract);
- DemandMemberAccessPermission(memberAccessFlag);
- if (classContract.IsReadOnlyContract)
- {
- ThrowIfCannotSerializeReadOnlyTypes(classContract);
- }
- WriteClass(classContract);
- return (XmlFormatClassWriterDelegate)ilg.EndMethod();
- }
- internal XmlFormatCollectionWriterDelegate GenerateCollectionWriter(CollectionDataContract collectionContract)
- {
- ilg = new CodeGenerator();
- bool memberAccessFlag = collectionContract.RequiresMemberAccessForWrite(null);
- try
- {
- ilg.BeginMethod("Write" + collectionContract.StableName.Name + "ToXml", Globals.TypeOfXmlFormatCollectionWriterDelegate, memberAccessFlag);
- }
- catch (SecurityException securityException)
- {
- if (memberAccessFlag && securityException.PermissionType.Equals(typeof(ReflectionPermission)))
- {
- collectionContract.RequiresMemberAccessForWrite(securityException);
- }
- else
- {
- throw;
- }
- }
- InitArgs(collectionContract.UnderlyingType);
- DemandMemberAccessPermission(memberAccessFlag);
- if (collectionContract.IsReadOnlyContract)
- {
- ThrowIfCannotSerializeReadOnlyTypes(collectionContract);
- }
- WriteCollection(collectionContract);
- return (XmlFormatCollectionWriterDelegate)ilg.EndMethod();
- }
- void InitArgs(Type objType)
- {
- xmlWriterArg = ilg.GetArg(0);
- contextArg = ilg.GetArg(2);
- dataContractArg = ilg.GetArg(3);
- objectLocal = ilg.DeclareLocal(objType, "objSerialized");
- ArgBuilder objectArg = ilg.GetArg(1);
- ilg.Load(objectArg);
- // Copy the data from the DataTimeOffset object passed in to the DateTimeOffsetAdapter.
- // DateTimeOffsetAdapter is used here for serialization purposes to bypass the ISerializable implementation
- // on DateTimeOffset; which does not work in partial trust.
- if (objType == Globals.TypeOfDateTimeOffsetAdapter)
- {
- ilg.ConvertValue(objectArg.ArgType, Globals.TypeOfDateTimeOffset);
- ilg.Call(XmlFormatGeneratorStatics.GetDateTimeOffsetAdapterMethod);
- }
- else
- {
- ilg.ConvertValue(objectArg.ArgType, objType);
- }
- ilg.Stloc(objectLocal);
- }
- void DemandMemberAccessPermission(bool memberAccessFlag)
- {
- if (memberAccessFlag)
- {
- ilg.Call(contextArg, XmlFormatGeneratorStatics.DemandMemberAccessPermissionMethod);
- }
- }
- void DemandSerializationFormatterPermission(ClassDataContract classContract)
- {
- if (!classContract.HasDataContract && !classContract.IsNonAttributedType)
- {
- ilg.Call(contextArg, XmlFormatGeneratorStatics.DemandSerializationFormatterPermissionMethod);
- }
- }
- void ThrowIfCannotSerializeReadOnlyTypes(ClassDataContract classContract)
- {
- ThrowIfCannotSerializeReadOnlyTypes(XmlFormatGeneratorStatics.ClassSerializationExceptionMessageProperty);
- }
- void ThrowIfCannotSerializeReadOnlyTypes(CollectionDataContract classContract)
- {
- ThrowIfCannotSerializeReadOnlyTypes(XmlFormatGeneratorStatics.CollectionSerializationExceptionMessageProperty);
- }
- void ThrowIfCannotSerializeReadOnlyTypes(PropertyInfo serializationExceptionMessageProperty)
- {
- ilg.Load(contextArg);
- ilg.LoadMember(XmlFormatGeneratorStatics.SerializeReadOnlyTypesProperty);
- ilg.IfNot();
- ilg.Load(dataContractArg);
- ilg.LoadMember(serializationExceptionMessageProperty);
- ilg.Load(null);
- ilg.Call(XmlFormatGeneratorStatics.ThrowInvalidDataContractExceptionMethod);
- ilg.EndIf();
- }
- void InvokeOnSerializing(ClassDataContract classContract)
- {
- if (classContract.BaseContract != null)
- InvokeOnSerializing(classContract.BaseContract);
- if (classContract.OnSerializing != null)
- {
- ilg.LoadAddress(objectLocal);
- ilg.Load(contextArg);
- ilg.Call(XmlFormatGeneratorStatics.GetStreamingContextMethod);
- ilg.Call(classContract.OnSerializing);
- }
- }
- void InvokeOnSerialized(ClassDataContract classContract)
- {
- if (classContract.BaseContract != null)
- InvokeOnSerialized(classContract.BaseContract);
- if (classContract.OnSerialized != null)
- {
- ilg.LoadAddress(objectLocal);
- ilg.Load(contextArg);
- ilg.Call(XmlFormatGeneratorStatics.GetStreamingContextMethod);
- ilg.Call(classContract.OnSerialized);
- }
- }
- void WriteClass(ClassDataContract classContract)
- {
- InvokeOnSerializing(classContract);
- if (classContract.IsISerializable)
- ilg.Call(contextArg, XmlFormatGeneratorStatics.WriteISerializableMethod, xmlWriterArg, objectLocal);
- else
- {
- if (classContract.ContractNamespaces.Length > 1)
- {
- contractNamespacesLocal = ilg.DeclareLocal(typeof(XmlDictionaryString[]), "contractNamespaces");
- ilg.Load(dataContractArg);
- ilg.LoadMember(XmlFormatGeneratorStatics.ContractNamespacesField);
- ilg.Store(contractNamespacesLocal);
- }
- memberNamesLocal = ilg.DeclareLocal(typeof(XmlDictionaryString[]), "memberNames");
- ilg.Load(dataContractArg);
- ilg.LoadMember(XmlFormatGeneratorStatics.MemberNamesField);
- ilg.Store(memberNamesLocal);
- for (int i = 0; i < classContract.ChildElementNamespaces.Length; i++)
- {
- if (classContract.ChildElementNamespaces[i] != null)
- {
- childElementNamespacesLocal = ilg.DeclareLocal(typeof(XmlDictionaryString[]), "childElementNamespaces");
- ilg.Load(dataContractArg);
- ilg.LoadMember(XmlFormatGeneratorStatics.ChildElementNamespacesProperty);
- ilg.Store(childElementNamespacesLocal);
- }
- }
- if (classContract.HasExtensionData)
- {
- LocalBuilder extensionDataLocal = ilg.DeclareLocal(Globals.TypeOfExtensionDataObject, "extensionData");
- ilg.Load(objectLocal);
- ilg.ConvertValue(objectLocal.LocalType, Globals.TypeOfIExtensibleDataObject);
- ilg.LoadMember(XmlFormatGeneratorStatics.ExtensionDataProperty);
- ilg.Store(extensionDataLocal);
- ilg.Call(contextArg, XmlFormatGeneratorStatics.WriteExtensionDataMethod, xmlWriterArg, extensionDataLocal, -1);
- WriteMembers(classContract, extensionDataLocal, classContract);
- }
- else
- WriteMembers(classContract, null, classContract);
- }
- InvokeOnSerialized(classContract);
- }
- int WriteMembers(ClassDataContract classContract, LocalBuilder extensionDataLocal, ClassDataContract derivedMostClassContract)
- {
- int memberCount = (classContract.BaseContract == null) ? 0 :
- WriteMembers(classContract.BaseContract, extensionDataLocal, derivedMostClassContract);
- LocalBuilder namespaceLocal = ilg.DeclareLocal(typeof(XmlDictionaryString), "ns");
- if (contractNamespacesLocal == null)
- {
- ilg.Load(dataContractArg);
- ilg.LoadMember(XmlFormatGeneratorStatics.NamespaceProperty);
- }
- else
- ilg.LoadArrayElement(contractNamespacesLocal, typeIndex - 1);
- ilg.Store(namespaceLocal);
- ilg.Call(contextArg, XmlFormatGeneratorStatics.IncrementItemCountMethod, classContract.Members.Count);
- for (int i = 0; i < classContract.Members.Count; i++, memberCount++)
- {
- DataMember member = classContract.Members[i];
- Type memberType = member.MemberType;
- LocalBuilder memberValue = null;
- if (member.IsGetOnlyCollection)
- {
- ilg.Load(contextArg);
- ilg.Call(XmlFormatGeneratorStatics.StoreIsGetOnlyCollectionMethod);
- }
- if (!member.EmitDefaultValue)
- {
- memberValue = LoadMemberValue(member);
- ilg.IfNotDefaultValue(memberValue);
- }
- bool writeXsiType = CheckIfMemberHasConflict(member, classContract, derivedMostClassContract);
- if (writeXsiType || !TryWritePrimitive(memberType, memberValue, member.MemberInfo, null /*arrayItemIndex*/, namespaceLocal, null /*nameLocal*/, i + childElementIndex))
- {
- WriteStartElement(memberType, classContract.Namespace, namespaceLocal, null /*nameLocal*/, i + childElementIndex);
- if (classContract.ChildElementNamespaces[i + childElementIndex] != null)
- {
- ilg.Load(xmlWriterArg);
- ilg.LoadArrayElement(childElementNamespacesLocal, i + childElementIndex);
- ilg.Call(XmlFormatGeneratorStatics.WriteNamespaceDeclMethod);
- }
- if (memberValue == null)
- memberValue = LoadMemberValue(member);
- WriteValue(memberValue, writeXsiType);
- WriteEndElement();
- }
- if (classContract.HasExtensionData)
- ilg.Call(contextArg, XmlFormatGeneratorStatics.WriteExtensionDataMethod, xmlWriterArg, extensionDataLocal, memberCount);
- if (!member.EmitDefaultValue)
- {
- if (member.IsRequired)
- {
- ilg.Else();
- ilg.Call(null, XmlFormatGeneratorStatics.ThrowRequiredMemberMustBeEmittedMethod, member.Name, classContract.UnderlyingType);
- }
- ilg.EndIf();
- }
- }
- typeIndex++;
- childElementIndex += classContract.Members.Count;
- return memberCount;
- }
- private LocalBuilder LoadMemberValue(DataMember member)
- {
- ilg.LoadAddress(objectLocal);
- ilg.LoadMember(member.MemberInfo);
- LocalBuilder memberValue = ilg.DeclareLocal(member.MemberType, member.Name + "Value");
- ilg.Stloc(memberValue);
- return memberValue;
- }
- void WriteCollection(CollectionDataContract collectionContract)
- {
- LocalBuilder itemNamespace = ilg.DeclareLocal(typeof(XmlDictionaryString), "itemNamespace");
- ilg.Load(dataContractArg);
- ilg.LoadMember(XmlFormatGeneratorStatics.NamespaceProperty);
- ilg.Store(itemNamespace);
- LocalBuilder itemName = ilg.DeclareLocal(typeof(XmlDictionaryString), "itemName");
- ilg.Load(dataContractArg);
- ilg.LoadMember(XmlFormatGeneratorStatics.CollectionItemNameProperty);
- ilg.Store(itemName);
- if (collectionContract.ChildElementNamespace != null)
- {
- ilg.Load(xmlWriterArg);
- ilg.Load(dataContractArg);
- ilg.LoadMember(XmlFormatGeneratorStatics.ChildElementNamespaceProperty);
- ilg.Call(XmlFormatGeneratorStatics.WriteNamespaceDeclMethod);
- }
- if (collectionContract.Kind == CollectionKind.Array)
- {
- Type itemType = collectionContract.ItemType;
- LocalBuilder i = ilg.DeclareLocal(Globals.TypeOfInt, "i");
- ilg.Call(contextArg, XmlFormatGeneratorStatics.IncrementArrayCountMethod, xmlWriterArg, objectLocal);
- if (!TryWritePrimitiveArray(collectionContract.UnderlyingType, itemType, objectLocal, itemName, itemNamespace))
- {
- ilg.For(i, 0, objectLocal);
- if (!TryWritePrimitive(itemType, null /*value*/, null /*memberInfo*/, i /*arrayItemIndex*/, itemNamespace, itemName, 0 /*nameIndex*/))
- {
- WriteStartElement(itemType, collectionContract.Namespace, itemNamespace, itemName, 0 /*nameIndex*/);
- ilg.LoadArrayElement(objectLocal, i);
- LocalBuilder memberValue = ilg.DeclareLocal(itemType, "memberValue");
- ilg.Stloc(memberValue);
- WriteValue(memberValue, false /*writeXsiType*/);
- WriteEndElement();
- }
- ilg.EndFor();
- }
- }
- else
- {
- MethodInfo incrementCollectionCountMethod = null;
- switch (collectionContract.Kind)
- {
- case CollectionKind.Collection:
- case CollectionKind.List:
- case CollectionKind.Dictionary:
- incrementCollectionCountMethod = XmlFormatGeneratorStatics.IncrementCollectionCountMethod;
- break;
- case CollectionKind.GenericCollection:
- case CollectionKind.GenericList:
- incrementCollectionCountMethod = XmlFormatGeneratorStatics.IncrementCollectionCountGenericMethod.MakeGenericMethod(collectionContract.ItemType);
- break;
- case CollectionKind.GenericDictionary:
- incrementCollectionCountMethod = XmlFormatGeneratorStatics.IncrementCollectionCountGenericMethod.MakeGenericMethod(Globals.TypeOfKeyValuePair.MakeGenericType(collectionContract.ItemType.GetGenericArguments()));
- break;
- }
- if (incrementCollectionCountMethod != null)
- {
- ilg.Call(contextArg, incrementCollectionCountMethod, xmlWriterArg, objectLocal);
- }
- bool isDictionary = false, isGenericDictionary = false;
- Type enumeratorType = null;
- Type[] keyValueTypes = null;
- if (collectionContract.Kind == CollectionKind.GenericDictionary)
- {
- isGenericDictionary = true;
- keyValueTypes = collectionContract.ItemType.GetGenericArguments();
- enumeratorType = Globals.TypeOfGenericDictionaryEnumerator.MakeGenericType(keyValueTypes);
- }
- else if (collectionContract.Kind == CollectionKind.Dictionary)
- {
- isDictionary = true;
- keyValueTypes = new Type[] { Globals.TypeOfObject, Globals.TypeOfObject };
- enumeratorType = Globals.TypeOfDictionaryEnumerator;
- }
- else
- {
- enumeratorType = collectionContract.GetEnumeratorMethod.ReturnType;
- }
- MethodInfo moveNextMethod = enumeratorType.GetMethod(Globals.MoveNextMethodName, BindingFlags.Instance | BindingFlags.Public, null, Globals.EmptyTypeArray, null);
- MethodInfo getCurrentMethod = enumeratorType.GetMethod(Globals.GetCurrentMethodName, BindingFlags.Instance | BindingFlags.Public, null, Globals.EmptyTypeArray, null);
- if (moveNextMethod == null || getCurrentMethod == null)
- {
- if (enumeratorType.IsInterface)
- {
- if (moveNextMethod == null)
- moveNextMethod = XmlFormatGeneratorStatics.MoveNextMethod;
- if (getCurrentMethod == null)
- getCurrentMethod = XmlFormatGeneratorStatics.GetCurrentMethod;
- }
- else
- {
- Type ienumeratorInterface = Globals.TypeOfIEnumerator;
- CollectionKind kind = collectionContract.Kind;
- if (kind == CollectionKind.GenericDictionary || kind == CollectionKind.GenericCollection || kind == CollectionKind.GenericEnumerable)
- {
- Type[] interfaceTypes = enumeratorType.GetInterfaces();
- foreach (Type interfaceType in interfaceTypes)
- {
- if (interfaceType.IsGenericType
- && interfaceType.GetGenericTypeDefinition() == Globals.TypeOfIEnumeratorGeneric
- && interfaceType.GetGenericArguments()[0] == collectionContract.ItemType)
- {
- ienumeratorInterface = interfaceType;
- break;
- }
- }
- }
- if (moveNextMethod == null)
- moveNextMethod = CollectionDataContract.GetTargetMethodWithName(Globals.MoveNextMethodName, enumeratorType, ienumeratorInterface);
- if (getCurrentMethod == null)
- getCurrentMethod = CollectionDataContract.GetTargetMethodWithName(Globals.GetCurrentMethodName, enumeratorType, ienumeratorInterface);
- }
- }
- Type elementType = getCurrentMethod.ReturnType;
- LocalBuilder currentValue = ilg.DeclareLocal(elementType, "currentValue");
- LocalBuilder enumerator = ilg.DeclareLocal(enumeratorType, "enumerator");
- ilg.Call(objectLocal, collectionContract.GetEnumeratorMethod);
- if (isDictionary)
- {
- ilg.ConvertValue(collectionContract.GetEnumeratorMethod.ReturnType, Globals.TypeOfIDictionaryEnumerator);
- ilg.New(XmlFormatGeneratorStatics.DictionaryEnumeratorCtor);
- }
- else if (isGenericDictionary)
- {
- Type ctorParam = Globals.TypeOfIEnumeratorGeneric.MakeGenericType(Globals.TypeOfKeyValuePair.MakeGenericType(keyValueTypes));
- ConstructorInfo dictEnumCtor = enumeratorType.GetConstructor(Globals.ScanAllMembers, null, new Type[] { ctorParam }, null);
- ilg.ConvertValue(collectionContract.GetEnumeratorMethod.ReturnType, ctorParam);
- ilg.New(dictEnumCtor);
- }
- ilg.Stloc(enumerator);
- ilg.ForEach(currentValue, elementType, enumeratorType, enumerator, getCurrentMethod);
- if (incrementCollectionCountMethod == null)
- {
- ilg.Call(contextArg, XmlFormatGeneratorStatics.IncrementItemCountMethod, 1);
- }
- if (!TryWritePrimitive(elementType, currentValue, null /*memberInfo*/, null /*arrayItemIndex*/, itemNamespace, itemName, 0 /*nameIndex*/))
- {
- WriteStartElement(elementType, collectionContract.Namespace, itemNamespace, itemName, 0 /*nameIndex*/);
- if (isGenericDictionary || isDictionary)
- {
- ilg.Call(dataContractArg, XmlFormatGeneratorStatics.GetItemContractMethod);
- ilg.Load(xmlWriterArg);
- ilg.Load(currentValue);
- ilg.ConvertValue(currentValue.LocalType, Globals.TypeOfObject);
- ilg.Load(contextArg);
- ilg.Call(XmlFormatGeneratorStatics.WriteXmlValueMethod);
- }
- else
- {
- WriteValue(currentValue, false /*writeXsiType*/);
- }
- WriteEndElement();
- }
- ilg.EndForEach(moveNextMethod);
- }
- }
- bool TryWritePrimitive(Type type, LocalBuilder value, MemberInfo memberInfo, LocalBuilder arrayItemIndex, LocalBuilder ns, LocalBuilder name, int nameIndex)
- {
- PrimitiveDataContract primitiveContract = PrimitiveDataContract.GetPrimitiveDataContract(type);
- if (primitiveContract == null || primitiveContract.UnderlyingType == Globals.TypeOfObject)
- return false;
- // load xmlwriter
- if (type.IsValueType)
- {
- ilg.Load(xmlWriterArg);
- }
- else
- {
- ilg.Load(contextArg);
- ilg.Load(xmlWriterArg);
- }
- // load primitive value
- if (value != null)
- {
- ilg.Load(value);
- }
- else if (memberInfo != null)
- {
- ilg.LoadAddress(objectLocal);
- ilg.LoadMember(memberInfo);
- }
- else
- {
- ilg.LoadArrayElement(objectLocal, arrayItemIndex);
- }
- // load name
- if (name != null)
- {
- ilg.Load(name);
- }
- else
- {
- ilg.LoadArrayElement(memberNamesLocal, nameIndex);
- }
- // load namespace
- ilg.Load(ns);
- // call method to write primitive
- ilg.Call(primitiveContract.XmlFormatWriterMethod);
- return true;
- }
- bool TryWritePrimitiveArray(Type type, Type itemType, LocalBuilder value, LocalBuilder itemName, LocalBuilder itemNamespace)
- {
- PrimitiveDataContract primitiveContract = PrimitiveDataContract.GetPrimitiveDataContract(itemType);
- if (primitiveContract == null)
- return false;
- string writeArrayMethod = null;
- switch (Type.GetTypeCode(itemType))
- {
- case TypeCode.Boolean:
- writeArrayMethod = "WriteBooleanArray";
- break;
- case TypeCode.DateTime:
- writeArrayMethod = "WriteDateTimeArray";
- break;
- case TypeCode.Decimal:
- writeArrayMethod = "WriteDecimalArray";
- break;
- case TypeCode.Int32:
- writeArrayMethod = "WriteInt32Array";
- break;
- case TypeCode.Int64:
- writeArrayMethod = "WriteInt64Array";
- break;
- case TypeCode.Single:
- writeArrayMethod = "WriteSingleArray";
- break;
- case TypeCode.Double:
- writeArrayMethod = "WriteDoubleArray";
- break;
- default:
- break;
- }
- if (writeArrayMethod != null)
- {
- ilg.Load(xmlWriterArg);
- ilg.Load(value);
- ilg.Load(itemName);
- ilg.Load(itemNamespace);
- ilg.Call(typeof(XmlWriterDelegator).GetMethod(writeArrayMethod, Globals.ScanAllMembers, null, new Type[] { type, typeof(XmlDictionaryString), typeof(XmlDictionaryString) }, null));
- return true;
- }
- return false;
- }
- void WriteValue(LocalBuilder memberValue, bool writeXsiType)
- {
- Type memberType = memberValue.LocalType;
- if (memberType.IsPointer)
- {
- ilg.Load(memberValue);
- ilg.Load(memberType);
- ilg.Call(XmlFormatGeneratorStatics.BoxPointer);
- memberType = Globals.TypeOfReflectionPointer;
- memberValue = ilg.DeclareLocal(memberType, "memberValueRefPointer");
- ilg.Store(memberValue);
- }
- bool isNullableOfT = (memberType.IsGenericType &&
- memberType.GetGenericTypeDefinition() == Globals.TypeOfNullable);
- if (memberType.IsValueType && !isNullableOfT)
- {
- PrimitiveDataContract primitiveContract = PrimitiveDataContract.GetPrimitiveDataContract(memberType);
- if (primitiveContract != null && !writeXsiType)
- ilg.Call(xmlWriterArg, primitiveContract.XmlFormatContentWriterMethod, memberValue);
- else
- InternalSerialize(XmlFormatGeneratorStatics.InternalSerializeMethod, memberValue, memberType, writeXsiType);
- }
- else
- {
- if (isNullableOfT)
- {
- memberValue = UnwrapNullableObject(memberValue); //Leaves !HasValue on stack
- memberType = memberValue.LocalType;
- }
- else
- {
- ilg.Load(memberValue);
- ilg.Load(null);
- ilg.Ceq();
- }
- ilg.If();
- ilg.Call(contextArg, XmlFormatGeneratorStatics.WriteNullMethod, xmlWriterArg, memberType, DataContract.IsTypeSerializable(memberType));
- ilg.Else();
- PrimitiveDataContract primitiveContract = PrimitiveDataContract.GetPrimitiveDataContract(memberType);
- if (primitiveContract != null && primitiveContract.UnderlyingType != Globals.TypeOfObject && !writeXsiType)
- {
- if (isNullableOfT)
- {
- ilg.Call(xmlWriterArg, primitiveContract.XmlFormatContentWriterMethod, memberValue);
- }
- else
- {
- ilg.Call(contextArg, primitiveContract.XmlFormatContentWriterMethod, xmlWriterArg, memberValue);
- }
- }
- else
- {
- if (memberType == Globals.TypeOfObject || //boxed Nullable<T>
- memberType == Globals.TypeOfValueType ||
- ((IList)Globals.TypeOfNullable.GetInterfaces()).Contains(memberType))
- {
- ilg.Load(memberValue);
- ilg.ConvertValue(memberValue.LocalType, Globals.TypeOfObject);
- memberValue = ilg.DeclareLocal(Globals.TypeOfObject, "unwrappedMemberValue");
- memberType = memberValue.LocalType;
- ilg.Stloc(memberValue);
- ilg.If(memberValue, Cmp.EqualTo, null);
- ilg.Call(contextArg, XmlFormatGeneratorStatics.WriteNullMethod, xmlWriterArg, memberType, DataContract.IsTypeSerializable(memberType));
- ilg.Else();
- }
- InternalSerialize((isNullableOfT ? XmlFormatGeneratorStatics.InternalSerializeMethod : XmlFormatGeneratorStatics.InternalSerializeReferenceMethod),
- memberValue, memberType, writeXsiType);
- if (memberType == Globals.TypeOfObject) //boxed Nullable<T>
- ilg.EndIf();
- }
- ilg.EndIf();
- }
- }
- void InternalSerialize(MethodInfo methodInfo, LocalBuilder memberValue, Type memberType, bool writeXsiType)
- {
- ilg.Load(contextArg);
- ilg.Load(xmlWriterArg);
- ilg.Load(memberValue);
- ilg.ConvertValue(memberValue.LocalType, Globals.TypeOfObject);
- LocalBuilder typeHandleValue = ilg.DeclareLocal(typeof(RuntimeTypeHandle), "typeHandleValue");
- ilg.Call(null, typeof(Type).GetMethod("GetTypeHandle"), memberValue);
- ilg.Stloc(typeHandleValue);
- ilg.LoadAddress(typeHandleValue);
- ilg.Ldtoken(memberType);
- ilg.Call(typeof(RuntimeTypeHandle).GetMethod("Equals", new Type[] { typeof(RuntimeTypeHandle) }));
- ilg.Load(writeXsiType);
- ilg.Load(DataContract.GetId(memberType.TypeHandle));
- ilg.Ldtoken(memberType);
- ilg.Call(methodInfo);
- }
- LocalBuilder UnwrapNullableObject(LocalBuilder memberValue)// Leaves !HasValue on stack
- {
- Type memberType = memberValue.LocalType;
- Label onNull = ilg.DefineLabel();
- Label end = ilg.DefineLabel();
- ilg.Load(memberValue);
- while (memberType.IsGenericType && memberType.GetGenericTypeDefinition() == Globals.TypeOfNullable)
- {
- Type innerType = memberType.GetGenericArguments()[0];
- ilg.Dup();
- ilg.Call(XmlFormatGeneratorStatics.GetHasValueMethod.MakeGenericMethod(innerType));
- ilg.Brfalse(onNull);
- ilg.Call(XmlFormatGeneratorStatics.GetNullableValueMethod.MakeGenericMethod(innerType));
- memberType = innerType;
- }
- memberValue = ilg.DeclareLocal(memberType, "nullableUnwrappedMemberValue");
- ilg.Stloc(memberValue);
- ilg.Load(false); //isNull
- ilg.Br(end);
- ilg.MarkLabel(onNull);
- ilg.Pop();
- ilg.Call(XmlFormatGeneratorStatics.GetDefaultValueMethod.MakeGenericMethod(memberType));
- ilg.Stloc(memberValue);
- ilg.Load(true); //isNull
- ilg.MarkLabel(end);
- return memberValue;
- }
- bool NeedsPrefix(Type type, XmlDictionaryString ns)
- {
- return type == Globals.TypeOfXmlQualifiedName && (ns != null && ns.Value != null && ns.Value.Length > 0);
- }
- void WriteStartElement(Type type, XmlDictionaryString ns, LocalBuilder namespaceLocal, LocalBuilder nameLocal, int nameIndex)
- {
- bool needsPrefix = NeedsPrefix(type, ns);
- ilg.Load(xmlWriterArg);
- // prefix
- if (needsPrefix)
- ilg.Load(Globals.ElementPrefix);
- // localName
- if (nameLocal == null)
- ilg.LoadArrayElement(memberNamesLocal, nameIndex);
- else
- ilg.Load(nameLocal);
- // namespace
- ilg.Load(namespaceLocal);
- ilg.Call(needsPrefix ? XmlFormatGeneratorStatics.WriteStartElementMethod3 : XmlFormatGeneratorStatics.WriteStartElementMethod2);
- }
- void WriteEndElement()
- {
- ilg.Call(xmlWriterArg, XmlFormatGeneratorStatics.WriteEndElementMethod);
- }
- bool CheckIfMemberHasConflict(DataMember member, ClassDataContract classContract, ClassDataContract derivedMostClassContract)
- {
- // Check for conflict with base type members
- if (CheckIfConflictingMembersHaveDifferentTypes(member))
- return true;
- // Check for conflict with derived type members
- string name = member.Name;
- string ns = classContract.StableName.Namespace;
- ClassDataContract currentContract = derivedMostClassContract;
- while (currentContract != null && currentContract != classContract)
- {
- if (ns == currentContract.StableName.Namespace)
- {
- List<DataMember> members = currentContract.Members;
- for (int j = 0; j < members.Count; j++)
- {
- if (name == members[j].Name)
- return CheckIfConflictingMembersHaveDifferentTypes(members[j]);
- }
- }
- currentContract = currentContract.BaseContract;
- }
- return false;
- }
- bool CheckIfConflictingMembersHaveDifferentTypes(DataMember member)
- {
- while (member.ConflictingMember != null)
- {
- if (member.MemberType != member.ConflictingMember.MemberType)
- return true;
- member = member.ConflictingMember;
- }
- return false;
- }
- #if NotUsed
- static Hashtable nsToPrefixTable = new Hashtable(4);
- internal static string GetPrefix(string ns)
- {
- string prefix = (string)nsToPrefixTable[ns];
- if (prefix == null)
- {
- lock (nsToPrefixTable)
- {
- if (prefix == null)
- {
- prefix = "p" + nsToPrefixTable.Count;
- nsToPrefixTable.Add(ns, prefix);
- }
- }
- }
- return prefix;
- }
- #endif
- }
- #endif
- }
- }
|