4 using System.Collections.Generic;
6 using System.Runtime.CompilerServices;
7 using System.Reflection;
8 using SiliconStudio.Core.Collections;
9 using SiliconStudio.Core.Serialization.Contents;
11 namespace SiliconStudio.Core.Serialization.Converters
15 static List<DataConverter> converters =
new List<DataConverter>();
16 static Dictionary<ConvertersBySourceTypeKey, DataConverter> convertersBySourceType =
new Dictionary<ConvertersBySourceTypeKey, DataConverter>();
18 private Dictionary<ConvertedObjectKey, object> convertedObjects =
new Dictionary<ConvertedObjectKey, object>();
24 converters.Add(converter);
27 [MethodImpl(MethodImplOptions.AggressiveInlining)]
28 public TData ConvertToData<TData>(
object source)
30 TData result =
default(TData);
31 ConvertToData(ref result, source);
35 [MethodImpl(MethodImplOptions.AggressiveInlining)]
38 TSource result =
default(TSource);
39 ConvertFromData(data, ref result,
flags);
48 source =
default(TSource);
52 var dataType = data.GetType();
53 var dataIsValueType = dataType.GetTypeInfo().IsValueType;
55 var dataConverter = GetDataConverter(dataType, typeof(TSource),
ConversionType.DataToObject);
56 if (dataConverter == null)
61 source = (TSource)data;
65 throw new InvalidOperationException(
string.Format(
"Could not find a valid converter from type {0} to {1}", dataType, typeof(TSource)));
69 bool alreadyStoredInConvertedObjects = ((
flags & ConvertFromDataFlags.Construct) == 0);
75 if (convertedObjects.TryGetValue(
new ConvertedObjectKey(data, dataConverter.ObjectType), out cachedSource))
77 source = (TSource)cachedSource;
81 sourceObject = source;
83 if (dataConverter.CanConstruct)
85 dataConverter.ConstructFromData(
this, data, ref sourceObject);
88 if (sourceObject != null)
90 convertedObjects.Add(
new ConvertedObjectKey(data, dataConverter.ObjectType), sourceObject);
91 alreadyStoredInConvertedObjects =
true;
97 sourceObject = source;
102 dataConverter.ConvertFromData(
this, data, ref sourceObject);
104 if (!dataIsValueType && dataConverter.CacheResult)
108 if (!alreadyStoredInConvertedObjects)
109 convertedObjects.Add(
new ConvertedObjectKey(data, dataConverter.ObjectType), sourceObject);
113 source = (TSource)sourceObject;
116 public void ConvertToData<TData>(ref TData data,
object source)
121 data =
default(TData);
125 var sourceType = source.GetType();
126 var sourceIsValueType = sourceType.GetTypeInfo().IsValueType;
128 var dataConverter = GetDataConverter(typeof(TData), sourceType,
ConversionType.ObjectToData);
129 if (dataConverter == null)
134 data = (TData)source;
138 throw new InvalidOperationException(
string.Format(
"Could not find a valid converter from type {0} to {1}", sourceType, typeof(TData)));
141 if (!sourceIsValueType && dataConverter.CacheResult)
145 if (convertedObjects.TryGetValue(
new ConvertedObjectKey(source, dataConverter.ObjectType), out cachedData))
147 data = (TData)cachedData;
152 object dataObject = data;
153 dataConverter.ConvertToData(
this, ref dataObject, source);
155 if (!sourceIsValueType && dataConverter.CacheResult)
157 convertedObjects.Add(
new ConvertedObjectKey(source, dataConverter.ObjectType), dataObject);
160 data = (TData)dataObject;
165 lock (convertersBySourceType)
168 if (!convertersBySourceType.TryGetValue(
new ConvertersBySourceTypeKey(dataType, objectType), out dataConverter))
171 foreach (var existingConverter
in converters)
173 bool matching = conversionType == ConversionType.ObjectToData
174 ? objectType == existingConverter.ObjectType && dataType.GetTypeInfo().IsAssignableFrom(existingConverter.DataType.GetTypeInfo())
175 : dataType == existingConverter.
DataType && objectType.GetTypeInfo().IsAssignableFrom(existingConverter.ObjectType.GetTypeInfo());
178 if (dataConverter != null)
179 throw new InvalidOperationException(
string.Format(
"Found two matching converters between types {0} and {1}", dataType, objectType));
180 dataConverter = existingConverter;
185 if (dataConverter == null)
187 DataConverterResult objectResult, dataResult;
188 if (GetDataConverter(dataType, objectType, typeof(IList<>), conversionType, out dataResult, out objectResult))
190 dataConverter = (
DataConverter)Activator.CreateInstance(typeof(ListDataConverter<,,,>).MakeGenericType(dataResult.Type, objectResult.Type, dataResult.InterfaceType.GenericTypeArguments[0], objectResult.InterfaceType.GenericTypeArguments[0]));
192 else if (GetDataConverter(dataType, objectType, typeof(
IDictionary<,>), conversionType, out dataResult, out objectResult))
195 typeof(DictionaryDataConverter<,,,,,>).MakeGenericType(
196 dataResult.Type, objectResult.Type,
197 dataResult.InterfaceType.GenericTypeArguments[0], dataResult.InterfaceType.GenericTypeArguments[1],
198 objectResult.InterfaceType.GenericTypeArguments[0], objectResult.InterfaceType.GenericTypeArguments[1]));
203 if (dataConverter == null)
205 DataConverterResult dataResult;
206 if (GetGenericTypeArgumentsForInterface(dataType, typeof(
ContentReference<>), out dataResult))
208 var contentDataType = dataResult.InterfaceType.GenericTypeArguments[0];
209 var contentObjectType = objectType;
210 var itemDataConverter = GetDataConverter(dataType.GenericTypeArguments[0], objectType, conversionType);
215 contentObjectType = (itemDataConverter != null) ? itemDataConverter.ObjectType : contentDataType;
218 dataConverter = (
DataConverter)Activator.CreateInstance(typeof(ContentReferenceDataConverter<,>).MakeGenericType(contentDataType, contentObjectType));
222 convertersBySourceType.Add(
new ConvertersBySourceTypeKey(dataType, objectType), dataConverter);
224 return dataConverter;
228 private static bool GetGenericTypeArgumentsForInterface(Type type, Type genericType, out DataConverterResult result)
230 result =
new DataConverterResult();
232 var typeInfo = type.GetTypeInfo();
233 var genericTypeInfo = genericType.GetTypeInfo();
236 if (typeInfo.IsGenericType && type.GetGenericTypeDefinition() == genericType)
238 result.InterfaceType = type;
244 if (genericTypeInfo.IsInterface)
246 foreach (var
@interface in typeInfo.ImplementedInterfaces)
248 var interfaceTypeInfo =
@interface.GetTypeInfo();
249 if (interfaceTypeInfo.IsGenericType && interfaceTypeInfo.GetGenericTypeDefinition() == genericType)
251 result.InterfaceType = interfaceTypeInfo.AsType();
261 private static bool GetDataConverter(Type dataType, Type objectType, Type genericType, ConversionType conversionType, out DataConverterResult dataResult, out DataConverterResult objectResult)
263 bool objectResultFound = GetGenericTypeArgumentsForInterface(objectType, genericType, out objectResult);
264 bool dataResultFound = GetGenericTypeArgumentsForInterface(dataType, genericType, out dataResult);
266 switch (conversionType)
268 case ConversionType.ObjectToData:
269 if (objectResultFound && !dataResultFound)
271 dataResultFound =
true;
272 var genericTypeArguments = objectResult.InterfaceType.GenericTypeArguments.Select(x =>
274 var dataConverter = GetDataConverter(typeof(
object), x, conversionType);
275 return dataConverter != null ? dataConverter.DataType : x;
277 dataResult.Type = dataResult.InterfaceType = genericType.MakeGenericType(genericTypeArguments.ToArray());
280 case ConversionType.DataToObject:
281 if (dataResultFound && !objectResultFound)
283 objectResultFound =
true;
284 var genericTypeArguments = dataResult.InterfaceType.GenericTypeArguments.Select(x =>
286 var dataConverter = GetDataConverter(x, typeof(
object), conversionType);
287 return dataConverter != null ? dataConverter.ObjectType : x;
289 objectResult.Type = objectResult.InterfaceType = genericType.MakeGenericType(genericTypeArguments.ToArray());
293 throw new ArgumentOutOfRangeException(
"conversionType");
296 return (objectResultFound && dataResultFound);
305 struct DataConverterResult
315 public Type InterfaceType;
318 struct ConvertersBySourceTypeKey : IEquatable<ConvertersBySourceTypeKey>
320 public Type DataType;
323 public ConvertersBySourceTypeKey(Type dataType, Type objectType)
329 public bool Equals(ConvertersBySourceTypeKey other)
331 return DataType.Equals(other.DataType) &&
ObjectType.Equals(other.ObjectType);
334 public override bool Equals(
object obj)
336 if (ReferenceEquals(null, obj))
return false;
337 return obj is ConvertersBySourceTypeKey && Equals((ConvertersBySourceTypeKey)obj);
340 public override int GetHashCode()
344 return (DataType.GetHashCode()*397) ^
ObjectType.GetHashCode();
349 struct ConvertedObjectKey : IEquatable<ConvertedObjectKey>
354 public ConvertedObjectKey(
object o, Type objectType)
360 public bool Equals(ConvertedObjectKey other)
362 return Object.Equals(other.Object) &&
ObjectType.Equals(other.ObjectType);
365 public override bool Equals(
object obj)
367 if (ReferenceEquals(null, obj))
return false;
368 return obj is ConvertedObjectKey && Equals((ConvertedObjectKey)obj);
371 public override int GetHashCode()
static DataConverter GetDataConverter(Type dataType, Type objectType, ConversionType conversionType)
_In_ size_t _In_ DXGI_FORMAT _In_ size_t _In_ DXGI_FORMAT _In_ DWORD flags
Represents a container that can hold properties, lightweight to embed (lazy initialized).
Base class for converters to/from a data type.
abstract Type DataType
Gets the data type.
The type of the serialized type will be passed as a generic arguments of the serializer. Example: serializer of A becomes instantiated as Serializer{A}.