Paradox Game Engine  v1.0.0 beta06
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros Pages
CecilSerializerContext.cs
Go to the documentation of this file.
1 // Copyright (c) 2014 Silicon Studio Corp. (http://siliconstudio.co.jp)
2 // This file is distributed under GPL v3. See LICENSE.md for details.
3 using System;
4 using System.Collections.Generic;
5 using System.Linq;
6 using System.Runtime.Remoting.Contexts;
7 using Mono.Cecil;
8 using Mono.Cecil.Cil;
9 using SiliconStudio.Core.Serialization.Serializers;
10 
11 namespace SiliconStudio.AssemblyProcessor.Serializers
12 {
13  internal class CecilSerializerContext
14  {
15  public CecilSerializerContext(AssemblyDefinition assembly)
16  {
17  Assembly = assembly;
18  SerializableTypesProfiles = new Dictionary<string, ProfileInfo>();
19  SerializableTypes = new ProfileInfo();
20  SerializableTypesProfiles.Add("Default", SerializableTypes);
21  ComplexTypes = new Dictionary<TypeDefinition, SerializableTypeInfo>();
22 
23  SiliconStudioCoreAssembly = assembly.Name.Name == "SiliconStudio.Core"
24  ? assembly
25  : assembly.MainModule.AssemblyResolver.Resolve("SiliconStudio.Core");
26  }
27 
28  /// <summary>
29  /// Gets the assembly being processed.
30  /// </summary>
31  /// <value>
32  /// The assembly being processed.
33  /// </value>
34  public AssemblyDefinition Assembly { get; private set; }
35 
36  public AssemblyDefinition SiliconStudioCoreAssembly { get; private set; }
37 
38  /// <summary>
39  /// Gets the list of serializable type grouped by profile.
40  /// </summary>
41  /// <value>
42  /// The serializable types profiles.
43  /// </value>
44  public Dictionary<string, ProfileInfo> SerializableTypesProfiles { get; private set; }
45 
46  /// <summary>
47  /// Gets the set of type that can be serialized (key) with their serializer name (string), corresponding to the "Default" profile.
48  /// </summary>
49  public ProfileInfo SerializableTypes { get; private set; }
50 
51  /// <summary>
52  /// Gets the list of complex serializers to generate.
53  /// </summary>
54  /// <value>
55  /// The list of complex serializers to generate.
56  /// </value>
57  public Dictionary<TypeDefinition, SerializableTypeInfo> ComplexTypes { get; private set; }
58 
59  /// <summary>
60  /// Ensure the following type can be serialized. If not, try to register appropriate serializer.
61  /// This method can be recursive.
62  /// </summary>
63  /// <param name="type">The type.</param>
64  public SerializableTypeInfo GenerateSerializer(TypeReference type, bool force = true, string profile = "Default", bool generic = false)
65  {
66  var serializableTypes = GetSerializableTypes(profile);
67 
68  // Already handled?
69  SerializableTypeInfo serializableTypeInfo;
70  if (serializableTypes.TryGetSerializableTypeInfo(type, generic, out serializableTypeInfo))
71  return serializableTypeInfo;
72 
73  // Try to get one without generic
74  if (generic && serializableTypes.TryGetSerializableTypeInfo(type, false, out serializableTypeInfo))
75  return serializableTypeInfo;
76 
77  // TDOO: Array, List, Generic types, etc... (equivalent of previous serializer factories)
78  var arrayType = type as ArrayType;
79  if (arrayType != null)
80  {
81  // Only proceed if element type is serializable (and in Default profile, otherwise ElementType is enough)
82  if (GenerateSerializer(arrayType.ElementType, force, profile) != null)
83  {
84  if (profile == "Default")
85  {
86  var arraySerializerType = SiliconStudioCoreAssembly.MainModule.GetTypeResolved("SiliconStudio.Core.Serialization.Serializers.ArraySerializer`1");
87  var serializerType = new GenericInstanceType(arraySerializerType);
88  serializerType.GenericArguments.Add(arrayType.ElementType);
89  AddSerializableType(type, serializableTypeInfo = new SerializableTypeInfo(serializerType, true), profile);
90  return serializableTypeInfo;
91  }
92  else
93  {
94  // Fallback to default
95  return GenerateSerializer(type, force, "Default");
96  }
97  }
98 
99  return null;
100  }
101 
102  // Try to match with existing generic serializer (for List, Dictionary, etc...)
103  var genericInstanceType = type as GenericInstanceType;
104  if (genericInstanceType != null)
105  {
106  var elementType = genericInstanceType.ElementType;
107  SerializableTypeInfo elementSerializableTypeInfo;
108  if ((elementSerializableTypeInfo = GenerateSerializer(elementType, false, profile, true)) != null)
109  {
110  switch (elementSerializableTypeInfo.Mode)
111  {
112  case DataSerializerGenericMode.Type:
113  {
114  var serializerType = new GenericInstanceType(elementSerializableTypeInfo.SerializerType);
115  serializerType.GenericArguments.Add(type);
116 
117  AddSerializableType(type, serializableTypeInfo = new SerializableTypeInfo(serializerType, true) { ComplexSerializer = elementSerializableTypeInfo.ComplexSerializer }, profile);
118  break;
119  }
120  case DataSerializerGenericMode.TypeAndGenericArguments:
121  {
122  var serializerType = new GenericInstanceType(elementSerializableTypeInfo.SerializerType);
123  serializerType.GenericArguments.Add(type);
124  foreach (var genericArgument in genericInstanceType.GenericArguments)
125  {
126  // Generate serializer for each generic argument
127  //GenerateSerializer(genericArgument);
128 
129  serializerType.GenericArguments.Add(genericArgument);
130  }
131 
132  AddSerializableType(type, serializableTypeInfo = new SerializableTypeInfo(serializerType, true) { ComplexSerializer = elementSerializableTypeInfo.ComplexSerializer }, profile);
133  break;
134  }
135  case DataSerializerGenericMode.GenericArguments:
136  {
137  var serializerType = new GenericInstanceType(elementSerializableTypeInfo.SerializerType);
138  foreach (var genericArgument in genericInstanceType.GenericArguments)
139  {
140  // Generate serializer for each generic argument
141  //GenerateSerializer(genericArgument);
142 
143  serializerType.GenericArguments.Add(genericArgument);
144  }
145 
146  AddSerializableType(type, serializableTypeInfo = new SerializableTypeInfo(serializerType, true) { ComplexSerializer = elementSerializableTypeInfo.ComplexSerializer }, profile);
147  break;
148  }
149  default:
150  throw new NotImplementedException();
151  }
152 
153  if (elementSerializableTypeInfo.ComplexSerializer)
154  {
155  ProcessComplexSerializerMembers(type, serializableTypeInfo);
156  }
157  return serializableTypeInfo;
158  }
159  }
160 
161  // Check complex type definitions
162  if (profile == "Default" && (serializableTypeInfo = FindSerializerInfo(type, generic)) != null)
163  {
164  return serializableTypeInfo;
165  }
166 
167  // Fallback to default
168  if (profile != "Default")
169  return GenerateSerializer(type, force, "Default", generic);
170 
171  // Part after that is only if a serializer is absolutely necessary. This is skipped when scanning normal assemblies type that might have nothing to do with serialization.
172  if (!force)
173  return null;
174 
175  // Non instantiable type? (object, interfaces, abstract classes)
176  // Serializer can be null since they will be inherited anyway (handled through MemberSerializer)
177  var resolvedType = type.Resolve();
178  if (resolvedType.IsAbstract || resolvedType.IsAbstract || resolvedType.FullName == typeof(object).FullName)
179  {
180  AddSerializableType(type, serializableTypeInfo = new SerializableTypeInfo(null, true), profile);
181  return serializableTypeInfo;
182  }
183 
184  return null;
185  }
186 
187  private void ProcessComplexSerializerMembers(TypeReference type, SerializableTypeInfo serializableTypeInfo, string profile = "Default")
188  {
189  // Process base type (for complex serializers)
190  // If it's a closed type and there is a serializer, we'll serialize parent
191  SerializableTypeInfo parentSerializableTypeInfo;
192  var parentType = ResolveGenericsVisitor.Process(type, type.Resolve().BaseType);
193  if (!parentType.ContainsGenericParameter() && (parentSerializableTypeInfo = GenerateSerializer(parentType, false, profile)) != null &&
194  parentSerializableTypeInfo.SerializerType != null)
195  {
196  serializableTypeInfo.ComplexSerializerProcessParentType = true;
197  }
198 
199  // Process members
200  foreach (var serializableItem in ComplexClassSerializerGenerator.GetSerializableItems(type, true))
201  {
202  // Check that all closed types have a proper serializer
203  if (!serializableItem.Type.ContainsGenericParameter() && GenerateSerializer(serializableItem.Type, profile: profile) == null
204  && !serializableItem.Attributes.Any(x => x.AttributeType.FullName == "SiliconStudio.Core.DataMemberCustomSerializerAttribute"))
205  {
206  throw new InvalidOperationException(string.Format("Member {0} (type: {1}) doesn't seem to have a valid serializer.", serializableItem.MemberInfo, serializableItem.Type.ConvertCSharp()));
207  }
208  }
209  }
210 
211  /// <summary>
212  /// Finds the serializer information.
213  /// </summary>
214  /// <param name="type">The type.</param>
215  /// <param name="generic">If set to true, when using <see cref="DataSerializerGenericMode.Type"/>, it will returns the generic version instead of actual type one.</param>
216  /// <returns></returns>
217  /// <exception cref="System.InvalidOperationException">Not sure how to process this inherited serializer</exception>
218  internal SerializableTypeInfo FindSerializerInfo(TypeReference type, bool generic)
219  {
220  if (type == null || type.FullName == typeof(object).FullName || type.FullName == typeof(ValueType).FullName || type.IsGenericParameter)
221  return null;
222 
223  var resolvedType = type.Resolve();
224 
225  // Nested type
226  if (resolvedType.IsNested)
227  {
228  // Check public/private flags
229  if (!resolvedType.IsNestedPublic && !resolvedType.IsNestedAssembly)
230  return null;
231  }
232 
233  if (resolvedType.IsEnum)
234  {
235  // Enum
236  // Let's generate a EnumSerializer
237  var enumSerializerType = SiliconStudioCoreAssembly.MainModule.GetTypeResolved("SiliconStudio.Core.Serialization.Serializers.EnumSerializer`1");
238  var serializerType = new GenericInstanceType(enumSerializerType);
239  serializerType.GenericArguments.Add(type);
240 
241  var serializableTypeInfo = new SerializableTypeInfo(serializerType, true, DataSerializerGenericMode.None);
242  AddSerializableType(type, serializableTypeInfo);
243  return serializableTypeInfo;
244  }
245 
246  // 1. Check if there is a Serializable attribute
247  // Note: Not anymore since we don't want all system types to have unknown complex serializers.
248  //if (((resolvedType.Attributes & TypeAttributes.Serializable) == TypeAttributes.Serializable) || resolvedType.CustomAttributes.Any(x => x.AttributeType.FullName == typeof(SerializableAttribute).FullName))
249  //{
250  // serializerInfo.Serializable = true;
251  // serializerInfo.ComplexSerializer = true;
252  // serializerInfo.ComplexSerializerName = SerializerTypeName(resolvedType);
253  // return serializerInfo;
254  //}
255 
256  // 2.1. Check if there is DataSerializerAttribute on this type (if yes, it is serializable, but not a "complex type")
257  var dataSerializerAttribute =
258  resolvedType.CustomAttributes.FirstOrDefault(
259  x => x.AttributeType.FullName == "SiliconStudio.Core.Serialization.Serializers.DataSerializerAttribute");
260  if (dataSerializerAttribute != null)
261  {
262  var modeField = dataSerializerAttribute.Fields.FirstOrDefault(x => x.Name == "Mode");
263  var mode = (modeField.Name != null) ? (DataSerializerGenericMode)modeField.Argument.Value : DataSerializerGenericMode.None;
264 
265  // TODO: Replace with ResolveGenericsVisitor
266  var dataSerializerType = ((TypeReference)dataSerializerAttribute.ConstructorArguments[0].Value);
267  if (mode == DataSerializerGenericMode.Type || (mode == DataSerializerGenericMode.TypeAndGenericArguments && type is GenericInstanceType))
268  {
269  var genericSerializableTypeInfo = new SerializableTypeInfo(dataSerializerType, true, mode) { Inherited = true };
270  AddSerializableType(type, genericSerializableTypeInfo);
271 
272  var actualSerializerType = new GenericInstanceType(dataSerializerType);
273 
274  // Add Type as generic arguments
275  actualSerializerType.GenericArguments.Add(type);
276 
277  // If necessary, add generic arguments too
278  if (mode == DataSerializerGenericMode.TypeAndGenericArguments)
279  {
280  foreach (var genericArgument in ((GenericInstanceType)type).GenericArguments)
281  {
282  actualSerializerType.GenericArguments.Add(genericArgument);
283  }
284  }
285 
286  // Special case for GenericMode == DataSerializerGenericMode.Type: we store actual serializer instantiation in SerializerType (alongside the generic version in GenericSerializerType).
287  var serializableTypeInfo = new SerializableTypeInfo(actualSerializerType, true);
288  AddSerializableType(type, serializableTypeInfo);
289 
290  if (!generic)
291  return serializableTypeInfo;
292 
293  return genericSerializableTypeInfo;
294  }
295  else
296  {
297  var serializableTypeInfo = new SerializableTypeInfo(dataSerializerType, true, mode) { Inherited = false };
298  AddSerializableType(type, serializableTypeInfo);
299  return serializableTypeInfo;
300  }
301  }
302 
303  // 2.2. Check if SerializableExtendedAttribute is set on this class, or any of its base class with ApplyHierarchy
304  var serializableExtendedAttribute =
305  resolvedType.CustomAttributes.FirstOrDefault(
306  x => x.AttributeType.FullName == "SiliconStudio.Core.DataContractAttribute");
307  if (dataSerializerAttribute == null && serializableExtendedAttribute != null)
308  {
309  // CHeck if ApplyHierarchy is active, otherwise it needs to be the exact type.
310  var inherited = serializableExtendedAttribute.Properties.Where(x => x.Name == "Inherited")
311  .Select(x => (bool)x.Argument.Value)
312  .FirstOrDefault();
313 
314  var serializableTypeInfo = CreateComplexSerializer(type);
315  serializableTypeInfo.Inherited = inherited;
316 
317  // Process members
318  ProcessComplexSerializerMembers(type, serializableTypeInfo);
319 
320  return serializableTypeInfo;
321  }
322 
323  // Check if parent type contains Inherited attribute
324  var parentType = ResolveGenericsVisitor.Process(type, type.Resolve().BaseType);
325  if (parentType != null)
326  {
327  // Generate serializer for parent type
328  var parentSerializableInfoType = GenerateSerializer(parentType.Resolve(), false, generic: true);
329 
330  // If Inherited flag is on, we also generate a serializer for this type
331  if (parentSerializableInfoType != null && parentSerializableInfoType.Inherited)
332  {
333  if (parentSerializableInfoType.ComplexSerializer)
334  {
335  var serializableTypeInfo = CreateComplexSerializer(type);
336  serializableTypeInfo.Inherited = true;
337 
338  // Process members
339  ProcessComplexSerializerMembers(type, serializableTypeInfo);
340 
341  return serializableTypeInfo;
342  }
343  else if (parentSerializableInfoType.Mode == DataSerializerGenericMode.Type || parentSerializableInfoType.Mode == DataSerializerGenericMode.TypeAndGenericArguments)
344  {
345  // Register generic version
346  var genericSerializableTypeInfo = new SerializableTypeInfo(parentSerializableInfoType.SerializerType, true, parentSerializableInfoType.Mode);
347  AddSerializableType(type, genericSerializableTypeInfo);
348 
349  if (!type.HasGenericParameters)
350  {
351  var actualSerializerType = new GenericInstanceType(parentSerializableInfoType.SerializerType);
352 
353  // Add Type as generic arguments
354  actualSerializerType.GenericArguments.Add(type);
355 
356  // If necessary, add generic arguments too
357  if (parentSerializableInfoType.Mode == DataSerializerGenericMode.TypeAndGenericArguments)
358  {
359  foreach (var genericArgument in ((GenericInstanceType)parentType).GenericArguments)
360  {
361  actualSerializerType.GenericArguments.Add(genericArgument);
362  }
363  }
364 
365  // Register actual type
366  var serializableTypeInfo = new SerializableTypeInfo(actualSerializerType, true);
367  AddSerializableType(type, serializableTypeInfo);
368 
369  if (!generic)
370  return serializableTypeInfo;
371  }
372 
373  return genericSerializableTypeInfo;
374  }
375  else
376  {
377  throw new InvalidOperationException("Not sure how to process this inherited serializer");
378  }
379  }
380  }
381 
382  return null;
383  }
384 
385  private SerializableTypeInfo CreateComplexSerializer(TypeReference type)
386  {
387  // Create a fake TypeReference (even though it doesn't really exist yet, but at least ConvertCSharp to get its name will work).
388  var dataSerializerType = new TypeReference("SiliconStudio.DataSerializers",
389  ComplexClassSerializerGenerator.SerializerTypeName(type, false, true), type.Module, type.Scope);
390  var mode = DataSerializerGenericMode.None;
391  if (type.HasGenericParameters)
392  {
393  mode = DataSerializerGenericMode.GenericArguments;
394 
395  // Clone generic parameters
396  foreach (var genericParameter in type.GenericParameters)
397  {
398  var newGenericParameter = new GenericParameter(genericParameter.Name, dataSerializerType)
399  {
400  Attributes = genericParameter.Attributes
401  };
402 
403  // Clone type constraints (others will be in Attributes)
404  foreach (var constraint in genericParameter.Constraints)
405  newGenericParameter.Constraints.Add(constraint);
406 
407  dataSerializerType.GenericParameters.Add(newGenericParameter);
408  }
409  }
410 
411  var isLocal = type.Resolve().Module.Assembly == Assembly;
412  var serializableTypeInfo = new SerializableTypeInfo(dataSerializerType, true, mode);
413  serializableTypeInfo.Local = type.Resolve().Module.Assembly == Assembly;
414  AddSerializableType(type, serializableTypeInfo);
415 
416  if (isLocal && type is TypeDefinition)
417  {
418  ComplexTypes.Add((TypeDefinition)type, serializableTypeInfo);
419  }
420 
421  serializableTypeInfo.ComplexSerializer = true;
422 
423  return serializableTypeInfo;
424  }
425 
426  public void AddSerializableType(TypeReference dataType, SerializableTypeInfo serializableTypeInfo, string profile = "Default")
427  {
428  SerializableTypeInfo currentValue;
429 
430  // Check if declaring type is generics
431  var resolvedType = dataType.Resolve();
432  if (resolvedType != null && resolvedType.DeclaringType != null && (resolvedType.HasGenericParameters || resolvedType.DeclaringType.HasGenericParameters))
433  throw new NotSupportedException(String.Format("Serialization of nested types referencing parent's generic parameters is not currently supported. " +
434  "[Nested type={0} Parent={1}]", resolvedType.FullName, resolvedType.DeclaringType));
435 
436  var profileInfo = GetSerializableTypes(profile);
437 
438  if (profileInfo.TryGetSerializableTypeInfo(dataType, serializableTypeInfo.Mode != DataSerializerGenericMode.None, out currentValue))
439  {
440  // TODO: Doesn't work in some generic case
441  if (//currentValue.SerializerType.ConvertCSharp() != serializableTypeInfo.SerializerType.ConvertCSharp() ||
442  currentValue.Mode != serializableTypeInfo.Mode)
443  throw new InvalidOperationException(string.Format("Incompatible serializer found for same type in different assemblies for {0}", dataType.ConvertCSharp()));
444  return;
445  }
446 
447  // Check that we don't simply try to add the same serializer than Default profile (optimized)
448  SerializableTypeInfo defaultValue;
449  if (profile != "Default" && SerializableTypes.TryGetSerializableTypeInfo(dataType, serializableTypeInfo.Mode != DataSerializerGenericMode.None, out defaultValue))
450  {
451  if (defaultValue.SerializerType.FullName == serializableTypeInfo.SerializerType.FullName)
452  {
453  // Already added in default profile, early exit
454  return;
455  }
456  }
457 
458  profileInfo.AddSerializableTypeInfo(dataType, serializableTypeInfo);
459 
460  // Scan and add dependencies (stored in EnumerateGenericInstantiations() functions).
461  if (serializableTypeInfo.Local && serializableTypeInfo.SerializerType != null)
462  {
463  var resolvedSerializerType = serializableTypeInfo.SerializerType.Resolve();
464  if (resolvedSerializerType != null)
465  {
466  var enumerateGenericInstantiationsMethod = resolvedSerializerType.Methods.FirstOrDefault(x => x.Name == "EnumerateGenericInstantiations");
467  if (enumerateGenericInstantiationsMethod != null)
468  {
469  // Detect all ldtoken (attributes would have been better, but unfortunately C# doesn't allow generics in attributes)
470  foreach (var inst in enumerateGenericInstantiationsMethod.Body.Instructions)
471  {
472  if (inst.OpCode.Code == Code.Ldtoken)
473  {
474  var type = (TypeReference)inst.Operand;
475 
476  // Try to "close" generics type with serializer type as a context
477  var dependentType = ResolveGenericsVisitor.Process(serializableTypeInfo.SerializerType, type);
478  if (!dependentType.ContainsGenericParameter())
479  {
480  // Import type so that it becomes local to the assembly
481  // (otherwise SerializableTypeInfo.Local will be false and it won't be instantiated)
482  var importedType = Assembly.MainModule.Import(dependentType);
483  if (GenerateSerializer(importedType) == null)
484  {
485  throw new InvalidOperationException(string.Format("Could not find serializer for generic dependent type {0}", dependentType));
486  }
487  }
488  }
489  }
490  }
491  }
492  }
493  }
494 
495  private ProfileInfo GetSerializableTypes(string profile)
496  {
497  ProfileInfo profileInfo;
498  if (!SerializableTypesProfiles.TryGetValue(profile, out profileInfo))
499  {
500  profileInfo = new ProfileInfo();
501  SerializableTypesProfiles.Add(profile, profileInfo);
502  }
503  return profileInfo;
504  }
505 
506  internal class SerializableTypeInfo
507  {
508  public TypeReference SerializerType { get; internal set; }
509  public DataSerializerGenericMode Mode { get; internal set; }
510 
511  // True if type is created in current assembly
512  public bool Local;
513 
514  // True if the serializer is defined manually by a hand-written DataSerializerGlobalAttribute in current assembly
515  public bool ExistingLocal;
516 
517  /// <summary>
518  /// True if serializer is inherited (i.e. DataSerializer(Inherited == true)).
519  /// </summary>
520  public bool Inherited;
521 
522  /// <summary>
523  /// True if it's a complex serializer.
524  /// </summary>
525  public bool ComplexSerializer;
526 
527  /// <summary>
528  /// True if it's a complex serializer and its base class should be serialized too.
529  /// </summary>
530  public bool ComplexSerializerProcessParentType;
531 
532  public SerializableTypeInfo(TypeReference serializerType, bool local, DataSerializerGenericMode mode = DataSerializerGenericMode.None)
533  {
534  SerializerType = serializerType;
535  Mode = mode;
536  Local = local;
537  }
538  }
539 
540  public class ProfileInfo
541  {
542  /// <summary>
543  /// Serializable types (Mode is always None).
544  /// </summary>
545  public Dictionary<TypeReference, SerializableTypeInfo> SerializableTypes = new Dictionary<TypeReference, SerializableTypeInfo>(TypeReferenceEqualityComparer.Default);
546 
547  /// <summary>
548  /// Generic serializable types.
549  /// </summary>
550  public Dictionary<TypeReference, SerializableTypeInfo> GenericSerializableTypes = new Dictionary<TypeReference, SerializableTypeInfo>(TypeReferenceEqualityComparer.Default);
551 
552  public bool TryGetSerializableTypeInfo(TypeReference type, bool generic, out SerializableTypeInfo result)
553  {
554  return generic
555  ? GenericSerializableTypes.TryGetValue(type, out result)
556  : SerializableTypes.TryGetValue(type, out result);
557  }
558 
559  public void AddSerializableTypeInfo(TypeReference typeReference, SerializableTypeInfo serializableTypeInfo)
560  {
561  if (serializableTypeInfo.Mode != DataSerializerGenericMode.None)
562  GenericSerializableTypes.Add(typeReference, serializableTypeInfo);
563  else
564  SerializableTypes.Add(typeReference, serializableTypeInfo);
565  }
566  }
567  }
568 }
DataSerializerGenericMode
Defines what generic parameters to pass to the serializer.
bool TryGetSerializableTypeInfo(TypeReference type, bool generic, out SerializableTypeInfo result)
void AddSerializableTypeInfo(TypeReference typeReference, SerializableTypeInfo serializableTypeInfo)