I have changed my serialization to DataContracts but now I am having problem with a specific class. It works fine on my Mac, but not on my android devices when built using IL2CPP. The thread stops at the writeObject function. My three classes related to the error:
[DataContract]
[KnownType(typeof(TaskIdentifier))]
[KnownType(typeof(TraceableTaskItem))]
[KnownType(typeof(List<TraceableTaskItem>))]
public class TraceableTaskContainer
{
[DataMember]
protected TaskIdentifier _taskIdent;
[DataMember]
protected List<TraceableTaskItem> _lNotAccomplishedTaskItems = new List<TraceableTaskItem>();
//.....
}
[DataContract]
[KnownType(typeof(DateTime))]
[KnownType(typeof(ItemReviewStage))]
public class TraceableTaskItem : GenericTaskItem, IEquatable<TraceableTaskItem>, IComparable<TraceableTaskItem>
{
[DataMember]
public string sDisplayTextInTraceableTaskReport;
[DataMember]
protected DateTime NextReviewDate;
[DataMember] //ItemReviewStage is a enum
protected ItemReviewStage reviewStage = ItemReviewStage.NewTask;
public TraceableTaskItem() //important to deserialize old classes, do not remove it
{
}
//....
}
[DataContract]
//[KnownType(typeof(List<bool>))]
abstract public class GenericTaskItem
{
[DataMember]
public string sItemID = "";
//[DataMember]
protected List<bool> lTimesAnsweredCorrectly = new List<bool>();
protected List<List<string>> llWrongAnswers = new List<List<string>>();
//...
}
The code works with the commented lines above. But as soon as I uncomment DataMember on the lTimesAnsweredCorrely and with or without uncommenting the equivalent KnownType line (I have tested both), the code stops working on my mobile devices. Any idea how can I fix this?
Exception:
"System.Reflection.TargetInvocationException:
Exception has been thrown by the target of an invocation.
---> System.ExecutionEngineException: Attempting to call method \'System.Runtime.Serialization.XmlObjectSerializerWriteContext::
IncrementCollectionCountGeneric<System.Boolean>\'
for which no ahead of time (AOT) code was generated.\n at
System.Reflection.MonoMethod.Invoke (System.Object obj,
System.Reflection.BindingFlags invokeAttr,
System.Reflection.Binder binder, System.Object[] parameters,
System.Globalization.CultureInfo culture) [0x00000]
in <00000000000000000000000000000000>:0 \n at
System.Reflection.MethodBase.Invoke (System.Object obj, System.Object[] parameters) [0x00000]
in <00000000000000000000000000000000>:0 \n at System.Runtime.Serialization.XmlFormatWriterInterpreter.WriteCollection (System.Runtime.Serialization.CollectionDataContract collectionContract) [0x00000]
in <00000000000000000000000000000000>:0 \n at
System.Runtime.Serialization.XmlFormatWriterInt… string
StackTrace: " at System.Reflection.MonoMethod.Invoke (System.Object obj, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) [0x00000] in <00000000000000000000000000000000>:0 \n at System.Reflection.MethodBase.Invoke (System.Object obj, System.Object[] parameters) [0x00000] in <00000000000000000000000000000000>:0 \n at System.Runtime.Serialization.XmlFormatWriterInterpreter.WriteCollection (System.Runtime.Serialization.CollectionDataContract collectionContract) [0x00000] in <00000000000000000000000000000000>:0 \n at System.Runtime.Serialization.XmlFormatWriterInterpreter.WriteCollectionToXml (System.Runtime.Serialization.XmlWriterDelegator xmlWriter, System.Object obj, System.Runtime.Serialization.XmlObjectSerializerWriteContext context, System.Runtime.Serialization.CollectionDataContract collectionContract) [0x00000] in <00000000000000000000000000000000>:0 \n at System.Runtime.Serialization.XmlForma… string
Source: "mscorlib" string
inner exception:
InnerException "System.ExecutionEngineException: Attempting to call method \'System.Runtime.Serialization.XmlObjectSerializerWriteContext::
IncrementCollectionCountGeneric<System.Boolean>\' for which no ahead of time (AOT) code was generated.\n at System.Reflection.MonoMethod.Invoke (System.Object obj, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) [0x00000] in <00000000000000000000000000000000>:0 \n at System.Reflection.MethodBase.Invoke (System.Object obj, System.Object[] parameters) [0x00000] in <00000000000000000000000000000000>:0 \n at System.Runtime.Serialization.XmlFormatWriterInterpreter.WriteCollection (System.Runtime.Serialization.CollectionDataContract collectionContract) [0x00000] in <00000000000000000000000000000000>:0 \n at System.Runtime.Serialization.XmlFormatWriterInterpreter.WriteCollectionToXml (System.Runtime.Serialization.XmlWriterDelegator xmlWriter, System.Object obj, System.Ru… System.Exception
Update
The problem seems to be with bool and int only, a List of string works just as expected.
Based on your statement
It appears that, on Android, the ahead-of-time compilation for your framework isn't generating the necessary code for the .NET internal method
XmlObjectSerializerWriteContext.IncrementCollectionCountGeneric<T>(XmlWriterDelegator xmlWriter, ICollection<T> collection)whenTis a value type such asboolorint, but it is generating the necessary code for reference types. [1]This may be a bug in the runtime or framework you are using on Android. You may want to report an issue to the vendor.
As a workaround, since collections such as
List<string>do serialize successfully, you can create surrogate collections for yourList<bool>andList<int>that appear to the serializer to be collections of strings, and perform the necessary string-to-bool (or string-to-int) conversion internally.First, define the following classes:
Now modify your type
GenericTaskItemcontain aList<bool>by adding a private surrogateXmlBoolListproperty for serialization purposes:Now the serializer will serialize
XmlBoolListas an array of reference types, specifically.Notes:
The
XmlConvertclass may be used to convert .NET primitives from and to XML values.XmlBoolListandXmlIntListare designed to have the same collection data contracts as, respectively,List<bool>andList<int>.[KnownType(typeof(T))]attributes are only required when serializing polymorphic object graphs where the actual type being serialized differs from the declared type, which is not the case in yourList<bool>andXmlBoolListproperties. See Data Contract Known Types for details.You might investigate using data contract surrogates to replace collections of value types such as
List<bool>globally rather than on a per-property basis.Demo fiddle here.
[1] This is surprising -- but not entirely surprising. The .NET runtime implements support for generics of reference types vs generics of value types very differently; see Generics in the Run Time (C# Programming Guide) for details.