CMertens / protobuf-net

Automatically exported from code.google.com/p/protobuf-net
Other
0 stars 0 forks source link

DataContractAttribute IsReference is not supported. #325

Open GoogleCodeExporter opened 9 years ago

GoogleCodeExporter commented 9 years ago
Please include an e-mail address if this might need a dialogue!
==============

What steps will reproduce the problem?
1. Set the DataContractAttribute IsReference value to true.
2. Attempt to serialize an object graph with a circular reference.

What is the expected output? What do you see instead?
The expected output is that protobuf recognizes that DataContractAttribute 
IsReference has been applied to types and applies the ProtoMember AsReference 
when appropriate, yielding the correst serialized output and not entering an 
infinite recursive loop.  What is observed is that currently protobuf will 
enter an infinite recursive loop when trying to serialize such an object 
defined using only the DataContract attributes.

What version of the product are you using? On what operating system?
trunk revision 592.

Please provide any additional information below.
I pulled the sources to test out a possible solution for this before submitting 
the issue.  I have made some local updates to test how I would have liked this 
to work.  Here is a chunk of code I inserted into the 
MetaType::NormalizeProtoMember method to get the desired behavior for this.

            if (!ignore && !done && HasFamily(family, AttributeFamily.DataContractSerialier))
            {
                attrib = GetAttribute(attribs, "System.Runtime.Serialization.DataMemberAttribute");
                if (attrib != null)
                {
                    /*
                     * ***********  Begin new code to handle IsReference value from DataContractAttribute
                     */
                    // TODO: move this to method
                    //
                    // Check for DataContract IsReference attribute value
                    // and apply ProtoMember AsReference attribute value
                    // if found...
                    {
                        // Get the field or property type depending
                        // on if this member is a field or property.
                        Type memberType = null;
                        switch (member.MemberType)
                        {
                            case MemberTypes.Field:
                                {
                                    FieldInfo info = member as FieldInfo;
                                    if (info != null)
                                    {
                                        memberType = info.FieldType;
                                    }
                                }
                                break;
                            case MemberTypes.Property:
                                {
                                    PropertyInfo info = member as PropertyInfo;
                                    if (info != null)
                                    {
                                        memberType = info.PropertyType;
                                    }
                                }
                                break;
                        }

                        // If this member is a field or property then we should
                        // now have a type for it, so lets check to see if this
                        // type should use reference tracking.
                        if (memberType != null)
                        {
                            // Query for the data contract attribute from this type.
                            // the DataContract attribute is not inherited so we don't
                            // need to bother searching the inheritance chain for it,
                            // and we only expect to have one of them defined on the class.
                            object[] memberTypeAttrs = memberType.GetCustomAttributes(
                                typeof(System.Runtime.Serialization.DataContractAttribute), false);
                            if (memberTypeAttrs != null && memberTypeAttrs.Length == 1)
                            {
                                // If we found the attribute then check the IsReference
                                // value and use that to indicate if we should use reference
                                // tracking for this member.
                                System.Runtime.Serialization.DataContractAttribute dcAttr =
                                    memberTypeAttrs[0] as System.Runtime.Serialization.DataContractAttribute;
                                asReference = dcAttr.IsReference;
                            }
                        }
                    }
                    /*
                     * ***********  End new code to handle IsReference value from DataContractAttribute
                     */

                    GetFieldNumber(ref fieldNumber, attrib, "Order");
                    GetFieldName(ref name, attrib, "Name");
                    GetFieldBoolean(ref isRequired, attrib, "IsRequired");
                    done = fieldNumber >= minAcceptFieldNumber;
                    if (done) fieldNumber += dataMemberOffset; // dataMemberOffset only applies to DCS flags, to allow us to "bump" WCF by a notch
                }
            }

Original issue reported on code.google.com by mst...@symbotic.com on 25 Sep 2012 at 3:41

Attachments: