internal static BinaryPropertyInfo CreateProperty(
            TypeMap typeMap,
            Type declaredPropertyType,
            Type runtimePropertyType,
            MemberInfo memberInfo,
            Type parentClassType,
            BinaryConverter converter,
            BinarySerializerOptions options,
            BinaryIgnoreCondition?ignoreCondition = null)
        {
            // Create the BinaryPropertyInfo instance.
            BinaryPropertyInfo binaryPropertyInfo = converter.CreateBinaryPropertyInfo();

            binaryPropertyInfo.Initialize(
                typeMap,
                parentClassType,
                declaredPropertyType,
                runtimePropertyType,
                runtimeClassType: converter.ClassType,
                memberInfo,
                converter,
                ignoreCondition,
                options);

            return(binaryPropertyInfo);
        }
 public void EndProperty()
 {
     DeclaredBinaryPropertyInfo    = null !;
     BinaryPropertyNameAsString    = null;
     PolymorphicBinaryPropertyInfo = null;
     PropertyState = StackFramePropertyState.None;
 }
        public static BinaryPropertyInfo AddProperty(
            TypeMap typeMap,
            MemberInfo memberInfo,
            Type memberType,
            Type parentClassType,
            BinarySerializerOptions options)
        {
            BinaryIgnoreCondition?ignoreCondition = BinaryPropertyInfo.GetAttribute <BinaryIgnoreAttribute>(memberInfo)?.Condition;

            if (ignoreCondition == BinaryIgnoreCondition.Always)
            {
                return(BinaryPropertyInfo.CreateIgnoredPropertyPlaceholder(typeMap, memberInfo, options));
            }

            BinaryConverter converter = GetConverter(
                memberType,
                parentClassType,
                memberInfo,
                out Type runtimeType,
                options);

            return(CreateProperty(
                       typeMap,
                       declaredPropertyType: memberType,
                       runtimePropertyType: runtimeType,
                       memberInfo,
                       parentClassType,
                       converter,
                       options,
                       ignoreCondition));
        }
        internal static void CreateDataExtensionProperty(
            ref ReadStack state,
            object obj,
            BinaryPropertyInfo binaryPropertyInfo)
        {
            Debug.Assert(binaryPropertyInfo != null);

            object extensionData = binaryPropertyInfo.GetValueAsObject(obj);

            if (extensionData == null)
            {
                // Create the appropriate dictionary type. We already verified the types.
#if DEBUG
                Type   underlyingIDictionaryType = binaryPropertyInfo.DeclaredPropertyType.GetCompatibleGenericInterface(typeof(IDictionary <,>)) !;
                Type[] genericArgs = underlyingIDictionaryType.GetGenericArguments();

                Debug.Assert(underlyingIDictionaryType.IsGenericType);
                Debug.Assert(genericArgs.Length == 2);
                Debug.Assert(genericArgs[0].UnderlyingSystemType == typeof(string));
                Debug.Assert(
                    genericArgs[1].UnderlyingSystemType == BinaryClassInfo.ObjectType);
#endif
                if (binaryPropertyInfo.RuntimeClassInfo.CreateObject == null)
                {
                    ThrowHelper.ThrowNotSupportedException_SerializationNotSupported(binaryPropertyInfo.DeclaredPropertyType);
                }

                extensionData = binaryPropertyInfo.RuntimeClassInfo.CreateObject();
                binaryPropertyInfo.SetExtensionDictionaryAsObject(ref state, obj, extensionData);
            }

            // We don't add the value to the dictionary here because we need to support the read-ahead functionality for Streams.
        }
 // Create a parameter that is ignored at run-time. It uses the same type (typeof(sbyte)) to help
 // prevent issues with unsupported types and helps ensure we don't accidently (de)serialize it.
 public static BinaryParameterInfo CreateIgnoredParameterPlaceholder(BinaryPropertyInfo matchingProperty)
 {
     return(new BinaryParameterInfo <sbyte>
     {
         RuntimePropertyType = typeof(sbyte),
         NameAsUtf8Bytes = matchingProperty.NameAsUtf8Bytes !,
         TypeMap = matchingProperty.TypeMap
     });
        public BinaryClassInfo([NotNull] Type type, [NotNull] TypeMap typeMap, [NotNull] BinarySerializerOptions options)
        {
            TypeMap = typeMap;
            Type    = type;
            Options = options;

            BinaryConverter converter = GetConverter(
                Type,
                parentClassType: null, // A ClassInfo never has a "parent" class.
                memberInfo: null,      // A ClassInfo never has a "parent" property.
                out Type runtimeType,
                Options);

            ClassType = converter.ClassType;

            PropertyInfoForClassInfo = CreatePropertyInfoForClassInfo(TypeMap, Type, runtimeType, converter, Options);
            TypeSeq = converter.GetTypeSeq(typeMap, options);

            switch (ClassType)
            {
            case ClassType.Object:
            {
                CreateObject = Options.MemberAccessorStrategy.CreateConstructor(type);
                GetObjectMemberInfos(type, typeMap, converter);
            }
            break;

            case ClassType.Enumerable:
            case ClassType.Dictionary:
            {
                ElementType  = converter.ElementType;
                CreateObject = Options.MemberAccessorStrategy.CreateConstructor(runtimeType);
                GetObjectMemberInfos(type, typeMap, converter, true);
            }
            break;

            case ClassType.Value:
            case ClassType.NewValue:
            {
                CreateObject = Options.MemberAccessorStrategy.CreateConstructor(type);
            }
            break;

            case ClassType.None:
            {
                ThrowHelper.ThrowNotSupportedException_SerializationNotSupported(type);
            }
            break;

            default:
                Debug.Fail($"Unexpected class type: {ClassType}");
                throw new InvalidOperationException();
            }
        }
 public void EndProperty()
 {
     BinaryPropertyInfo         = null !;
     BinaryPropertyName         = null;
     BinaryPropertyNameAsString = null;
     PropertyState                = StackFramePropertyState.None;
     ValidateEndTokenOnArray      = false;
     PropertyPolymorphicConverter = null;
     // No need to clear these since they are overwritten each time:
     //  NumberHandling
     //  UseExtensionProperty
 }
        /// <summary>
        /// Initializes the state for polymorphic or re-entry cases.
        /// </summary>
        public BinaryConverter InitializeReEntry(Type type, BinarySerializerOptions options, string propertyName = null)
        {
            BinaryClassInfo classInfo = options.GetOrAddClass(type);


            // Set for exception handling calculation of BinaryPath.
            BinaryPropertyNameAsString = propertyName;

            PolymorphicBinaryPropertyInfo = classInfo.PropertyInfoForClassInfo;
            //PolymorphicBinaryClassInfo = classInfo;
            //PolymorphicBinaryTypeInfo = classInfo.TypeMap.GetTypeInfo(classInfo.TypeSeq);
            return(PolymorphicBinaryPropertyInfo.ConverterBase);
        }
Exemple #9
0
        public static BinaryPropertyInfo GetPropertyPlaceholder()
        {
            BinaryPropertyInfo info = new BinaryPropertyInfo <object>();

            Debug.Assert(!info.IsForClassInfo);
            Debug.Assert(!info.ShouldDeserialize);
            Debug.Assert(!info.ShouldSerialize);

            info.NameAsString = string.Empty;


            return(info);
        }
        private void CacheMember(
            Type declaringType,
            Type memberType,
            MemberInfo memberInfo,
            Dictionary <string, BinaryPropertyInfo> cache,
            ref Dictionary <string, MemberInfo> ignoredMembers)
        {
            BinaryPropertyInfo binaryPropertyInfo = AddProperty(TypeMap, memberInfo, memberType, declaringType, Options);

            Debug.Assert(binaryPropertyInfo.NameAsString != null);

            string memberName = memberInfo.Name;

            // The BinaryPropertyNameAttribute or naming policy resulted in a collision.
            if (!cache.TryAdd(binaryPropertyInfo.NameAsString, binaryPropertyInfo))
            {
                BinaryPropertyInfo other = cache[binaryPropertyInfo.NameAsString];

                if (other.IsIgnored)
                {
                    // Overwrite previously cached property since it has [BinaryIgnore].
                    cache[binaryPropertyInfo.NameAsString] = binaryPropertyInfo;
                }
                else if (
                    // Does the current property have `BinaryIgnoreAttribute`?
                    !binaryPropertyInfo.IsIgnored &&
                    // Is the current property hidden by the previously cached property
                    // (with `new` keyword, or by overriding)?
                    other.MemberInfo !.Name != memberName &&
                    // Was a property with the same CLR name was ignored? That property hid the current property,
                    // thus, if it was ignored, the current property should be ignored too.
                    ignoredMembers?.ContainsKey(memberName) != true)
                {
                    // We throw if we have two public properties that have the same property name, and neither have been ignored.
                    ThrowHelper.ThrowInvalidOperationException_SerializerPropertyNameConflict(Type, binaryPropertyInfo);
                }
                // Ignore the current property.
            }
            else
            {
                int seq = System.Threading.Interlocked.Increment(ref _propertySeq);
                binaryPropertyInfo.Seq = (ushort)seq;
            }

            if (binaryPropertyInfo.IsIgnored)
            {
                (ignoredMembers ??= new Dictionary <string, MemberInfo>()).Add(memberName, memberInfo);
            }
        }
 public virtual void Initialize(
     TypeMap typeMap,
     Type runtimePropertyType,
     ParameterInfo parameterInfo,
     BinaryPropertyInfo matchingProperty,
     BinarySerializerOptions options)
 {
     TypeMap                   = typeMap;
     RuntimePropertyType       = runtimePropertyType;
     Position                  = parameterInfo?.Position ?? 0;
     NameAsUtf8Bytes           = matchingProperty.NameAsUtf8Bytes !;
     Options                   = options;
     ShouldDeserialize         = true;
     ConverterBase             = matchingProperty.ConverterBase;
     IgnoreDefaultValuesOnRead = matchingProperty.IgnoreDefaultValuesOnRead;
 }
Exemple #12
0
        // Create a property that is ignored at run-time. It uses the same type (typeof(sbyte)) to help
        // prevent issues with unsupported types and helps ensure we don't accidently (de)serialize it.
        public static BinaryPropertyInfo CreateIgnoredPropertyPlaceholder(TypeMap typeMap, MemberInfo memberInfo, BinarySerializerOptions options)
        {
            BinaryPropertyInfo binaryPropertyInfo = new BinaryPropertyInfo <sbyte>
            {
                Options    = options,
                MemberInfo = memberInfo
            };

            binaryPropertyInfo.DeterminePropertyName();
            binaryPropertyInfo.IsIgnored = true;
            binaryPropertyInfo.TypeMap   = typeMap;

            Debug.Assert(!binaryPropertyInfo.ShouldDeserialize);
            Debug.Assert(!binaryPropertyInfo.ShouldSerialize);

            return(binaryPropertyInfo);
        }
        public void Reset()
        {
            CollectionEnumerator      = null;
            EnumeratorIndex           = 0;
            IgnoreDictionaryKeyPolicy = false;
            BinaryClassInfo           = null !;
            EnumerableIndexBytes      = 8;
            //PolymorphicBinaryClassInfo = null;
            PolymorphicBinaryPropertyInfo = null;
            OriginalDepth            = 0;
            ProcessedStartToken      = false;
            ProcessedEndToken        = false;
            ProcessedEnumerableIndex = false;
            ObjectState = StackFrameWriteObjectState.None;
            //ProcessedArrayLength = false;

            EndProperty();
        }
        internal static BinaryPropertyInfo LookupProperty(
            object obj,
            ReadOnlySpan <byte> unescapedPropertyName,
            ref ReadStack state,
            out bool useExtensionProperty,
            bool createExtensionProperty = true)
        {
            Debug.Assert(state.Current.BinaryClassInfo.ClassType == ClassType.Object || state.Current.BinaryClassInfo.ClassType == ClassType.Enumerable || state.Current.BinaryClassInfo.ClassType == ClassType.Dictionary);

            useExtensionProperty = false;

            BinaryPropertyInfo binaryPropertyInfo = state.Current.BinaryClassInfo.GetProperty(
                unescapedPropertyName,
                ref state.Current,
                out byte[] utf8PropertyName);

            // Increment PropertyIndex so GetProperty() checks the next property first when called again.
            state.Current.PropertyIndex++;

            // For case insensitive and missing property support of BinaryPath, remember the value on the temporary stack.
            state.Current.BinaryPropertyName = utf8PropertyName;

            // Determine if we should use the extension property.
            if (binaryPropertyInfo == BinaryPropertyInfo.s_missingProperty)
            {
                BinaryPropertyInfo dataExtProperty = state.Current.BinaryClassInfo.DataExtensionProperty;
                if (dataExtProperty != null && dataExtProperty.HasGetter && dataExtProperty.HasSetter)
                {
                    state.Current.BinaryPropertyNameAsString = BinaryReaderHelper.TranscodeHelper(unescapedPropertyName);

                    if (createExtensionProperty)
                    {
                        CreateDataExtensionProperty(ref state, obj, dataExtProperty);
                    }

                    binaryPropertyInfo   = dataExtProperty;
                    useExtensionProperty = true;
                }
            }

            state.Current.BinaryPropertyInfo = binaryPropertyInfo;
            return(binaryPropertyInfo);
        }
        private static BinaryPropertyInfo GetPropertyWithUniqueAttribute(Type classType, Type attributeType, Dictionary <string, BinaryPropertyInfo> cache)
        {
            BinaryPropertyInfo property = null;

            foreach (BinaryPropertyInfo binaryPropertyInfo in cache.Values)
            {
                Debug.Assert(binaryPropertyInfo.MemberInfo != null);
                Attribute attribute = binaryPropertyInfo.MemberInfo.GetCustomAttribute(attributeType);
                if (attribute != null)
                {
                    if (property != null)
                    {
                        ThrowHelper.ThrowInvalidOperationException_SerializationDuplicateTypeAttribute(classType, attributeType);
                    }

                    property = binaryPropertyInfo;
                }
            }

            return(property);
        }
        /// <summary>
        /// 检查是否具有扩展数据字段
        /// </summary>
        /// <param name="cache"></param>
        /// <returns></returns>
        public bool DetermineExtensionDataProperty(Dictionary <string, BinaryPropertyInfo> cache)
        {
            // 一个类型中只能由一个扩展字段(由BinaryExtensionDataAttribute标注)
            BinaryPropertyInfo binaryPropertyInfo = GetPropertyWithUniqueAttribute(Type, typeof(BinaryExtensionDataAttribute), cache);

            if (binaryPropertyInfo != null)
            {
                Type declaredPropertyType = binaryPropertyInfo.DeclaredPropertyType;
                if (typeof(IDictionary <string, object>).IsAssignableFrom(declaredPropertyType))
                {
                    BinaryConverter converter = Options.GetConverter(declaredPropertyType);
                    Debug.Assert(converter != null);
                }
                else
                {
                    ThrowHelper.ThrowInvalidOperationException_SerializationDataExtensionPropertyInvalid(Type, binaryPropertyInfo);
                }

                DataExtensionProperty = binaryPropertyInfo;
                return(true);
            }

            return(false);
        }
Exemple #17
0
 public static void ThrowInvalidOperationException_SerializerPropertyNameNull(Type parentType, BinaryPropertyInfo binaryPropertyInfo)
 {
     throw new InvalidOperationException(string.Format(Strings.SerializerPropertyNameNull, parentType, binaryPropertyInfo.MemberInfo?.Name));
 }
Exemple #18
0
        public static void ThrowInvalidOperationException_IgnoreConditionOnValueTypeInvalid(BinaryPropertyInfo binaryPropertyInfo)
        {
            MemberInfo memberInfo = binaryPropertyInfo.MemberInfo !;

            throw new InvalidOperationException(string.Format(Strings.IgnoreConditionOnValueTypeInvalid, memberInfo.Name, memberInfo.DeclaringType));
        }
 public void EndDictionaryElement()
 {
     PropertyState = StackFramePropertyState.None;
     PolymorphicBinaryPropertyInfo = null;
 }
        private void GetObjectMemberInfos(Type type, TypeMap typeMap, BinaryConverter converter, bool ignoreReadOnly = false)
        {
            Dictionary <string, BinaryPropertyInfo> cache = new Dictionary <string, BinaryPropertyInfo>(
                Options.PropertyNameCaseInsensitive
                                            ? StringComparer.OrdinalIgnoreCase
                                            : StringComparer.Ordinal);

            Dictionary <string, MemberInfo> ignoredMembers = null;

            // We start from the most derived type.
            for (Type currentType = type; currentType != null; currentType = currentType.BaseType)
            {
                const BindingFlags bindingFlags =
                    BindingFlags.Instance |
                    BindingFlags.Public |
                    BindingFlags.NonPublic |
                    BindingFlags.DeclaredOnly;

                foreach (PropertyInfo propertyInfo in currentType.GetProperties(bindingFlags))
                {
                    // Ignore indexers and virtual properties that have overrides that were [BinaryIgnore]d.
                    if (propertyInfo.GetIndexParameters().Length > 0 || PropertyIsOverridenAndIgnored(propertyInfo, ignoredMembers))
                    {
                        continue;
                    }

                    // For now we only support public properties (i.e. setter and/or getter is public).
                    if (propertyInfo.GetMethod?.IsPublic == true ||
                        propertyInfo.SetMethod?.IsPublic == true)
                    {
                        if (!propertyInfo.CanWrite && ignoreReadOnly)
                        {
                            continue;
                        }
                        CacheMember(currentType, propertyInfo.PropertyType, propertyInfo, cache, ref ignoredMembers);
                    }
                    else
                    {
                        if (BinaryPropertyInfo.GetAttribute <BinaryIncludeAttribute>(propertyInfo) != null)
                        {
                            ThrowHelper.ThrowInvalidOperationException_BinaryIncludeOnNonPublicInvalid(propertyInfo, currentType);
                        }

                        // Non-public properties should not be included for (de)serialization.
                    }
                }

                foreach (FieldInfo fieldInfo in currentType.GetFields(bindingFlags))
                {
                    if (PropertyIsOverridenAndIgnored(fieldInfo, ignoredMembers))
                    {
                        continue;
                    }

                    bool hasBinaryInclude = BinaryPropertyInfo.GetAttribute <BinaryIncludeAttribute>(fieldInfo) != null;

                    if (fieldInfo.IsPublic)
                    {
                        if (hasBinaryInclude || Options.IncludeFields || converter.IncludeFields)
                        {
                            CacheMember(currentType, fieldInfo.FieldType, fieldInfo, cache, ref ignoredMembers);
                        }
                    }
                    else
                    {
                        if (hasBinaryInclude)
                        {
                            ThrowHelper.ThrowInvalidOperationException_BinaryIncludeOnNonPublicInvalid(fieldInfo, currentType);
                        }

                        // Non-public fields should not be included for (de)serialization.
                    }
                }

                var methods = converter.GetAdditionalDataMethod();
                if (methods != null)
                {
                    foreach (var m in methods)
                    {
                        CacheMember(currentType, m.ReturnType, m, cache, ref ignoredMembers);
                    }
                }
            }

            BinaryPropertyInfo[] cacheArray;
            if (DetermineExtensionDataProperty(cache))
            {
                // Remove from cache since it is handled independently.
                cache.Remove(DataExtensionProperty !.NameAsString);

                cacheArray = new BinaryPropertyInfo[cache.Count + 1];

                // Set the last element to the extension property.
                cacheArray[cache.Count] = DataExtensionProperty;
            }
            else
            {
                cacheArray = new BinaryPropertyInfo[cache.Count];
            }

            // Copy the dictionary cache to the array cache.
            cache.Values.CopyTo(cacheArray, 0);

            // These are not accessed by other threads until the current BinaryClassInfo instance
            // is finished initializing and added to the cache on BinarySerializerOptions.
            PropertyCache      = cache;
            PropertyCacheArray = cacheArray;

            if (converter.ConstructorIsParameterized)
            {
                InitializeConstructorParameters(converter.ConstructorInfo !);
            }

            typeMap.TrySetTypeMemberInfos(TypeSeq, this.GetMemberInfos);
        }