AqlaSolutions / AqlaSerializer

Binary serializer with full .NET support!
http://www.aqla.net
Other
17 stars 3 forks source link

Recursion depth exceeded safe limit #46

Closed inethui closed 2 years ago

inethui commented 2 years ago

The following test "TestDistribution" results in an exception. AqlaSerializer.ProtoException : Recursion depth exceeded safe limit. See TypeModel.RecursionDepthLimit.

Any idea what is wrong? Thanks

    private void SetupModel()
    {
        var metaType2 = AqlaSerializer.Meta.RuntimeTypeModel.Default.Add(typeof(Surrogate), false);
        metaType2.DefaultFormat = AqlaSerializer.ValueFormat.Reference;
        metaType2.UseConstructor = false;
        var metaField1 = metaType2.AddField(1, "_distribution");
        metaField1.SetSettings(x => { x.V.Format = AqlaSerializer.ValueFormat.Reference; });

        var metaType3 = AqlaSerializer.Meta.RuntimeTypeModel.Default.Add(typeof(Distribution), false);
        metaType3.DefaultFormat = AqlaSerializer.ValueFormat.Reference;
        metaType3.UseConstructor = false;

        AqlaSerializer.Meta.MetaType metaType4 = AqlaSerializer.Meta.RuntimeTypeModel.Default[typeof(ILoader)];
        metaType4.AddSubType(1, typeof(Distribution));
        metaType4.SetSurrogate(typeof(Surrogate));

        var metaType6 = AqlaSerializer.Meta.RuntimeTypeModel.Default.Add(typeof(Instrument), false);
        metaType6.DefaultFormat = AqlaSerializer.ValueFormat.Reference;
        metaType6.UseConstructor = false;
        var metaField2 = metaType6.AddField(1, "_loader");
        metaField2.SetSettings(x => { x.V.Format = AqlaSerializer.ValueFormat.Reference; });
    }

    [Test]
    public void TestDistribution()
    {
        SetupModel();

        var inst = new Instrument()
        {
            Loader = new Distribution()
        };

        var clone = AqlaSerializer.Serializer.DeepClone(inst);

        Assert.NotNull(clone);
    }

    private class Instrument
    {
        private ILoader _loader;

        public ILoader Loader
        {
            get { return _loader; }
            set { _loader = value; }
        }
    }

    private class Distribution : ILoader
    {
        public IReadOnlyDictionary<int, double> GetDistribution()
        {
            throw new NotImplementedException();
        }
    }

    private class DefaultLoader : ILoader
    {
        public IReadOnlyDictionary<int, double> GetDistribution()
        {
            return new ReadOnlyDictionary<int, double>(new Dictionary<int, double>());
        }
    }

    private interface ILoader
    {
        IReadOnlyDictionary<int, double> GetDistribution();
    }

    private class Surrogate
    {
        private Distribution _distribution;

        [ProtoConverter]
        public static ILoader FromSurrogate(Surrogate surrogate)
        {
            if (surrogate == null)
                return null;

            if (surrogate._distribution != null)
                return surrogate._distribution;

            return new DefaultLoader();
        }

        [ProtoConverter]
        public static Surrogate ToSurrogate(ILoader loader)
        {
            if (loader == null)
                return null;

            var distribution = loader as Distribution;
            return new Surrogate { _distribution = distribution };
        }
    }
inethui commented 2 years ago

Found a workaround on our side.

AqlaSolutions commented 2 years ago

The surrogate contains Distrubution which is itself an ILoader which needs to be converted into surrogate before serialization. This won't work.