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));
        }
        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);
        }