/// <summary> /// Attempts to produce a decorated serializer for the provided <see cref="ISerializableTypeContext"/>. /// </summary> /// <param name="context">The context.</param> /// <exception cref="InvalidOperationException">Throws if the <see cref="ITypeSerializerStrategy{TType}"/> could not be created.</exception> /// <returns>A decorated serializer.</returns> public ITypeSerializerStrategy <TType> Create <TType>([NotNull] ISerializableTypeContext context) { if (context == null) { throw new ArgumentNullException(nameof(context)); } //Build the contextual key first. We used to do this as one of the last steps but we need //to grab the key to check if it already exists. context.BuiltContextKey = lookupKeyFactoryService.Create(context); if (serializerProviderService.HasSerializerFor(context.BuiltContextKey.Value)) { throw new InvalidOperationException($"Tried to create multiple serializer for already created serialize with Context: {context.ToString()}."); } //This may look weird but this was done for perf reasons //We can't be passing around IEnumerables and ToListing them //Otherwise complex types will take seconds to register List <ISerializableTypeContext> contexts = new List <ISerializableTypeContext>(200); GetAllSubTypeContexts(context, contexts); IEnumerable <ISerializableTypeContext> byLikelyRegisteration = contexts .Distinct(new SerializableTypeContextComparer()) .ToList(); //We must register all subcontexts first foreach (ISerializableTypeContext subContext in byLikelyRegisteration) { MethodInfo info = null; if (CachedGenericInternalCreateMap.ContainsKey(subContext.TargetType)) { info = CachedGenericInternalCreateMap[subContext.TargetType]; } else { info = (CachedGenericInternalCreateMap[subContext.TargetType] = GetType().GetTypeInfo().GetMethod(nameof(InternalCreate), BindingFlags.NonPublic | BindingFlags.Instance) .MakeGenericMethod(subContext.TargetType)); } info.Invoke(this, new object[] { subContext }); } //Now that all dependencies in the object graph are registered we can create the requested type return(InternalCreate <TType>(context)); }
public ITypeSerializerStrategy <TType> Create <TType>([NotNull] ISerializableTypeContext context) { if (context == null) { throw new ArgumentNullException(nameof(context)); } if (!CanHandle(context)) { throw new InvalidOperationException($"Cannot handle Type: {context.TargetType.Name} with a {this.GetType().FullName}."); } if (!context.BuiltContextKey.HasValue) { throw new InvalidOperationException($"Failed to build a {nameof(ContextualSerializerLookupKey)} for the Type: {context.TargetType} with Context: {context.ToString()}."); } ITypeSerializerStrategy <TType> serializer = TryCreateSerializer <TType>(context); if (serializer == null) { throw new InvalidOperationException($"Failed to generate a serializer for Type: {context.TargetType.Name} with decorator factory {this.GetType().FullName}."); } return(serializer); }
//TODO: Refactor; mess; too long /// <inheritdoc /> protected override ITypeSerializerStrategy <TType> TryCreateSerializer <TType>(ISerializableTypeContext context) { if (context == null) { throw new ArgumentNullException(nameof(context)); } if (!context.BuiltContextKey.HasValue) { throw new InvalidOperationException($"Provided {nameof(ISerializableTypeContext)} did not contain a valid {nameof(context.BuiltContextKey)} for Context: {context.ToString()}."); } ICollectionSizeStrategy collectionSizeStrategy = null; //TODO: Handle contextless requests. The future may require a single array serializer for all unknown sizes. if (context.BuiltContextKey.Value.ContextFlags.HasFlag(ContextTypeFlags.FixedSize)) { int knownSize = context.BuiltContextKey.Value.ContextSpecificKey.Key; collectionSizeStrategy = new FixedSizeCollectionSizeStrategy(knownSize); } else if (context.BuiltContextKey.Value.ContextFlags.HasFlag(ContextTypeFlags.SendSize)) { sbyte addedSize = (sbyte)(context.BuiltContextKey.Value.ContextSpecificKey.Key >> 4); //TODO: Is there a way to obsecure this bit fiddling? switch ((SendSizeAttribute.SizeType)(context.BuiltContextKey.Value.ContextSpecificKey.Key & 0b0000_0000_0000_1111)) //get just the key {
//Called as the fallback factory. /// <inheritdoc /> public ITypeSerializerStrategy <TType> Create <TType>([NotNull] ISerializableTypeContext context) { if (context == null) { throw new ArgumentNullException(nameof(context)); } //This service acts a the default/fallback factory for serializer creation. If any factory encounters a type //inside of a type that it doesn't know about or requires handling outside of its scope it'll broadcast that //and we will implement more complex handling here ITypeSerializerStrategy <TType> strategy = serializerStrategyFactoryService.Create <TType>(context); //The serializer could be null; we should verify it if (strategy == null) { throw new InvalidOperationException($"Failed to create serializer for Type: {context.TargetType} with Context: {context.ToString()}."); } return(strategy); }