2

I have a class, ClassA which has a property which contains types of ClassB which has a field which is of Type ClassA. When I tried to serialize this via WCF I got an exception due to the recursive nature of this. The solution was to add IsReference=true to the data contract definition of ClassA.

This is great except I have members of ClassA which are marked with the DataMember(IsRequired=true) attribute and once I added the IsReference=true it then complained that things can't be both IsReference=true and have members which are IsRequired=true.

I can't understand why this would be and I would like to know if there is a workaround for this?

I'd like to declare my datamembers so that they required in the xml?

I have seen this post already, but the answer is still not clear to me. If I want to prevent default values from being emitted then I can use the EmitDefaultValues=false along side the IsRequired=true (which is what I want to do anyway). Is there another workaround?

Sam Holder
  • 32,535
  • 13
  • 101
  • 181

1 Answers1

0

Consider the deserialization scenario. You have a bunch of XML that DataContractSerializer is reading in. Imagine that you are dealing with type Foo, which is marked IsReference=true and IsRequired=true.

The serializer encounters a field foo1 of type Foo. Now, this means that the XML could say something like the followin:

<foo1 ref="1" /?

The serializer would deserialize foo1 to null, but remember that it referenced an object it does not yet have. THe serializer goes on to deserialize the remaining fields. Eventually, it encounters another field like the one below. Aha, it sees the object that foo1 referred to earlier -- the object with ID of 1.

<foo2 id="1"> <datamember1> ... </datamember1> <datamember2> ... </datamember2> </foo2>

When it encounters id="1", the serializer goes back and fixes up foo1 to point to foo2.

However, it is possible for foo2 to never exist. In other words, foo1 could be refering to an ID that does not exist anywhere else in the XML. There is no way for the serializer to know this for sure until it has fully deserialized the rest of the graph.

I hope you begin to see the problem. If a type were both IsReference and IsReequired, it is no longer possible for the serialize to guarantee that the IsRequired nature of the type will be honored during deserialization. It can no longer fail fast if the required element does not exist, because it cannot be sure whether it exists.

krisragh MSFT
  • 1,908
  • 1
  • 13
  • 22
  • Thanks Krisragh, but the IsRequired flag is not allowed *on members of `Foo`* not on instances of `Foo` in other classes. Your explanation doesn't shed any light on why I can't have a field which is required on Foo, just because references to Foo are shared. – Sam Holder Apr 20 '11 at 07:23
  • Sam -- actually, my expalanation does answer your question. The argument I described applies to members of Foo in exactly the same way; note that in the explanation, it does not matter whether the IsRequired is on the type itself or on a member of that type. The ordering and references issues manifest themselves in the same way. – krisragh MSFT Apr 21 '11 at 04:04
  • maybe I am just being dim but I fail to see how the argument applies to members of Foo. With IsRequired=true (and with EmitDefaultValue=false as well) I am basically saying, when this type is included in the xml document an element for this member must be part document (and with EmitDefaultValue the element must not be empty). I fail to see how this has an effect on whether any instance of Foo is referenced or not. If an instance of Foo exists in the document then these attributes affect how it is defined, and thts it don't they? if that instance is shared, then so be it. – Sam Holder Apr 21 '11 at 08:23