Stack overflow with circular reference

Jan 10, 2014 at 11:14 PM
I have found a couple of discussions about circular references and a work item 8018 that was created and closed, but I'm having an issue. Is there a solution when the DTD has a circular reference.

DTD example:

<!ELEMENT PriceSheet (AccessorialTotal, ..., AssociatedCarrierPricesheet?)>
<!ELEMENT AssociatedCarrierPricesheet (PriceSheet)>

I have turned on LazyLoading which gets me further, but when I try to Serialize I get the stack overflow error.
Jan 10, 2014 at 11:36 PM
I posted the code change that I used to get around this problem several years ago. I experienced the same issue with Lazy Loading that you mentioned (i.e. the stack overflow gets deferred from class instantiation until serialization) I haven't run this in a long time, but last year a coworker ran into the same problem and added the code change to fix the problem.

Randy Okubo



Jan 16, 2014 at 2:11 PM
Thanks for the direction. I went back and read your changes. The source has changed since then, but I believe I made your 2 changes.

Can you review and see if I missed something?

Also, at what point do you need to manually instantiate the recursive element?
per: I can now instantiate any recursive class without a StackOverflowException. However, I also have to manually instantiate each recursive element.

First change:
            if (GeneratorContext.GeneratorParams.EnableInitializeFields && GeneratorContext.GeneratorParams.CollectionObjectType != CollectionType.Array)
            {
                bool finded;
                CodeTypeDeclaration declaration = this.FindTypeInNamespace(field.Type.BaseType, ns, out finded);
                if (thisIsCollectionType ||
                    (((declaration != null) && declaration.IsClass)
                     && ((declaration.TypeAttributes & TypeAttributes.Abstract) != TypeAttributes.Abstract)
                     && ctor.Name != field.Type.BaseType))                               //new
                {
                    if (GeneratorContext.GeneratorParams.PropertyParams.EnableLazyLoading)
                    {
                        LazyLoadingFields.Add(field.Name);
                    }
                    else
                    {
                        if (field.Type.BaseType != "System.Byte")
                        {
                            ctor.Statements.Insert(0, this.CreateInstance(field.Name, field.Type));
                            addedToConstructor = true;
                        }
                    }
                }
            }
Second change:
        protected virtual CodeConstructor GetConstructor(CodeTypeDeclaration type, ref bool newCTor)
        {
            CodeConstructor ctor = null;
            foreach (CodeTypeMember member in type.Members)
            {
                if (member is CodeConstructor)
                    ctor = member as CodeConstructor;
            }

            if (ctor == null)
            {
                newCTor = true;
                ctor = this.CreateClassConstructor(type);
                ctor.Name = type.Name;                                  //new
            }

            if (GeneratorContext.GeneratorParams.Miscellaneous.EnableSummaryComment)
                CodeDomHelper.CreateSummaryComment(ctor.Comments, string.Format("{0} class constructor", ctor.Name));

            return ctor;
        }
I then compiled the solution and updated files in the XSD2Code folder where they were installed. This include 3 files (Xsd2Code.exe, Xsd2Code.Addin.dll and Xsd2Code.Library.dll). I restarted VS2013 and ran the XSD2Code generation. I still have the same issue. Looking at the generated code it appears nothing has changed. I still get ... new Class() statement in both get property methods.

Is it good enough to just replace the previous binary files with newly compile ones (may be the new binaries are not be used)?

Property of PriceSheet
        public AssociatedCarrierPricesheet AssociatedCarrierPricesheet {
            get {
                if ((this.associatedCarrierPricesheetField == null)) {
                    this.associatedCarrierPricesheetField = new AssociatedCarrierPricesheet();
                }
                return this.associatedCarrierPricesheetField;
            }
            set {
                this.associatedCarrierPricesheetField = value;
            }
        }
Property of AssociatedCarrierPricesheet
        public PriceSheet PriceSheet {
            get {
                if ((this.priceSheetField == null)) {
                    this.priceSheetField = new PriceSheet();
                }
                return this.priceSheetField;
            }
            set {
                this.priceSheetField = value;
            }
        }