~ubuntu-branches/ubuntu/oneiric/monodevelop/oneiric-updates

« back to all changes in this revision

Viewing changes to src/core/MonoDevelop.Core/MonoDevelop.Core.Serialization/ClassDataType.cs

  • Committer: Bazaar Package Importer
  • Author(s): Jo Shields
  • Date: 2009-02-18 08:40:51 UTC
  • mfrom: (1.2.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20090218084051-gh8m6ukvokbwj7cf
Tags: 1.9.2+dfsg-1ubuntu1
* Merge from Debian Experimental (LP: #330519), remaining Ubuntu changes:
  + debian/control:
    - Update for Gnome# 2.24
    - Add libmono-cairo1.0-cil to build-deps to fool pkg-config check

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
//
 
2
// ClassDataType.cs
 
3
//
 
4
// Author:
 
5
//   Lluis Sanchez Gual
 
6
//
 
7
// Copyright (C) 2005 Novell, Inc (http://www.novell.com)
 
8
//
 
9
// Permission is hereby granted, free of charge, to any person obtaining
 
10
// a copy of this software and associated documentation files (the
 
11
// "Software"), to deal in the Software without restriction, including
 
12
// without limitation the rights to use, copy, modify, merge, publish,
 
13
// distribute, sublicense, and/or sell copies of the Software, and to
 
14
// permit persons to whom the Software is furnished to do so, subject to
 
15
// the following conditions:
 
16
// 
 
17
// The above copyright notice and this permission notice shall be
 
18
// included in all copies or substantial portions of the Software.
 
19
// 
 
20
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 
21
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 
22
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 
23
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 
24
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 
25
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 
26
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
27
//
 
28
 
 
29
using System;
 
30
using System.Collections;
 
31
using System.Collections.Generic;
 
32
using System.Reflection;
 
33
 
 
34
namespace MonoDevelop.Core.Serialization
 
35
{
 
36
        public class ClassDataType: DataType
 
37
        {
 
38
                Hashtable properties = new Hashtable ();
 
39
                List<ItemProperty> sortedPoperties = new List<ItemProperty> ();
 
40
                ArrayList subtypes;
 
41
                Type fallbackType;
 
42
                
 
43
                public ClassDataType (Type propType): base (propType)
 
44
                {
 
45
                }
 
46
                
 
47
                public override bool IsSimpleType { get { return false; } }
 
48
                public override bool CanCreateInstance { get { return true; } }
 
49
                public override bool CanReuseInstance { get { return true; } }
 
50
                
 
51
                protected override void Initialize ()
 
52
                {
 
53
                        DataItemAttribute atd = (DataItemAttribute) Context.AttributeProvider.GetCustomAttribute (ValueType, typeof(DataItemAttribute), false);
 
54
                        if (atd != null) {
 
55
                                if (!string.IsNullOrEmpty (atd.Name)) {
 
56
                                        Name = atd.Name;
 
57
                                }
 
58
                                if (atd.FallbackType != null) {
 
59
                                        fallbackType = atd.FallbackType;
 
60
                                        if (!typeof(IExtendedDataItem).IsAssignableFrom (fallbackType))
 
61
                                                throw new InvalidOperationException ("Fallback type '" + fallbackType + "' must implement IExtendedDataItem");
 
62
                                        if (!ValueType.IsAssignableFrom (fallbackType))
 
63
                                                throw new InvalidOperationException ("Fallback type '" + fallbackType + "' must be a subclass of '" + ValueType + "'");
 
64
                                }
 
65
                        }
 
66
                        
 
67
                        object[] incs = Attribute.GetCustomAttributes (ValueType, typeof (DataIncludeAttribute), true);
 
68
                        foreach (DataIncludeAttribute incat in incs) {
 
69
                                Context.IncludeType (incat.Type);
 
70
                        }
 
71
                        
 
72
                        if (ValueType.BaseType != null) {
 
73
                                ClassDataType baseType = (ClassDataType) Context.GetConfigurationDataType (ValueType.BaseType);
 
74
                                baseType.AddSubtype (this);
 
75
                                int n=0;
 
76
                                foreach (ItemProperty prop in baseType.Properties) {
 
77
                                        properties.Add (prop.Name, prop);
 
78
                                        sortedPoperties.Insert (n++, prop);
 
79
                                }
 
80
                                
 
81
                                // Inherit the fallback type
 
82
                                if (fallbackType == null && baseType.fallbackType != null)
 
83
                                        fallbackType = baseType.fallbackType;
 
84
                        }
 
85
 
 
86
                        foreach (Type interf in ValueType.GetInterfaces ()) {
 
87
                                ClassDataType baseType = (ClassDataType) Context.GetConfigurationDataType (interf);
 
88
                                baseType.AddSubtype (this);
 
89
                        }
 
90
                        
 
91
                        MemberInfo[] members = ValueType.GetMembers (BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
 
92
                        foreach (MemberInfo member in members) {
 
93
                                if ((member is FieldInfo || member is PropertyInfo) && member.DeclaringType == ValueType) {
 
94
                                        Type memberType = member is FieldInfo ? ((FieldInfo)member).FieldType : ((PropertyInfo)member).PropertyType;
 
95
                                        AddProperty (member, member.Name, memberType);
 
96
                                }
 
97
                        }
 
98
                        
 
99
                        foreach (ItemMember member in Context.AttributeProvider.GetItemMembers (ValueType)) {
 
100
                                AddProperty (member, member.Name, member.Type);
 
101
                        }
 
102
                        
 
103
                        if (fallbackType != null)
 
104
                                Context.IncludeType (fallbackType);
 
105
                }
 
106
                
 
107
                void AddProperty (object member, string name, Type memberType)
 
108
                {
 
109
                        object[] ats = Context.AttributeProvider.GetCustomAttributes (member, typeof(Attribute), true);
 
110
                        
 
111
                        ItemPropertyAttribute at = FindPropertyAttribute (ats, "");
 
112
                        if (at == null)
 
113
                                return;
 
114
                        
 
115
                        ItemProperty prop = new ItemProperty ();
 
116
                        prop.Name = (at.Name != null) ? at.Name : name;
 
117
                        prop.ExpandedCollection = Context.AttributeProvider.IsDefined (member, typeof(ExpandedCollectionAttribute), true);
 
118
                        prop.DefaultValue = at.DefaultValue;
 
119
                        prop.IsExternal = at.IsExternal;
 
120
                        prop.SkipEmpty = at.SkipEmpty;
 
121
 
 
122
                        if (prop.ExpandedCollection) {
 
123
                                ICollectionHandler handler = Context.GetCollectionHandler (memberType);
 
124
                                if (handler == null)
 
125
                                        throw new InvalidOperationException ("ExpandedCollectionAttribute can't be applied to property '" + prop.Name + "' in type '" + ValueType + "' becuase it is not a valid collection.");
 
126
                                        
 
127
                                memberType = handler.GetItemType ();
 
128
                                prop.ExpandedCollectionHandler = handler;
 
129
                        }
 
130
 
 
131
                        if (at.ValueType != null)
 
132
                                prop.PropertyType = at.ValueType;
 
133
                        else
 
134
                                prop.PropertyType = memberType;
 
135
                                
 
136
                        if (at.SerializationDataType != null) {
 
137
                                try {
 
138
                                        prop.DataType = (DataType) Activator.CreateInstance (at.SerializationDataType, new object[] { prop.PropertyType } );
 
139
                                } catch (MissingMethodException ex) {
 
140
                                        throw new InvalidOperationException ("Constructor not found for custom data type: " + at.SerializationDataType.Name + " (Type propertyType);", ex);
 
141
                                }
 
142
                        }
 
143
                        
 
144
                        if (member is MemberInfo) {
 
145
                                prop.Member = (MemberInfo) member;
 
146
                                AddProperty (prop);
 
147
                        } else {
 
148
                                prop.InitValue = ((ItemMember)member).InitValue;
 
149
                                AddProperty (prop, ((ItemMember)member).InsertBefore);
 
150
                        }
 
151
                        
 
152
                        prop.Initialize (ats, "");
 
153
                        
 
154
                        if (prop.ExpandedCollection && prop.DataType.IsSimpleType)
 
155
                                throw new InvalidOperationException ("ExpandedCollectionAttribute is not allowed in collections of simple types");
 
156
                }
 
157
                
 
158
                internal protected override object GetMapData (object[] attributes, string scope)
 
159
                {
 
160
                        // We only need the fallback type for now
 
161
 
 
162
                        ItemPropertyAttribute at = FindPropertyAttribute (attributes, scope);
 
163
                        if (at != null)
 
164
                                return at.FallbackType;
 
165
                        else
 
166
                                return null;
 
167
                }
 
168
                
 
169
                private void AddSubtype (ClassDataType subtype)
 
170
                {
 
171
                        if (subtypes == null)
 
172
                                subtypes = new ArrayList ();
 
173
                        subtypes.Add (subtype); 
 
174
                }
 
175
 
 
176
                ICollection Properties {
 
177
                        get { return sortedPoperties; }
 
178
                }
 
179
                
 
180
                public void AddProperty (ItemProperty prop)
 
181
                {
 
182
                        AddProperty (prop, null);
 
183
                }
 
184
                
 
185
                void AddProperty (ItemProperty prop, string insertBefore)
 
186
                {
 
187
                        if (!prop.IsNested) {
 
188
                                foreach (ItemProperty p in sortedPoperties) {
 
189
                                        if (p.IsNested && p.NameList[0] == prop.Name)
 
190
                                                throw CreateNestedConflictException (prop, p);
 
191
                                }
 
192
                        } else {
 
193
                                ItemProperty p = properties [prop.NameList[0]] as ItemProperty;
 
194
                                if (p != null)
 
195
                                        throw CreateNestedConflictException (prop, p);
 
196
                        }
 
197
                        
 
198
                        prop.SetContext (Context);
 
199
                        if (properties.ContainsKey (prop.Name))
 
200
                                throw new InvalidOperationException ("Duplicate property '" + prop.Name + "' in class '" + ValueType);
 
201
                        
 
202
                        properties.Add (prop.Name, prop);
 
203
                        
 
204
                        if (insertBefore != null) {
 
205
                                bool added = false;
 
206
                                for (int n=0; n<sortedPoperties.Count; n++) {
 
207
                                        ItemProperty p = sortedPoperties [n];
 
208
                                        if (p.MemberName == insertBefore) {
 
209
                                                sortedPoperties.Insert (n, prop);
 
210
                                                added = true;
 
211
                                                break;
 
212
                                        }
 
213
                                }
 
214
                                if (!added)
 
215
                                        sortedPoperties.Add (prop);
 
216
                        }
 
217
                        else if (prop.Unsorted) {
 
218
                                int foundPos = sortedPoperties.Count;
 
219
                                for (int n=0; n < sortedPoperties.Count; n++) {
 
220
                                        ItemProperty cp = (ItemProperty) sortedPoperties [n];
 
221
                                        if (cp.Unsorted && prop.Name.CompareTo (cp.Name) < 0) {
 
222
                                                foundPos = n;
 
223
                                                break;
 
224
                                        }
 
225
                                }
 
226
                                sortedPoperties.Insert (foundPos, prop);
 
227
                        } else
 
228
                                sortedPoperties.Add (prop);
 
229
                        
 
230
                        if (subtypes != null && subtypes.Count > 0) {
 
231
                                foreach (ClassDataType subtype in subtypes)
 
232
                                        subtype.AddProperty (prop);
 
233
                        }
 
234
                }
 
235
                
 
236
                public void RemoveProperty (string name)
 
237
                {
 
238
                        ItemProperty prop = (ItemProperty) properties [name];
 
239
                        if (prop == null)
 
240
                                return;
 
241
                        properties.Remove (name);
 
242
                        sortedPoperties.Remove (prop);
 
243
                        
 
244
                        if (subtypes != null && subtypes.Count > 0) {
 
245
                                foreach (ClassDataType subtype in subtypes)
 
246
                                        subtype.RemoveProperty (name);
 
247
                        }
 
248
                }
 
249
                
 
250
                public IEnumerable<ItemProperty> GetProperties (SerializationContext serCtx, object instance)
 
251
                {
 
252
                        foreach (ItemProperty prop in sortedPoperties) {
 
253
                                if (serCtx.Serializer.CanHandleProperty (prop, serCtx, instance))
 
254
                                        yield return prop;
 
255
                        }
 
256
                }
 
257
                
 
258
                Exception CreateNestedConflictException (ItemProperty p1, ItemProperty p2)
 
259
                {
 
260
                        return new InvalidOperationException ("There is a conflict between the properties '" + p1.Name + "' and '" + p2.Name + "'. Nested element properties can't be mixed with normal element properties.");
 
261
                }
 
262
                
 
263
                internal protected override DataNode OnSerialize (SerializationContext serCtx, object mapData, object obj)
 
264
                {
 
265
                        string ctype = null;
 
266
                        
 
267
                        if (obj.GetType () != ValueType) {
 
268
                                if (obj is IExtendedDataItem) {
 
269
                                        // This is set by fallback types, to make sure the original type name is serialized back
 
270
                                        ctype = (string) ((IExtendedDataItem)obj).ExtendedProperties ["__raw_ctype"];
 
271
                                }
 
272
                                if (ctype == null) {
 
273
                                        DataType subtype = Context.GetConfigurationDataType (obj.GetType ());
 
274
                                        DataItem it = (DataItem) subtype.Serialize (serCtx, mapData, obj);
 
275
                                        it.ItemData.Add (new DataValue ("ctype", subtype.Name));
 
276
                                        it.Name = Name;
 
277
                                        return it;
 
278
                                }
 
279
                        } 
 
280
                        
 
281
                        DataItem item = new DataItem ();
 
282
                        item.Name = Name;
 
283
                        
 
284
                        ICustomDataItem citem = Context.AttributeProvider.GetCustomDataItem (obj);
 
285
                        if (citem != null) {
 
286
                                ClassTypeHandler handler = new ClassTypeHandler (serCtx, this);
 
287
                                item.ItemData = citem.Serialize (handler);
 
288
                        }
 
289
                        else
 
290
                                item.ItemData = Serialize (serCtx, obj);
 
291
                                
 
292
                        if (ctype != null)
 
293
                                item.ItemData.Add (new DataValue ("ctype", ctype));
 
294
 
 
295
                        return item;
 
296
                }
 
297
                
 
298
                internal DataCollection Serialize (SerializationContext serCtx, object obj)
 
299
                {
 
300
                        DataCollection itemCol = new DataCollection ();
 
301
                        
 
302
                        foreach (ItemProperty prop in Properties) {
 
303
                                if (prop.ReadOnly || !prop.CanSerialize (serCtx, obj))
 
304
                                        continue;
 
305
                                object val = prop.GetValue (obj);
 
306
                                if (val == null)
 
307
                                        continue;
 
308
                                if (val.Equals (prop.DefaultValue))
 
309
                                        continue;
 
310
                                
 
311
                                DataCollection col = itemCol;
 
312
                                if (prop.IsNested)
 
313
                                        col = GetNestedCollection (col, prop.NameList, 0);
 
314
                                
 
315
                                if (prop.ExpandedCollection) {
 
316
                                        ICollectionHandler handler = prop.ExpandedCollectionHandler;
 
317
                                        object pos = handler.GetInitialPosition (val);
 
318
                                        while (handler.MoveNextItem (val, ref pos)) {
 
319
                                                object item = handler.GetCurrentItem (val, pos);
 
320
                                                if (item == null) continue;
 
321
                                                DataNode data = prop.Serialize (serCtx, obj, item);
 
322
                                                data.Name = prop.SingleName;
 
323
                                                col.Add (data);
 
324
                                        }
 
325
                                }
 
326
                                else {
 
327
                                        DataNode data = prop.Serialize (serCtx, obj, val);
 
328
                                        if (data == null)
 
329
                                                continue;
 
330
                                        col.Add (data);
 
331
                                }
 
332
                        }
 
333
                        
 
334
                        if (obj is IExtendedDataItem) {
 
335
                                // Serialize raw data which could not be deserialized
 
336
                                DataItem uknData = (DataItem) ((IExtendedDataItem)obj).ExtendedProperties ["__raw_data"];
 
337
                                if (uknData != null)
 
338
                                        itemCol.Merge (uknData.ItemData);
 
339
                        }
 
340
                        
 
341
                        return itemCol;
 
342
                }
 
343
                
 
344
                DataCollection GetNestedCollection (DataCollection col, string[] nameList, int pos)
 
345
                {
 
346
                        if (pos == nameList.Length - 1) return col;
 
347
 
 
348
                        DataItem item = col [nameList[pos]] as DataItem;
 
349
                        if (item == null) {
 
350
                                item = new DataItem ();
 
351
                                item.Name = nameList[pos];
 
352
                                col.Add (item);
 
353
                        }
 
354
                        return GetNestedCollection (item.ItemData, nameList, pos + 1);
 
355
                }
 
356
                
 
357
                internal protected override object OnDeserialize (SerializationContext serCtx, object mapData, DataNode data)
 
358
                {
 
359
                        DataItem item = data as DataItem;
 
360
                        if (item == null)
 
361
                                throw new InvalidOperationException ("Invalid value found for type '" + Name + "' " + data);
 
362
                                
 
363
                        DataValue ctype = item ["ctype"] as DataValue;
 
364
                        if (ctype != null && ctype.Value != Name) {
 
365
                                bool isFallbackType;
 
366
                                DataType stype = FindDerivedType (ctype.Value, mapData, out isFallbackType);
 
367
                                
 
368
                                if (isFallbackType) {
 
369
                                        // Remove the ctype attribute, to make sure it is not checked again
 
370
                                        // by the fallback type
 
371
                                        item.ItemData.Remove (ctype);
 
372
                                }
 
373
                                
 
374
                                if (stype != null) {
 
375
                                        object sobj = stype.Deserialize (serCtx, mapData, data);
 
376
                                        
 
377
                                        // Store the original data type, so it can be serialized back
 
378
                                        if (isFallbackType && sobj is IExtendedDataItem) {
 
379
                                                ((IExtendedDataItem)sobj).ExtendedProperties ["__raw_ctype"] = ctype.Value;
 
380
                                        }
 
381
                                                
 
382
                                        return sobj;
 
383
                                }
 
384
                                else
 
385
                                        throw new InvalidOperationException ("Type not found: " + ctype.Value);
 
386
                        }
 
387
                        
 
388
                        ConstructorInfo ctor = ValueType.GetConstructor (BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, Type.EmptyTypes, null);
 
389
                        if (ctor == null) throw new InvalidOperationException ("Default constructor not found for type '" + ValueType + "'");
 
390
 
 
391
                        object obj = ctor.Invoke (null);
 
392
                        Deserialize (serCtx, null, item, obj);
 
393
                        return obj;
 
394
                }
 
395
                
 
396
                internal protected override object OnCreateInstance (SerializationContext serCtx, DataNode data)
 
397
                {
 
398
                        DataItem item = data as DataItem;
 
399
                        if (item == null)
 
400
                                throw new InvalidOperationException ("Invalid value found for type '" + Name + "'");
 
401
                                
 
402
                        DataValue ctype = item ["ctype"] as DataValue;
 
403
                        if (ctype != null && ctype.Value != Name) {
 
404
                                bool isFallbackType;
 
405
                                DataType stype = FindDerivedType (ctype.Value, null, out isFallbackType);
 
406
                                if (isFallbackType) {
 
407
                                        // Remove the ctype attribute, to make sure it is not checked again
 
408
                                        // by the fallback type
 
409
                                        item.ItemData.Remove (ctype);
 
410
                                }
 
411
                                if (stype != null) {
 
412
                                        object sobj = stype.CreateInstance (serCtx, data);
 
413
                                        // Store the original data type, so it can be serialized back
 
414
                                        if (isFallbackType && sobj is IExtendedDataItem)
 
415
                                                ((IExtendedDataItem)sobj).ExtendedProperties ["__raw_ctype"] = ctype;
 
416
                                        return sobj;
 
417
                                }
 
418
                                else throw new InvalidOperationException ("Type not found: " + ctype.Value);
 
419
                        }
 
420
                        
 
421
                        ConstructorInfo ctor = ValueType.GetConstructor (BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, Type.EmptyTypes, null);
 
422
                        if (ctor == null) throw new InvalidOperationException ("Default constructor not found for type '" + ValueType + "'");
 
423
 
 
424
                        return ctor.Invoke (null);
 
425
                }
 
426
                
 
427
                protected internal override void OnDeserialize (SerializationContext serCtx, object mapData, DataNode data, object obj)
 
428
                {
 
429
                        DataItem item = (DataItem) data;
 
430
                        ICustomDataItem citem = Context.AttributeProvider.GetCustomDataItem (obj);
 
431
                        if (citem != null) {
 
432
                                ClassTypeHandler handler = new ClassTypeHandler (serCtx, this);
 
433
                                citem.Deserialize (handler, item.ItemData);
 
434
                        }
 
435
                        else
 
436
                                DeserializeNoCustom (serCtx, obj, item.ItemData);
 
437
                }
 
438
                
 
439
                internal void DeserializeNoCustom (SerializationContext serCtx, object obj, DataCollection itemData)
 
440
                {
 
441
                        foreach (ItemProperty prop in Properties)
 
442
                                if (!prop.CanDeserialize (serCtx, obj) && prop.DefaultValue != null)
 
443
                                        prop.SetValue (obj, prop.DefaultValue);
 
444
                        
 
445
                        // ukwnDataRoot is where to store values for which a property cannot be found.
 
446
                        DataItem ukwnDataRoot = (obj is IExtendedDataItem) ? new DataItem () : null;
 
447
                        
 
448
                        Deserialize (serCtx, obj, itemData, ukwnDataRoot, "");
 
449
                        
 
450
                        // store unreadable raw data to a special property so it can be 
 
451
                        // serialized back an the original format is kept
 
452
                        if (ukwnDataRoot != null && ukwnDataRoot.HasItemData)
 
453
                                ((IExtendedDataItem)obj).ExtendedProperties ["__raw_data"] = ukwnDataRoot;
 
454
                }
 
455
                
 
456
                void Deserialize (SerializationContext serCtx, object obj, DataCollection itemData, DataItem ukwnDataRoot, string baseName)
 
457
                {
 
458
                        Hashtable expandedCollections = null;
 
459
                        
 
460
                        foreach (DataNode value in itemData) {
 
461
                                ItemProperty prop = (ItemProperty) properties [baseName + value.Name];
 
462
                                if (prop == null) {
 
463
                                        if (value is DataItem) {
 
464
                                                DataItem root = new DataItem ();
 
465
                                                root.Name = value.Name;
 
466
                                                root.UniqueNames = ((DataItem)value).UniqueNames;
 
467
                                                if (ukwnDataRoot != null)
 
468
                                                        ukwnDataRoot.ItemData.Add (root);
 
469
                                                Deserialize (serCtx, obj, ((DataItem)value).ItemData, root, baseName + value.Name + "/");
 
470
 
 
471
                                                // If no unknown data has been added, there is no need to keep this
 
472
                                                // in the unknown items list.
 
473
                                                if (ukwnDataRoot != null && !root.HasItemData)
 
474
                                                        ukwnDataRoot.ItemData.Remove (root);
 
475
                                        }
 
476
                                        else if (obj is IExtendedDataItem && (value.Name != "ctype" || baseName.Length > 0)) {
 
477
                                                // store unreadable raw data to a special property so it can be 
 
478
                                                // serialized back an the original format is kept
 
479
                                                // The ctype attribute don't need to be stored for the root object, since
 
480
                                                // it is generated by the serializer
 
481
                                                ukwnDataRoot.ItemData.Add (value);
 
482
                                        }
 
483
                                        continue;
 
484
                                }
 
485
                                if (prop.WriteOnly || !prop.CanDeserialize (serCtx, obj))
 
486
                                        continue;
 
487
                                
 
488
                                try {
 
489
                                        if (prop.ExpandedCollection) {
 
490
                                                ICollectionHandler handler = prop.ExpandedCollectionHandler;
 
491
                                                if (expandedCollections == null) expandedCollections = new Hashtable ();
 
492
                                                
 
493
                                                object pos, col;
 
494
                                                if (!expandedCollections.ContainsKey (prop)) {
 
495
                                                        col = handler.CreateCollection (out pos, -1);
 
496
                                                } else {
 
497
                                                        pos = expandedCollections [prop];
 
498
                                                        col = prop.GetValue (obj);
 
499
                                                }
 
500
                                                handler.AddItem (ref col, ref pos, prop.Deserialize (serCtx, obj, value));
 
501
                                                expandedCollections [prop] = pos;
 
502
                                                prop.SetValue (obj, col);
 
503
                                        }
 
504
                                        else {
 
505
                                                if (prop.HasSetter && prop.DataType.CanCreateInstance)
 
506
                                                        prop.SetValue (obj, prop.Deserialize (serCtx, obj, value));
 
507
                                                else if (prop.DataType.CanReuseInstance) {
 
508
                                                        object pval = prop.GetValue (obj);
 
509
                                                        if (pval == null) {
 
510
                                                                if (prop.HasSetter)
 
511
                                                                        throw new InvalidOperationException ("The property '" + prop.Name + "' is null and a new instance of '" + prop.PropertyType + "' can't be created.");
 
512
                                                                else
 
513
                                                                        throw new InvalidOperationException ("The property '" + prop.Name + "' is null and it does not have a setter.");
 
514
                                                        }
 
515
                                                        prop.Deserialize (serCtx, obj, value, pval);
 
516
                                                } else {
 
517
                                                        throw new InvalidOperationException ("The property does not have a setter.");
 
518
                                                }
 
519
                                        }
 
520
                                }
 
521
                                catch (Exception ex) {
 
522
                                        throw new InvalidOperationException ("Could not set property '" + prop.Name + "' in type '" + Name + "'", ex);
 
523
                                }
 
524
                        }
 
525
                }
 
526
                
 
527
                DataType FindDerivedType (string name, object mapData, out bool isFallbackType)
 
528
                {
 
529
                        isFallbackType = false;
 
530
                        if (subtypes != null) {
 
531
                                foreach (ClassDataType stype in subtypes) {
 
532
                                        if (stype.Name == name) 
 
533
                                                return stype;
 
534
                                                
 
535
                                        bool fb;
 
536
                                        DataType cst = stype.FindDerivedType (name, null, out fb);
 
537
                                        if (cst != null && !fb) {
 
538
                                                isFallbackType = false;
 
539
                                                return cst;
 
540
                                        }
 
541
                                }
 
542
                        }
 
543
                        if (mapData != null) {
 
544
                                isFallbackType = true;
 
545
                                return Context.GetConfigurationDataType ((Type)mapData);
 
546
                        }
 
547
                        
 
548
                        if (fallbackType != null) {
 
549
                                isFallbackType = true;
 
550
                                return Context.GetConfigurationDataType (fallbackType);
 
551
                        }
 
552
                        else
 
553
                                return null;
 
554
                }
 
555
        }
 
556
        
 
557
        internal class ClassTypeHandler: ITypeSerializer
 
558
        {
 
559
                SerializationContext ctx;
 
560
                ClassDataType cdt;
 
561
                
 
562
                internal ClassTypeHandler (SerializationContext ctx, ClassDataType cdt)
 
563
                {
 
564
                        this.ctx = ctx;
 
565
                        this.cdt = cdt;
 
566
                }
 
567
                
 
568
                public DataCollection Serialize (object instance)
 
569
                {
 
570
                        return cdt.Serialize (ctx, instance);
 
571
                }
 
572
                
 
573
                public void Deserialize (object instance, DataCollection data)
 
574
                {
 
575
                        cdt.DeserializeNoCustom (ctx, instance, data);
 
576
                }
 
577
                
 
578
                public SerializationContext SerializationContext {
 
579
                        get { return ctx; }
 
580
                }
 
581
        }
 
582
}