Esempio n. 1
0
        /// <summary>
        /// Gets the external object serializer for the specified type.
        /// </summary>
        /// <param name="type">Type to get an external object serializer for.</param>
        /// <param name="version">Receives the version of the serializer.</param>
        /// <returns>
        /// The external object serializer for the specified type;
        /// <c>null</c>, if the type does not have an external object serializer.
        /// </returns>
        public static IExternalObjectSerializer GetExternalObjectSerializer(Type type, out uint version)
        {
            // check whether a serializer for exactly the specified type is available
            if (sExternalObjectSerializerInfoBySerializee.TryGetValue(type, out var eosi))
            {
                version = eosi.SerializerInfo.Version;
                return(eosi.Serializer);
            }

            // there is no external object serializer instance handling the specified type, yet
            // => find the external object serializer matching best...

            lock (sSync)
            {
                // once again, check whether a serializer for exactly the specified type is available
                // (maybe someone else has added the serializer meanwhile...)
                if (sExternalObjectSerializerInfoBySerializee.TryGetValue(type, out eosi))
                {
                    version = eosi.SerializerInfo.Version;
                    return(eosi.Serializer);
                }

                // get a list containing the serializee type and all interfaces it implements
                var possibleSerializeeTypes = GetPossibleSerializeeTypes(type);

                // check the types against the types registered external object serializers can handle
                // (the order of both lists ensures that the most specific types are checked first)
                foreach (var possibleSerializeeType in possibleSerializeeTypes)
                {
                    foreach (var eosInfo in sRegisteredExternalObjectSerializers)
                    {
                        IExternalObjectSerializer eosInstance = null;

                        if (possibleSerializeeType == eosInfo.SerializeeType)
                        {
                            // the serializee exactly matches the serializee supported by the external object serializer
                            // => the serializer can handle the type directly
                            eosInstance = (IExternalObjectSerializer)FastActivator.CreateInstance(eosInfo.SerializerType);
                        }
                        else if (possibleSerializeeType.IsConstructedGenericType && eosInfo.SerializeeType.ContainsGenericParameters)
                        {
                            // the serializee is a generic type and the serializee supported by the external object serializer is a generic type as well
                            // => check whether their generic type definitions are the same, so the serializer can be used to handle the type
                            var possibleSerializeeTypeDefinition = possibleSerializeeType.GetGenericTypeDefinition();
                            var eosSerializeeTypeDefinition      = eosInfo.SerializeeType.GetGenericTypeDefinition();
                            if (possibleSerializeeTypeDefinition == eosSerializeeTypeDefinition)
                            {
                                // both generic type definitions are the same
                                // => found serializer that can handle the type
                                var constructedEosType = eosInfo.SerializerType.MakeGenericType(possibleSerializeeType.GenericTypeArguments);
                                eosInstance = (IExternalObjectSerializer)FastActivator.CreateInstance(constructedEosType);
                            }
                        }

                        if (eosInstance != null)
                        {
                            // found an external object serializer that is capable of handling the specified type
                            // => add it to the serializer cache...
                            var eosDictCopy = new TypeKeyedDictionary <SerializeeInfo>(sExternalObjectSerializerInfoBySerializee)
                            {
                                { type, new SerializeeInfo(type, eosInfo, eosInstance) }
                            };
                            Thread.MemoryBarrier();
                            sExternalObjectSerializerInfoBySerializee = eosDictCopy;

                            version = eosInfo.Version;
                            return(eosInstance);
                        }
                    }
                }
            }

            version = 0;
            return(null);
        }