4 using System.Collections.Generic;
6 using System.Runtime.Remoting.Contexts;
9 using SiliconStudio.Core.Serialization.Serializers;
11 namespace SiliconStudio.AssemblyProcessor.Serializers
13 internal class CecilSerializerContext
15 public CecilSerializerContext(AssemblyDefinition assembly)
18 SerializableTypesProfiles =
new Dictionary<string, ProfileInfo>();
19 SerializableTypes =
new ProfileInfo();
20 SerializableTypesProfiles.Add(
"Default", SerializableTypes);
21 ComplexTypes =
new Dictionary<TypeDefinition, SerializableTypeInfo>();
23 SiliconStudioCoreAssembly = assembly.Name.Name ==
"SiliconStudio.Core"
25 : assembly.MainModule.AssemblyResolver.Resolve(
"SiliconStudio.Core");
34 public AssemblyDefinition Assembly {
get;
private set; }
36 public AssemblyDefinition SiliconStudioCoreAssembly {
get;
private set; }
44 public Dictionary<string, ProfileInfo> SerializableTypesProfiles {
get;
private set; }
49 public ProfileInfo SerializableTypes {
get;
private set; }
57 public Dictionary<TypeDefinition, SerializableTypeInfo> ComplexTypes {
get;
private set; }
64 public SerializableTypeInfo GenerateSerializer(TypeReference type,
bool force =
true,
string profile =
"Default",
bool generic =
false)
66 var serializableTypes = GetSerializableTypes(profile);
69 SerializableTypeInfo serializableTypeInfo;
70 if (serializableTypes.TryGetSerializableTypeInfo(type,
generic, out serializableTypeInfo))
71 return serializableTypeInfo;
74 if (
generic && serializableTypes.TryGetSerializableTypeInfo(type,
false, out serializableTypeInfo))
75 return serializableTypeInfo;
78 var arrayType = type as ArrayType;
79 if (arrayType != null)
82 if (GenerateSerializer(arrayType.ElementType, force, profile) != null)
84 if (profile ==
"Default")
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;
95 return GenerateSerializer(type, force,
"Default");
103 var genericInstanceType = type as GenericInstanceType;
104 if (genericInstanceType != null)
106 var elementType = genericInstanceType.ElementType;
107 SerializableTypeInfo elementSerializableTypeInfo;
108 if ((elementSerializableTypeInfo = GenerateSerializer(elementType,
false, profile,
true)) != null)
110 switch (elementSerializableTypeInfo.Mode)
112 case DataSerializerGenericMode.Type:
114 var serializerType =
new GenericInstanceType(elementSerializableTypeInfo.SerializerType);
115 serializerType.GenericArguments.Add(type);
117 AddSerializableType(type, serializableTypeInfo =
new SerializableTypeInfo(serializerType,
true) { ComplexSerializer = elementSerializableTypeInfo.ComplexSerializer }, profile);
120 case DataSerializerGenericMode.TypeAndGenericArguments:
122 var serializerType =
new GenericInstanceType(elementSerializableTypeInfo.SerializerType);
123 serializerType.GenericArguments.Add(type);
124 foreach (var genericArgument
in genericInstanceType.GenericArguments)
129 serializerType.GenericArguments.Add(genericArgument);
132 AddSerializableType(type, serializableTypeInfo =
new SerializableTypeInfo(serializerType,
true) { ComplexSerializer = elementSerializableTypeInfo.ComplexSerializer }, profile);
135 case DataSerializerGenericMode.GenericArguments:
137 var serializerType =
new GenericInstanceType(elementSerializableTypeInfo.SerializerType);
138 foreach (var genericArgument
in genericInstanceType.GenericArguments)
143 serializerType.GenericArguments.Add(genericArgument);
146 AddSerializableType(type, serializableTypeInfo =
new SerializableTypeInfo(serializerType,
true) { ComplexSerializer = elementSerializableTypeInfo.ComplexSerializer }, profile);
150 throw new NotImplementedException();
153 if (elementSerializableTypeInfo.ComplexSerializer)
155 ProcessComplexSerializerMembers(type, serializableTypeInfo);
157 return serializableTypeInfo;
162 if (profile ==
"Default" && (serializableTypeInfo = FindSerializerInfo(type,
generic)) != null)
164 return serializableTypeInfo;
168 if (profile !=
"Default")
169 return GenerateSerializer(type, force,
"Default",
generic);
177 var resolvedType = type.Resolve();
178 if (resolvedType.IsAbstract || resolvedType.IsAbstract || resolvedType.FullName == typeof(
object).FullName)
180 AddSerializableType(type, serializableTypeInfo =
new SerializableTypeInfo(null,
true), profile);
181 return serializableTypeInfo;
187 private void ProcessComplexSerializerMembers(TypeReference type, SerializableTypeInfo serializableTypeInfo,
string profile =
"Default")
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)
196 serializableTypeInfo.ComplexSerializerProcessParentType =
true;
200 foreach (var serializableItem
in ComplexClassSerializerGenerator.GetSerializableItems(type,
true))
203 if (!serializableItem.Type.ContainsGenericParameter() && GenerateSerializer(serializableItem.Type, profile: profile) == null
204 && !serializableItem.Attributes.Any(x => x.AttributeType.FullName ==
"SiliconStudio.Core.DataMemberCustomSerializerAttribute"))
206 throw new InvalidOperationException(
string.Format(
"Member {0} (type: {1}) doesn't seem to have a valid serializer.", serializableItem.MemberInfo, serializableItem.Type.ConvertCSharp()));
218 internal SerializableTypeInfo FindSerializerInfo(TypeReference type,
bool generic)
220 if (type == null || type.FullName == typeof(
object).FullName || type.FullName == typeof(ValueType).FullName || type.IsGenericParameter)
223 var resolvedType = type.Resolve();
226 if (resolvedType.IsNested)
229 if (!resolvedType.IsNestedPublic && !resolvedType.IsNestedAssembly)
233 if (resolvedType.IsEnum)
237 var enumSerializerType = SiliconStudioCoreAssembly.MainModule.GetTypeResolved(
"SiliconStudio.Core.Serialization.Serializers.EnumSerializer`1");
238 var serializerType =
new GenericInstanceType(enumSerializerType);
239 serializerType.GenericArguments.Add(type);
242 AddSerializableType(type, serializableTypeInfo);
243 return serializableTypeInfo;
257 var dataSerializerAttribute =
258 resolvedType.CustomAttributes.FirstOrDefault(
259 x => x.AttributeType.FullName ==
"SiliconStudio.Core.Serialization.Serializers.DataSerializerAttribute");
260 if (dataSerializerAttribute != null)
262 var modeField = dataSerializerAttribute.Fields.FirstOrDefault(x => x.Name ==
"Mode");
263 var mode = (modeField.Name != null) ? (
DataSerializerGenericMode)modeField.Argument.Value : DataSerializerGenericMode.None;
266 var dataSerializerType = ((TypeReference)dataSerializerAttribute.ConstructorArguments[0].Value);
269 var genericSerializableTypeInfo =
new SerializableTypeInfo(dataSerializerType,
true, mode) { Inherited =
true };
270 AddSerializableType(type, genericSerializableTypeInfo);
272 var actualSerializerType =
new GenericInstanceType(dataSerializerType);
275 actualSerializerType.GenericArguments.Add(type);
280 foreach (var genericArgument
in ((GenericInstanceType)type).GenericArguments)
282 actualSerializerType.GenericArguments.Add(genericArgument);
287 var serializableTypeInfo =
new SerializableTypeInfo(actualSerializerType,
true);
288 AddSerializableType(type, serializableTypeInfo);
291 return serializableTypeInfo;
293 return genericSerializableTypeInfo;
297 var serializableTypeInfo =
new SerializableTypeInfo(dataSerializerType,
true, mode) { Inherited =
false };
298 AddSerializableType(type, serializableTypeInfo);
299 return serializableTypeInfo;
304 var serializableExtendedAttribute =
305 resolvedType.CustomAttributes.FirstOrDefault(
306 x => x.AttributeType.FullName ==
"SiliconStudio.Core.DataContractAttribute");
307 if (dataSerializerAttribute == null && serializableExtendedAttribute != null)
310 var inherited = serializableExtendedAttribute.Properties.Where(x => x.Name ==
"Inherited")
311 .
Select(x => (
bool)x.Argument.Value)
314 var serializableTypeInfo = CreateComplexSerializer(type);
315 serializableTypeInfo.Inherited = inherited;
318 ProcessComplexSerializerMembers(type, serializableTypeInfo);
320 return serializableTypeInfo;
324 var parentType = ResolveGenericsVisitor.Process(type, type.Resolve().BaseType);
325 if (parentType != null)
328 var parentSerializableInfoType = GenerateSerializer(parentType.Resolve(),
false,
generic:
true);
331 if (parentSerializableInfoType != null && parentSerializableInfoType.Inherited)
333 if (parentSerializableInfoType.ComplexSerializer)
335 var serializableTypeInfo = CreateComplexSerializer(type);
336 serializableTypeInfo.Inherited =
true;
339 ProcessComplexSerializerMembers(type, serializableTypeInfo);
341 return serializableTypeInfo;
346 var genericSerializableTypeInfo =
new SerializableTypeInfo(parentSerializableInfoType.SerializerType,
true, parentSerializableInfoType.Mode);
347 AddSerializableType(type, genericSerializableTypeInfo);
349 if (!type.HasGenericParameters)
351 var actualSerializerType =
new GenericInstanceType(parentSerializableInfoType.SerializerType);
354 actualSerializerType.GenericArguments.Add(type);
359 foreach (var genericArgument
in ((GenericInstanceType)parentType).GenericArguments)
361 actualSerializerType.GenericArguments.Add(genericArgument);
366 var serializableTypeInfo =
new SerializableTypeInfo(actualSerializerType,
true);
367 AddSerializableType(type, serializableTypeInfo);
370 return serializableTypeInfo;
373 return genericSerializableTypeInfo;
377 throw new InvalidOperationException(
"Not sure how to process this inherited serializer");
385 private SerializableTypeInfo CreateComplexSerializer(TypeReference type)
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)
393 mode = DataSerializerGenericMode.GenericArguments;
396 foreach (var genericParameter
in type.GenericParameters)
398 var newGenericParameter =
new GenericParameter(genericParameter.Name, dataSerializerType)
400 Attributes = genericParameter.Attributes
404 foreach (var constraint
in genericParameter.Constraints)
405 newGenericParameter.Constraints.Add(constraint);
407 dataSerializerType.GenericParameters.Add(newGenericParameter);
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);
416 if (isLocal && type is TypeDefinition)
418 ComplexTypes.Add((TypeDefinition)type, serializableTypeInfo);
421 serializableTypeInfo.ComplexSerializer =
true;
423 return serializableTypeInfo;
426 public void AddSerializableType(TypeReference dataType, SerializableTypeInfo serializableTypeInfo,
string profile =
"Default")
428 SerializableTypeInfo currentValue;
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));
436 var profileInfo = GetSerializableTypes(profile);
438 if (profileInfo.TryGetSerializableTypeInfo(dataType, serializableTypeInfo.Mode !=
DataSerializerGenericMode.None, out currentValue))
442 currentValue.Mode != serializableTypeInfo.Mode)
443 throw new InvalidOperationException(
string.Format(
"Incompatible serializer found for same type in different assemblies for {0}", dataType.ConvertCSharp()));
448 SerializableTypeInfo defaultValue;
449 if (profile !=
"Default" && SerializableTypes.TryGetSerializableTypeInfo(dataType, serializableTypeInfo.Mode !=
DataSerializerGenericMode.None, out defaultValue))
451 if (defaultValue.SerializerType.FullName == serializableTypeInfo.SerializerType.FullName)
458 profileInfo.AddSerializableTypeInfo(dataType, serializableTypeInfo);
461 if (serializableTypeInfo.Local && serializableTypeInfo.SerializerType != null)
463 var resolvedSerializerType = serializableTypeInfo.SerializerType.Resolve();
464 if (resolvedSerializerType != null)
466 var enumerateGenericInstantiationsMethod = resolvedSerializerType.Methods.FirstOrDefault(x => x.Name ==
"EnumerateGenericInstantiations");
467 if (enumerateGenericInstantiationsMethod != null)
470 foreach (var inst
in enumerateGenericInstantiationsMethod.Body.Instructions)
472 if (inst.OpCode.Code ==
Code.Ldtoken)
474 var type = (TypeReference)inst.Operand;
477 var dependentType = ResolveGenericsVisitor.Process(serializableTypeInfo.SerializerType, type);
478 if (!dependentType.ContainsGenericParameter())
482 var importedType = Assembly.MainModule.Import(dependentType);
483 if (GenerateSerializer(importedType) == null)
485 throw new InvalidOperationException(
string.Format(
"Could not find serializer for generic dependent type {0}", dependentType));
495 private ProfileInfo GetSerializableTypes(
string profile)
497 ProfileInfo profileInfo;
498 if (!SerializableTypesProfiles.TryGetValue(profile, out profileInfo))
500 profileInfo =
new ProfileInfo();
501 SerializableTypesProfiles.Add(profile, profileInfo);
506 internal class SerializableTypeInfo
508 public TypeReference SerializerType {
get;
internal set; }
515 public bool ExistingLocal;
520 public bool Inherited;
525 public bool ComplexSerializer;
530 public bool ComplexSerializerProcessParentType;
534 SerializerType = serializerType;
545 public Dictionary<TypeReference, SerializableTypeInfo> SerializableTypes =
new Dictionary<TypeReference, SerializableTypeInfo>(TypeReferenceEqualityComparer.Default);
550 public Dictionary<TypeReference, SerializableTypeInfo> GenericSerializableTypes =
new Dictionary<TypeReference, SerializableTypeInfo>(TypeReferenceEqualityComparer.Default);
555 ? GenericSerializableTypes.TryGetValue(type, out result)
556 : SerializableTypes.TryGetValue(type, out result);
562 GenericSerializableTypes.Add(typeReference, serializableTypeInfo);
564 SerializableTypes.Add(typeReference, serializableTypeInfo);
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)