55using  System . Collections . Generic ; 
66using  System . Diagnostics ; 
77using  System . Diagnostics . CodeAnalysis ; 
8+ using  System . Globalization ; 
89using  System . Reflection ; 
910using  System . Text ; 
1011using  System . Xml . Schema ; 
@@ -125,7 +126,7 @@ private void WriteMember(object? o, object? choiceSource, ElementAccessor[] elem
125126            } 
126127            else 
127128            { 
128-                 WriteElements ( o ,  elements ,  text ,  choice ,  writeAccessors ,  memberTypeDesc . IsNullable ) ; 
129+                 WriteElements ( o ,  choiceSource ,   elements ,  text ,  choice ,  writeAccessors ,  memberTypeDesc . IsNullable ) ; 
129130            } 
130131        } 
131132
@@ -150,11 +151,11 @@ private void WriteArray(object o, object? choiceSource, ElementAccessor[] elemen
150151                } 
151152            } 
152153
153-             WriteArrayItems ( elements ,  text ,  choice ,  o ) ; 
154+             WriteArrayItems ( elements ,  text ,  choice ,  o ,   choiceSource ) ; 
154155        } 
155156
156157        [ RequiresUnreferencedCode ( "calls WriteElements" ) ] 
157-         private  void  WriteArrayItems ( ElementAccessor [ ]  elements ,  TextAccessor ?  text ,  ChoiceIdentifierAccessor ?  choice ,  object  o ) 
158+         private  void  WriteArrayItems ( ElementAccessor [ ]  elements ,  TextAccessor ?  text ,  ChoiceIdentifierAccessor ?  choice ,  object  o ,   object ?   choiceSources ) 
158159        { 
159160            var  arr  =  o  as  IList ; 
160161
@@ -163,7 +164,8 @@ private void WriteArrayItems(ElementAccessor[] elements, TextAccessor? text, Cho
163164                for  ( int  i  =  0 ;  i  <  arr . Count ;  i ++ ) 
164165                { 
165166                    object ?  ai  =  arr [ i ] ; 
166-                     WriteElements ( ai ,  elements ,  text ,  choice ,  true ,  true ) ; 
167+                     var  choiceSource  =  ( ( Array ? ) choiceSources ) ? . GetValue ( i ) ; 
168+                     WriteElements ( ai ,  choiceSource ,  elements ,  text ,  choice ,  true ,  true ) ; 
167169                } 
168170            } 
169171            else 
@@ -174,17 +176,18 @@ private void WriteArrayItems(ElementAccessor[] elements, TextAccessor? text, Cho
174176                IEnumerator  e  =  a . GetEnumerator ( ) ; 
175177                if  ( e  !=  null ) 
176178                { 
179+                     int  c  =  0 ; 
177180                    while  ( e . MoveNext ( ) ) 
178181                    { 
179182                        object  ai  =  e . Current ; 
180-                         WriteElements ( ai ,  elements ,  text ,  choice ,  true ,  true ) ; 
183+                         var  choiceSource  =  ( ( Array ? ) choiceSources ) ? . GetValue ( c ++ ) ; 
184+                         WriteElements ( ai ,  choiceSource ,  elements ,  text ,  choice ,  true ,  true ) ; 
181185                    } 
182186                } 
183187            } 
184188        } 
185- 
186189        [ RequiresUnreferencedCode ( "calls CreateUnknownTypeException" ) ] 
187-         private  void  WriteElements ( object ?  o ,  ElementAccessor [ ]  elements ,  TextAccessor ?  text ,  ChoiceIdentifierAccessor ?  choice ,  bool  writeAccessors ,  bool  isNullable ) 
190+         private  void  WriteElements ( object ?  o ,  object ?   choiceSource ,   ElementAccessor [ ]  elements ,  TextAccessor ?  text ,  ChoiceIdentifierAccessor ?  choice ,  bool  writeAccessors ,  bool  isNullable ) 
188191        { 
189192            if  ( elements . Length  ==  0  &&  text  ==  null ) 
190193                return ; 
@@ -222,16 +225,35 @@ private void WriteElements(object? o, ElementAccessor[] elements, TextAccessor?
222225                    } 
223226                    else  if  ( choice  !=  null ) 
224227                    { 
225-                         if  ( o  !=  null  &&  o . GetType ( )  ==  element . Mapping ! . TypeDesc ! . Type ) 
228+                         // This looks heavy - getting names of enums in string form for comparison rather than just comparing values. 
229+                         // But this faithfully mimics NetFx, and is necessary to prevent confusion between different enum types. 
230+                         // ie EnumType.ValueX could == 1, but TotallyDifferentEnumType.ValueY could also == 1. 
231+                         TypeDesc  td  =  element . Mapping ! . TypeDesc ! ; 
232+                         bool  enumUseReflection  =  choice . Mapping ! . TypeDesc ! . UseReflection ; 
233+                         string  enumTypeName  =  choice . Mapping ! . TypeDesc ! . FullName ; 
234+                         string  enumFullName  =  ( enumUseReflection  ?  ""  :  enumTypeName  +  ".@" )  +  FindChoiceEnumValue ( element ,  ( EnumMapping ) choice . Mapping ,  enumUseReflection ) ; 
235+                         string  choiceFullName  =  ( enumUseReflection  ?  ""  :  choiceSource ! . GetType ( ) . FullName  +  ".@" )  +  choiceSource ! . ToString ( ) ; 
236+ 
237+                         if  ( choiceFullName  ==  enumFullName ) 
226238                        { 
227-                             WriteElement ( o ,  element ,  writeAccessors ) ; 
228-                             return ; 
239+                             // Object is either non-null, or it is allowed to be null 
240+                             if  ( o  !=  null  ||  ( ! isNullable  ||  element . IsNullable ) ) 
241+                             { 
242+                                 // But if Object is non-null, it's got to match types 
243+                                 if  ( o  !=  null  &&  ! td . Type ! . IsAssignableFrom ( o ! . GetType ( ) ) ) 
244+                                 { 
245+                                     throw  CreateMismatchChoiceException ( td . FullName ,  choice . MemberName ! ,  enumFullName ) ; 
246+                                 } 
247+ 
248+                                 WriteElement ( o ,  element ,  writeAccessors ) ; 
249+                                 return ; 
250+                             } 
229251                        } 
230252                    } 
231253                    else 
232254                    { 
233255                        TypeDesc  td  =  element . IsUnbounded  ?  element . Mapping ! . TypeDesc ! . CreateArrayTypeDesc ( )  :  element . Mapping ! . TypeDesc ! ; 
234-                         if  ( o ! . GetType ( )   ==   td . Type ) 
256+                         if  ( td . Type ! . IsAssignableFrom ( o ! . GetType ( ) ) ) 
235257                        { 
236258                            WriteElement ( o ,  element ,  writeAccessors ) ; 
237259                            return ; 
@@ -280,6 +302,58 @@ private void WriteElements(object? o, ElementAccessor[] elements, TextAccessor?
280302            } 
281303        } 
282304
305+         private  static   string  FindChoiceEnumValue ( ElementAccessor  element ,  EnumMapping  choiceMapping ,  bool  useReflection ) 
306+         { 
307+             string ?  enumValue  =  null ; 
308+ 
309+             for  ( int  i  =  0 ;  i  <  choiceMapping . Constants ! . Length ;  i ++ ) 
310+             { 
311+                 string  xmlName  =  choiceMapping . Constants [ i ] . XmlName ; 
312+ 
313+                 if  ( element . Any  &&  element . Name . Length  ==  0 ) 
314+                 { 
315+                     if  ( xmlName  ==  "##any:" ) 
316+                     { 
317+                         if  ( useReflection ) 
318+                             enumValue  =  choiceMapping . Constants [ i ] . Value . ToString ( CultureInfo . InvariantCulture ) ; 
319+                         else 
320+                             enumValue  =  choiceMapping . Constants [ i ] . Name ; 
321+                         break ; 
322+                     } 
323+                     continue ; 
324+                 } 
325+                 int  colon  =  xmlName . LastIndexOf ( ':' ) ; 
326+                 string ?  choiceNs  =  colon  <  0  ?  choiceMapping . Namespace  :  xmlName . Substring ( 0 ,  colon ) ; 
327+                 string  choiceName  =  colon  <  0  ?  xmlName  :  xmlName . Substring ( colon  +  1 ) ; 
328+ 
329+                 if  ( element . Name  ==  choiceName ) 
330+                 { 
331+                     if  ( ( element . Form  ==  XmlSchemaForm . Unqualified  &&  string . IsNullOrEmpty ( choiceNs ) )  ||  element . Namespace  ==  choiceNs ) 
332+                     { 
333+                         if  ( useReflection ) 
334+                             enumValue  =  choiceMapping . Constants [ i ] . Value . ToString ( CultureInfo . InvariantCulture ) ; 
335+                         else 
336+                             enumValue  =  choiceMapping . Constants [ i ] . Name ; 
337+                         break ; 
338+                     } 
339+                 } 
340+             } 
341+ 
342+             if  ( string . IsNullOrEmpty ( enumValue ) ) 
343+             { 
344+                 if  ( element . Any  &&  element . Name . Length  ==  0 ) 
345+                 { 
346+                     // Type {0} is missing enumeration value '##any' for XmlAnyElementAttribute. 
347+                     throw  new  InvalidOperationException ( SR . Format ( SR . XmlChoiceMissingAnyValue ,  choiceMapping . TypeDesc ! . FullName ) ) ; 
348+                 } 
349+                 // Type {0} is missing value for '{1}'. 
350+                 throw  new  InvalidOperationException ( SR . Format ( SR . XmlChoiceMissingValue ,  choiceMapping . TypeDesc ! . FullName ,  element . Namespace  +  ":"  +  element . Name ,  element . Name ,  element . Namespace ) ) ; 
351+             } 
352+             if  ( ! useReflection ) 
353+                 CodeIdentifier . CheckValidIdentifier ( enumValue ) ; 
354+             return  enumValue ; 
355+         } 
356+ 
283357        private  void  WriteText ( object  o ,  TextAccessor  text ) 
284358        { 
285359            if  ( text . Mapping  is  PrimitiveMapping  primitiveMapping ) 
@@ -376,7 +450,7 @@ private void WriteElement(object? o, ElementAccessor element, bool writeAccessor
376450                    if  ( o  !=  null ) 
377451                    { 
378452                        WriteStartElement ( name ,  ns ,  false ) ; 
379-                         WriteArrayItems ( mapping . ElementsSortedByDerivation ! ,  null ,  null ,  o ) ; 
453+                         WriteArrayItems ( mapping . ElementsSortedByDerivation ! ,  null ,  null ,  o ,   null ) ; 
380454                        WriteEndElement ( ) ; 
381455                    } 
382456                } 
0 commit comments