// property serialization defaults


        /// <summary>
        /// Returns true if the given property should be serialized.
        ///
        /// Override to tweak behavior.
        /// </summary>
        protected virtual bool ShouldSerialize(TypeInfo forType, PropertyInfo property)
        {
            if (property.GetMethod == null)
            {
                return(false);
            }

            var ignoreDataMember = property.GetCustomAttribute <IgnoreDataMemberAttribute>();

            if (ignoreDataMember != null)
            {
                return(false);
            }

            var dataMember = property.GetCustomAttribute <DataMemberAttribute>();

            if (dataMember != null)
            {
                return(true);
            }

            return
                (property.GetMethod.IsPublic &&
                 !property.GetMethod.IsStatic &&
                 property.GetMethod.GetParameters().Length == 0 &&
                 property.GetMethod.ReturnType != Types.VoidType &&
                 SerializableMember.GetDefaultFormatter(property.GetMethod.ReturnType.GetTypeInfo()) != null);
        }
        private static SerializableMember Map(TypeInfo ontoType, SerializableMember member)
        {
            ShouldSerialize?shouldSerializeOnType;

            if (member.ShouldSerialize.HasValue)
            {
                var surrogateShouldSerializeWrapper = member.ShouldSerialize.Value;
                if (surrogateShouldSerializeWrapper.Mode == BackingMode.Method)
                {
                    if (surrogateShouldSerializeWrapper.Takes.HasValue && surrogateShouldSerializeWrapper.IsStatic)
                    {
                        Throw.InvalidOperationException($"Cannot map 'should serialize' {surrogateShouldSerializeWrapper} onto {ontoType}, it takes a parameter");
                    }

                    var surrogateShouldSerialize        = surrogateShouldSerializeWrapper.Method.Value;
                    var surrogateShouldSerializeBinding = GetEquivalentFlagsFor(surrogateShouldSerialize.IsPublic, surrogateShouldSerialize.IsStatic);

                    // intentionally letting this be null
                    var shouldSerializeOnTypeMtd = ontoType.GetMethod(surrogateShouldSerialize.Name, surrogateShouldSerializeBinding);
                    if (shouldSerializeOnTypeMtd == null)
                    {
                        Throw.InvalidOperationException($"No equivalent to {surrogateShouldSerialize} found on {ontoType}");
                    }

                    shouldSerializeOnType = ShouldSerialize.ForMethod(shouldSerializeOnTypeMtd);
                }
                else
                {
                    Throw.InvalidOperationException($"Cannot map 'should serialize' {surrogateShouldSerializeWrapper} onto {ontoType}, 'should serialize' isn't backed by a method");
                    return(default);
Example #3
0
        // internal for testing purposes
        internal ManualTypeDescriberBuilder WithSerializableMember(TypeInfo?forType, Getter?getter, string?name, Formatter?formatter, ShouldSerialize?shouldSerialize, EmitDefaultValue emitDefault)
        {
            if (forType == null)
            {
                Throw.ArgumentNullException(nameof(forType));
            }

            if (getter == null)
            {
                Throw.ArgumentNullException(nameof(getter));
            }

            if (name == null)
            {
                Throw.ArgumentNullException(nameof(name));
            }

            if (formatter == null)
            {
                Throw.ArgumentNullException(nameof(name));
            }

            // shouldSerialize can be null

            if (getter.RowType.HasValue)
            {
                var      getterOnType = getter.RowType.Value;
                var      isLegal      = false;
                TypeInfo?cur          = forType;

                while (cur != null)
                {
                    if (cur == getterOnType)
                    {
                        isLegal = true;
                        break;
                    }

                    cur = cur?.BaseType?.GetTypeInfo();
                }

                if (!isLegal)
                {
                    Throw.InvalidOperationException($"Provided getter ({getter}) is not on {forType} or one of it's base types.");
                }
            }

            var toAdd = SerializableMember.Create(forType, name, getter, formatter, shouldSerialize, emitDefault);

            if (!Serializers.TryGetValue(forType, out var s))
            {
                Serializers[forType] = s = ImmutableArray.CreateBuilder <SerializableMember>();
            }

            s.Add(toAdd);

            return(this);
        }
Example #4
0
        /// <summary>
        /// Enumerate members which will be serialized for the given type.
        ///
        /// Note that these members are generated ahead of time with a source gneerator,
        ///   and cannot be changed at runtime.
        /// </summary>
        public IEnumerable <SerializableMember> EnumerateMembersToSerialize(TypeInfo forType)
        {
            var paired = GetPairedType(forType, SERIALIZER_KIND);

            if (paired == null)
            {
                return(Enumerable.Empty <SerializableMember>());
            }

            var colNamesField = paired.GetFieldNonNull("ColumnNames", PublicStatic);
            var colNames      = (ImmutableArray <string>)colNamesField.GetValueNonNull(null);

            var ret = ImmutableArray.CreateBuilder <SerializableMember>(colNames.Length);

            for (var i = 0; i < colNames.Length; i++)
            {
                var name = colNames[i];

                var colWriterName = $"__Column_{i}";
                var colWriterMtd  = paired.GetMethodNonNull(colWriterName, PublicStatic);

#pragma warning disable CS0618 // This is obsolete to prevent clients from using them, but they are fine for us.
                var emitsDefaultValue = colWriterMtd.GetCustomAttribute <DoesNotEmitDefaultValueAttribute>() == null;
#pragma warning restore CS0618

                var shouldSerializeName = $"__Column_{i}_ShouldSerialize";
                var shouldSerializeMtd  = paired.GetMethod(shouldSerializeName, PublicStatic);
                var shouldSerialize     = (ShouldSerialize?)shouldSerializeMtd;

                var getterName = $"__Column_{i}_Getter";
                var getterMtd  = paired.GetMethodNonNull(getterName, PublicStatic);
                var getter     = Getter.ForMethod(getterMtd);

                var       formatterName = $"__Column_{i}_Formatter";
                var       formatterMtd  = paired.GetMethod(formatterName, PublicStatic);
                Formatter formatter;
                if (formatterMtd == null)
                {
                    // if a method isn't provided, it must be using the default
                    formatter = Utils.NonNull(Formatter.GetDefault(getter.Returns));
                }
                else
                {
                    formatter = Formatter.ForMethod(formatterMtd);
                }


                ret.Add(SerializableMember.ForGeneratedMethod(name, colWriterMtd, getter, formatter, shouldSerialize, emitsDefaultValue));
            }

            return(ret.ToImmutable());
        }
        /// <summary>
        /// Enumerate all columns to deserialize.
        /// </summary>
        public virtual IEnumerable <SerializableMember> EnumerateMembersToSerialize(TypeInfo forType)
        {
            var buffer = new List <(SerializableMember Member, int?Position)>();

            foreach (var p in forType.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance))
            {
                if (!ShouldSerialize(forType, p))
                {
                    continue;
                }

                var name            = GetSerializationName(forType, p);
                var getter          = GetGetter(forType, p);
                var shouldSerialize = GetShouldSerializeMethod(forType, p);
                var formatter       = GetFormatter(forType, p);
                var order           = GetPosition(forType, p);
                var emitDefault     = GetEmitDefaultValue(forType, p);

                buffer.Add((SerializableMember.Create(forType, name, getter, formatter, shouldSerialize, emitDefault), order));
            }

            foreach (var f in forType.GetFields())
            {
                if (!ShouldSerialize(forType, f))
                {
                    continue;
                }

                var name            = GetSerializationName(forType, f);
                var shouldSerialize = GetShouldSerializeMethod(forType, f);
                var formatter       = GetFormatter(forType, f);
                var order           = GetPosition(forType, f);
                var emitDefault     = GetEmitDefaultValue(forType, f);

                buffer.Add((SerializableMember.Create(forType, name, f, formatter, shouldSerialize, emitDefault), order));
            }

            buffer.Sort(TypeDescribers.SerializableComparer);

            foreach (var(member, _) in buffer)
            {
                yield return(member);
            }
        }
 // common serialization defaults
 private static MethodInfo GetFormatter(TypeInfo t)
 => SerializableMember.GetDefaultFormatter(t);
Example #7
0
        private static SerializableMember Map(TypeInfo ontoType, SerializableMember member)
        {
            MethodInfo shouldSerializeOnType;

            if (member.ShouldSerialize != null)
            {
                var surrogateShouldSerialize        = member.ShouldSerialize;
                var surrogateShouldSerializeBinding =
                    // explicitly ignoring DeclaredOnly; shadowing is fine
                    (surrogateShouldSerialize.IsPublic ? BindingFlags.Public : BindingFlags.NonPublic) |
                    (surrogateShouldSerialize.IsStatic ? BindingFlags.Static : BindingFlags.Instance);

                shouldSerializeOnType = ontoType.GetMethod(surrogateShouldSerialize.Name, surrogateShouldSerializeBinding);
                if (shouldSerializeOnType == null)
                {
                    Throw.InvalidOperationException($"No equivalent to {surrogateShouldSerialize} found on {ontoType}");
                }
            }
            else
            {
                shouldSerializeOnType = null;
            }


            if (member.Field != null)
            {
                var surrogateField        = member.Field;
                var surrogateFieldBinding =
                    // explicitly ignoring DeclaredOnly; shadowing is fine
                    (surrogateField.IsPublic ? BindingFlags.Public : BindingFlags.NonPublic) |
                    (surrogateField.IsStatic ? BindingFlags.Static : BindingFlags.Instance);

                var fieldOnType = ontoType.GetField(surrogateField.Name, surrogateFieldBinding);
                if (fieldOnType == null)
                {
                    Throw.InvalidOperationException($"No equivalent to {surrogateField} found on {ontoType}");
                }

                if (fieldOnType.FieldType != surrogateField.FieldType)
                {
                    Throw.InvalidOperationException($"Field {fieldOnType} type ({fieldOnType.FieldType}) does not match surrogate field {surrogateField} type ({surrogateField.FieldType})");
                }

                return(SerializableMember.Create(ontoType, member.Name, fieldOnType, member.Formatter, shouldSerializeOnType, member.EmitDefaultValue));
            }

            var surrogateGetter        = member.Getter;
            var surrogateGetterBinding =
                // explicitly ignoring DeclaredOnly; shadowing is fine
                (surrogateGetter.IsPublic ? BindingFlags.Public : BindingFlags.NonPublic) |
                (surrogateGetter.IsStatic ? BindingFlags.Static : BindingFlags.Instance);

            var getterOnType = ontoType.GetMethod(surrogateGetter.Name, surrogateGetterBinding);

            if (getterOnType == null)
            {
                Throw.InvalidOperationException($"No equivalent to {surrogateGetter} found on {ontoType}");
            }

            var surrogateParams = surrogateGetter.GetParameters();
            var onTypeParams    = getterOnType.GetParameters();

            if (surrogateParams.Length != onTypeParams.Length)
            {
                Throw.InvalidOperationException($"Parameters for {getterOnType} do not match parameters for {surrogateGetter}");
            }

            for (var i = 0; i < surrogateParams.Length; i++)
            {
                var sP = surrogateParams[i].ParameterType.GetTypeInfo();
                var tP = onTypeParams[i].ParameterType.GetTypeInfo();

                if (sP != tP)
                {
                    Throw.InvalidOperationException($"Parameter #{(i + 1)} on {getterOnType} does not match same parameter on {surrogateGetter}");
                }
            }

            return(SerializableMember.Create(ontoType, member.Name, getterOnType, member.Formatter, shouldSerializeOnType, member.EmitDefaultValue));
        }