Merge pull request #301 from directhex/master
[mono.git] / mcs / class / System.Design / System.ComponentModel.Design.Serialization / CodeDomSerializerBase.cs
1 //
2 // System.ComponentModel.Design.Serialization.CodeDomSerializerBase
3 //
4 // Authors:      
5 //        Ivan N. Zlatev (contact i-nZ.net)
6 //
7 // (C) 2007 Ivan N. Zlatev
8
9 //
10 // Permission is hereby granted, free of charge, to any person obtaining
11 // a copy of this software and associated documentation files (the
12 // "Software"), to deal in the Software without restriction, including
13 // without limitation the rights to use, copy, modify, merge, publish,
14 // distribute, sublicense, and/or sell copies of the Software, and to
15 // permit persons to whom the Software is furnished to do so, subject to
16 // the following conditions:
17 // 
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
20 // 
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 //
29
30 #if NET_2_0
31
32 using System;
33 using System.Collections;
34 using System.Reflection;
35 using System.ComponentModel;
36 using System.ComponentModel.Design;
37
38 using System.CodeDom;
39
40 namespace System.ComponentModel.Design.Serialization
41 {
42         [EditorBrowsable (EditorBrowsableState.Never)]
43         public abstract class CodeDomSerializerBase
44         {
45
46                 // MSDN says that if the deserialization fails a CodeExpression is returned
47                 //
48                 private sealed class DeserializationErrorMarker : CodeExpression
49                 {
50                         public override bool Equals (object o)
51                         {
52                                 return false;
53                         }
54
55                         public override int GetHashCode ()
56                         {
57                                 return base.GetHashCode ();
58                         }
59                 }
60
61                 private static readonly DeserializationErrorMarker _errorMarker = new DeserializationErrorMarker ();
62
63                 internal CodeDomSerializerBase ()
64                 {
65                 }
66
67                 private class ExpressionTable : Hashtable // just so that we have a specific type to append to the context stack
68                 {
69                 }
70
71                 protected CodeExpression SerializeToExpression (IDesignerSerializationManager manager, object instance)
72                 {
73                         if (manager == null)
74                                 throw new ArgumentNullException ("manager");
75
76                         CodeExpression expression = null;
77                         if (instance != null)
78                                 expression = this.GetExpression (manager, instance); // 1 - IDesignerSerializationManager.GetExpression
79                         if (expression == null) {
80                                 CodeDomSerializer serializer = this.GetSerializer (manager, instance); // 2 - manager.GetSerializer().Serialize()
81                                 if (serializer != null) {
82                                         object serialized = serializer.Serialize (manager, instance);
83                                         expression = serialized as CodeExpression; // 3 - CodeStatement or CodeStatementCollection
84                                         if (expression == null) {
85                                                 CodeStatement statement = serialized as CodeStatement;
86                                                 CodeStatementCollection statements = serialized as CodeStatementCollection;
87
88                                                 if (statement != null || statements != null) {
89                                                         CodeStatementCollection contextStatements = null;
90
91                                                         StatementContext context = manager.Context[typeof (StatementContext)] as StatementContext;
92                                                         if (context != null && instance != null)
93                                                                 contextStatements = context.StatementCollection[instance];
94
95                                                         if (contextStatements == null)
96                                                                 contextStatements = manager.Context[typeof (CodeStatementCollection)] as CodeStatementCollection;
97
98                                                         if (contextStatements != null) {
99                                                                 if (statements != null)
100                                                                         contextStatements.AddRange (statements);
101                                                                 else
102                                                                         contextStatements.Add (statement);
103                                                         }
104                                                 }
105                                         }
106                                         if (expression == null && instance != null)
107                                                 expression = this.GetExpression (manager, instance); // 4
108                                 } else {
109                                         ReportError (manager, "No serializer found for type '" + instance.GetType ().Name + "'");
110                                 }
111                         }
112                         return expression;
113                 }
114
115                 protected CodeDomSerializer GetSerializer (IDesignerSerializationManager manager, object instance)
116                 {
117                         DesignerSerializerAttribute attrInstance, attrType;
118                         attrType = attrInstance = null;
119
120                         CodeDomSerializer serializer = null;
121                         if (instance == null)
122                                 serializer = this.GetSerializer (manager, null);
123                         else {          
124                                 AttributeCollection attributes = TypeDescriptor.GetAttributes (instance);
125                                 foreach (Attribute a in attributes) {
126                                         DesignerSerializerAttribute designerAttr = a as DesignerSerializerAttribute;
127                                         if (designerAttr != null && manager.GetType (designerAttr.SerializerBaseTypeName) == typeof (CodeDomSerializer)) {
128                                                 attrInstance = designerAttr;
129                                                 break;
130                                         }
131                                 }
132         
133                                 attributes = TypeDescriptor.GetAttributes (instance.GetType ());
134                                 foreach (Attribute a in attributes) {
135                                         DesignerSerializerAttribute designerAttr = a as DesignerSerializerAttribute;
136                                         if (designerAttr != null && manager.GetType (designerAttr.SerializerBaseTypeName) == typeof (CodeDomSerializer)) {
137                                                 attrType = designerAttr;
138                                                 break;
139                                         }
140                                 }
141         
142                                 // if there is metadata modification in the instance then create the specified serializer instead of the one
143                                 // in the Type.
144                                 if (attrType != null && attrInstance != null && attrType.SerializerTypeName != attrInstance.SerializerTypeName)
145                                         serializer = Activator.CreateInstance (manager.GetType (attrInstance.SerializerTypeName)) as CodeDomSerializer;
146                                 else
147                                         serializer = this.GetSerializer (manager, instance.GetType ());
148                         }
149
150                         return serializer;
151                 }
152
153                 protected CodeDomSerializer GetSerializer (IDesignerSerializationManager manager, Type instanceType)
154                 {
155                         return manager.GetSerializer (instanceType, typeof (CodeDomSerializer)) as CodeDomSerializer;
156                 }
157
158                 protected CodeExpression GetExpression (IDesignerSerializationManager manager, object instance)
159                 {
160                         if (manager == null)
161                                 throw new ArgumentNullException ("manager");
162                         if (instance == null)
163                                 throw new ArgumentNullException ("instance");
164
165                         CodeExpression expression = null;
166
167                         ExpressionTable expressions = manager.Context[typeof (ExpressionTable)] as ExpressionTable;
168                         if (expressions != null) // 1st try: ExpressionTable
169                                 expression = expressions [instance] as CodeExpression;
170
171                         if (expression == null) { // 2nd try: RootContext
172                                 RootContext context = manager.Context[typeof (RootContext)] as RootContext;
173                                 if (context != null && context.Value == instance)
174                                         expression = context.Expression;
175                         }
176
177                         if (expression == null) { // 3rd try: IReferenceService (instance.property.property.property
178                                 string name = manager.GetName (instance);
179                                 if (name == null || name.IndexOf (".") == -1) {
180                                         IReferenceService service = manager.GetService (typeof (IReferenceService)) as IReferenceService;
181                                         if (service != null) {
182                                                 name = service.GetName (instance);
183                                                 if (name != null && name.IndexOf (".") != -1) {
184                                                         string[] parts = name.Split (new char[] { ',' });
185                                                         instance = manager.GetInstance (parts[0]);
186                                                         if (instance != null) {
187                                                                 expression = SerializeToExpression (manager, instance);
188                                                                 if (expression != null) {
189                                                                         for (int i=1; i < parts.Length; i++)
190                                                                                 expression = new CodePropertyReferenceExpression (expression, parts[i]);
191                                                                 }
192                                                         }
193                                                 }
194                                         }
195                                 }
196                         }
197                         return expression;
198                 }
199
200                 protected void SetExpression (IDesignerSerializationManager manager, object instance, CodeExpression expression)
201                 {
202                         SetExpression (manager, instance, expression, false);
203                 }
204
205                 // XXX: isPreset - what does this do when set?
206                 //
207                 protected void SetExpression (IDesignerSerializationManager manager, object instance, CodeExpression expression, bool isPreset)
208                 {
209                         if (manager == null)
210                                 throw new ArgumentNullException ("manager");
211                         if (instance == null)
212                                 throw new ArgumentNullException ("instance");
213                         if (expression == null)
214                                 throw new ArgumentNullException ("expression");
215
216                         ExpressionTable expressions = manager.Context[typeof (ExpressionTable)] as ExpressionTable;
217                         if (expressions == null) {
218                                 expressions = new ExpressionTable ();
219                                 manager.Context.Append (expressions);
220                         }
221
222                         expressions[instance] = expression;
223                 }
224
225                 protected bool IsSerialized (IDesignerSerializationManager manager, object value) 
226                 {
227                         return this.IsSerialized (manager, value, false);
228                 }
229
230                 // XXX: What should honorPreset do?
231                 protected bool IsSerialized (IDesignerSerializationManager manager, object instance, bool honorPreset) 
232                 {
233                         if (instance == null)
234                                 throw new ArgumentNullException ("instance");
235                         if (manager == null)
236                                 throw new ArgumentNullException ("manager");
237
238                         if (this.GetExpression (manager, instance) != null)
239                                 return true;
240                         else
241                                 return false;
242                 }
243
244                 protected CodeExpression SerializeCreationExpression (IDesignerSerializationManager manager, object value, out bool isComplete) 
245                 {
246                         if (value == null)
247                                 throw new ArgumentNullException ("value");
248                         if (manager == null)
249                                 throw new ArgumentNullException ("manager");
250
251                         CodeExpression expression = null;
252
253                         TypeConverter converter = TypeDescriptor.GetConverter (value);
254                         if (converter != null && converter.CanConvertTo (typeof (InstanceDescriptor))) {
255                                 InstanceDescriptor descriptor = converter.ConvertTo (value, typeof (InstanceDescriptor)) as InstanceDescriptor;
256                                 isComplete = descriptor.IsComplete;
257                                 if (descriptor != null && descriptor.MemberInfo != null)
258                                         expression = this.SerializeInstanceDescriptor (manager, descriptor);
259                                 else
260                                         ReportError (manager, "Unable to serialize to InstanceDescriptor", 
261                                                      "Value Type: " + value.GetType ().Name + System.Environment.NewLine + 
262                                                      "Value (ToString): " + value.ToString ());
263                         } else {
264                                 if (value.GetType().GetConstructor (Type.EmptyTypes) != null)
265                                         expression = new CodeObjectCreateExpression (value.GetType ().FullName, new CodeExpression[0]);
266                                 isComplete = false;
267                         }
268                         return expression;
269                 }
270
271                 private CodeExpression SerializeInstanceDescriptor (IDesignerSerializationManager manager, InstanceDescriptor descriptor)
272                 {
273                         CodeExpression expression = null;
274                         MemberInfo member = descriptor.MemberInfo;
275                         CodeExpression target = new CodeTypeReferenceExpression (member.DeclaringType);
276
277                         if (member is PropertyInfo) {
278                                 expression = new CodePropertyReferenceExpression (target, member.Name);
279                         } else if (member is FieldInfo) {
280                                 expression = new CodeFieldReferenceExpression (target, member.Name);
281                         } else if (member is MethodInfo) {
282                                 CodeMethodInvokeExpression methodInvoke = new CodeMethodInvokeExpression (target, member.Name);
283                                 if (descriptor.Arguments != null && descriptor.Arguments.Count > 0)
284                                         methodInvoke.Parameters.AddRange (SerializeParameters (manager, descriptor.Arguments));
285                                 expression = methodInvoke;
286                         } else if (member is ConstructorInfo) {
287                                 CodeObjectCreateExpression createExpr = new CodeObjectCreateExpression (member.DeclaringType);
288                                 if (descriptor.Arguments != null && descriptor.Arguments.Count > 0)
289                                         createExpr.Parameters.AddRange (SerializeParameters (manager, descriptor.Arguments));
290                                 expression = createExpr;
291                         }
292
293                         return expression;
294                 }
295
296                 private CodeExpression[] SerializeParameters (IDesignerSerializationManager manager, ICollection parameters)
297                 {
298                         CodeExpression[] expressions = null;
299
300                         if (parameters != null && parameters.Count > 0) {
301                                 expressions = new CodeExpression[parameters.Count];
302                                 int i = 0;
303                                 foreach (object parameter in parameters) {
304                                         expressions[i] = this.SerializeToExpression (manager, parameter);
305                                         i++;
306                                 }
307                         }
308
309                         return expressions;
310                 }
311
312                 protected void SerializeEvent (IDesignerSerializationManager manager, CodeStatementCollection statements, 
313                                                object value, EventDescriptor descriptor) 
314                 {
315                         if (descriptor == null)
316                                 throw new ArgumentNullException ("descriptor");
317                         if (value == null)
318                                 throw new ArgumentNullException ("value");
319                         if (statements == null)
320                                 throw new ArgumentNullException ("statements");
321                         if (manager == null)
322                                 throw new ArgumentNullException ("manager");
323
324                         MemberCodeDomSerializer serializer = manager.GetSerializer (descriptor.GetType (), typeof (MemberCodeDomSerializer)) as MemberCodeDomSerializer;
325                         if (serializer != null && serializer.ShouldSerialize (manager, value, descriptor))
326                                 serializer.Serialize (manager, value, descriptor, statements);
327                 }
328
329                 protected void SerializeEvents (IDesignerSerializationManager manager, CodeStatementCollection statements, 
330                                                 object value, params Attribute[] filter)
331                 {
332                         if (filter == null)
333                                 throw new ArgumentNullException ("filter");
334                         if (value == null)
335                                 throw new ArgumentNullException ("value");
336                         if (statements == null)
337                                 throw new ArgumentNullException ("statements");
338                         if (manager == null)
339                                 throw new ArgumentNullException ("manager");
340
341                         EventDescriptorCollection events = TypeDescriptor.GetEvents (value, filter);
342                         foreach (EventDescriptor e in events) 
343                                 this.SerializeEvent (manager, statements, value, e);
344                 }
345
346                 protected void SerializeProperty (IDesignerSerializationManager manager, CodeStatementCollection statements, 
347                                                   object value, PropertyDescriptor propertyToSerialize)
348                 {
349                         if (propertyToSerialize == null)
350                                 throw new ArgumentNullException ("propertyToSerialize");
351                         if (value == null)
352                                 throw new ArgumentNullException ("value");
353                         if (statements == null)
354                                 throw new ArgumentNullException ("statements");
355                         if (manager == null)
356                                 throw new ArgumentNullException ("manager");
357
358                         MemberCodeDomSerializer serializer = manager.GetSerializer (propertyToSerialize.GetType (), 
359                                                                                     typeof (MemberCodeDomSerializer)) as MemberCodeDomSerializer;
360                         if (serializer != null && serializer.ShouldSerialize (manager, value, propertyToSerialize))
361                                 serializer.Serialize (manager, value, propertyToSerialize, statements);
362                 }
363                 
364                 protected void SerializeProperties (IDesignerSerializationManager manager, CodeStatementCollection statements, 
365                                                                                         object value, Attribute[] filter) 
366                 {
367                         if (filter == null)
368                                 throw new ArgumentNullException ("filter");
369                         if (value == null)
370                                 throw new ArgumentNullException ("value");
371                         if (statements == null)
372                                 throw new ArgumentNullException ("statements");
373                         if (manager == null)
374                                 throw new ArgumentNullException ("manager");
375
376                         PropertyDescriptorCollection properties = TypeDescriptor.GetProperties (value, filter);
377                         foreach (PropertyDescriptor property in properties) {
378                                 if (!property.Attributes.Contains (DesignerSerializationVisibilityAttribute.Hidden))
379                                         this.SerializeProperty (manager, statements, value, property);
380                         }
381                 }
382
383                 protected virtual object DeserializeInstance (IDesignerSerializationManager manager, Type type, 
384                                                               object[] parameters, string name, bool addToContainer)
385                 {
386                         if (type == null)
387                                 throw new ArgumentNullException ("type");
388                         if (manager == null)
389                                 throw new ArgumentNullException ("manager");
390
391                         return manager.CreateInstance (type, parameters, name, addToContainer);
392                 }
393
394                 protected string GetUniqueName (IDesignerSerializationManager manager, object instance)
395                 {
396                         if (instance == null)
397                                 throw new ArgumentNullException ("instance");
398                         if (manager == null)
399                                 throw new ArgumentNullException ("manager");
400
401                         string name = manager.GetName (instance);
402                         if (name == null) {
403                                 INameCreationService service = manager.GetService (typeof (INameCreationService)) as INameCreationService;
404                                 name = service.CreateName (null, instance.GetType ());
405                                 if (name == null)
406                                         name = instance.GetType ().Name.ToLower ();
407                                 manager.SetName (instance, name);
408                         }
409                         return name;
410                 }
411
412                 protected object DeserializeExpression (IDesignerSerializationManager manager, string name, CodeExpression expression) 
413                 {
414                         if (expression == null)
415                                 throw new ArgumentNullException ("expression");
416                         if (manager == null)
417                                 throw new ArgumentNullException ("manager");
418
419                         bool errorOccurred = false;
420                         object deserialized = null;
421
422                         // CodeThisReferenceExpression
423                         //
424                         CodeThisReferenceExpression thisExpr = expression as CodeThisReferenceExpression;
425                         if (thisExpr != null) {
426                                 RootContext context = manager.Context[typeof (RootContext)] as RootContext;
427                                 if (context != null) {
428                                         deserialized = context.Value;
429                                 } else {
430                                         IDesignerHost host = manager.GetService (typeof (IDesignerHost)) as IDesignerHost;
431                                         if (host != null)
432                                                 deserialized = host.RootComponent;
433                                 }
434                         }
435                         
436                         // CodeVariableReferenceExpression
437                         //
438                         CodeVariableReferenceExpression varRef = expression as CodeVariableReferenceExpression;
439                         if (deserialized == null && varRef != null) {
440                                 deserialized = manager.GetInstance (varRef.VariableName);
441                                 if (deserialized == null) {
442                                         ReportError (manager, "Variable '" + varRef.VariableName + "' not initialized prior to reference");
443                                         errorOccurred = true;
444                                 }
445                         }
446
447                         // CodeFieldReferenceExpression (used for Enum references as well)
448                         //
449                         CodeFieldReferenceExpression fieldRef = expression as CodeFieldReferenceExpression;
450                         if (deserialized == null && fieldRef != null) {
451                                 deserialized = manager.GetInstance (fieldRef.FieldName);
452                                 if (deserialized == null) {
453                                         object fieldHolder = DeserializeExpression (manager, null, fieldRef.TargetObject);
454                                         FieldInfo field = null;
455                                         if (fieldHolder is Type) // static field
456                                                 field = ((Type)fieldHolder).GetField (fieldRef.FieldName, 
457                                                                                       BindingFlags.GetField | BindingFlags.Public | BindingFlags.Static);
458                                         else // instance field
459                                                 field = fieldHolder.GetType().GetField (fieldRef.FieldName, 
460                                                                                         BindingFlags.GetField | BindingFlags.Public | BindingFlags.Instance);
461                                         if (field != null)
462                                                 deserialized = field.GetValue (fieldHolder);
463                                 }
464                                 if (deserialized == null)
465                                         ReportError (manager, "Field '" + fieldRef.FieldName + "' not initialized prior to reference");
466                         }
467                                 
468
469                         // CodePrimitiveExpression
470                         //
471                         CodePrimitiveExpression primitiveExp = expression as CodePrimitiveExpression;
472                         if (deserialized == null && primitiveExp != null)
473                                 deserialized = primitiveExp.Value;
474
475                         // CodePropertyReferenceExpression
476                         //
477                         CodePropertyReferenceExpression propRef = expression as CodePropertyReferenceExpression;
478                         if (deserialized == null && propRef != null) {
479                                 object target = DeserializeExpression (manager, null, propRef.TargetObject);
480                                 if (target != null && target != _errorMarker) {
481                                         bool found = false;
482                                         if (target is Type) {
483                                                 PropertyInfo property = ((Type)target).GetProperty (propRef.PropertyName,
484                                                                                                     BindingFlags.GetProperty | 
485                                                                                                     BindingFlags.Public | BindingFlags.Static);
486                                                 if (property != null) {
487                                                         deserialized = property.GetValue (null, null);
488                                                         found = true;
489                                                 }
490
491                                                 // NRefactory seems to produce PropertyReferences to reference some fields and enums
492                                                 //
493                                                 FieldInfo field = ((Type)target).GetField (propRef.PropertyName,
494                                                                                            BindingFlags.GetField | BindingFlags.Public | BindingFlags.Static);
495                                                 if (field != null) {
496                                                         deserialized = field.GetValue (null);
497                                                         found = true;
498                                                 }
499                                         } else {
500                                                 PropertyDescriptor property = TypeDescriptor.GetProperties (target)[propRef.PropertyName];
501                                                 if (property != null) {
502                                                         deserialized = property.GetValue (target);
503                                                         found = true;
504                                                 }
505
506                                                 FieldInfo field = target.GetType().GetField (propRef.PropertyName,
507                                                                                              BindingFlags.GetField | BindingFlags.Public | BindingFlags.Instance);
508                                                 if (field != null) {
509                                                         deserialized = field.GetValue (null);
510                                                         found = true;
511                                                 }
512                                         }
513                                         
514                                         if (!found) {
515                                                 ReportError (manager, "Missing field '" + propRef.PropertyName + " 'in type " + 
516                                                              (target is Type ? ((Type)target).Name : target.GetType ().Name) + "'");
517                                                 errorOccurred = true;
518                                         }
519                                 }
520                         }
521
522                         // CodeObjectCreateExpression
523                         //
524                         CodeObjectCreateExpression createExpr = expression as CodeObjectCreateExpression;
525                         if (deserialized == null && createExpr != null) {
526                                 Type type = manager.GetType (createExpr.CreateType.BaseType);
527                                 if (type == null) {
528                                         ReportError (manager, "Type '" + createExpr.CreateType.BaseType + "' not found." + 
529                                                      "Are you missing a reference?");
530                                         errorOccurred = true;
531                                 } else {
532                                         object[] arguments = new object[createExpr.Parameters.Count];
533                                         for (int i=0; i < createExpr.Parameters.Count; i++) {
534                                                 arguments[i] = this.DeserializeExpression (manager, null, createExpr.Parameters[i]);
535                                                 if (arguments[i] == _errorMarker) {
536                                                         errorOccurred = true;
537                                                         break;
538                                                 }
539                                         }
540                                         if (!errorOccurred) {
541                                                 bool addToContainer = false;
542                                                 if (typeof(IComponent).IsAssignableFrom (type))
543                                                         addToContainer = true;
544                                                 deserialized = this.DeserializeInstance (manager, type, arguments, name, addToContainer);
545                                                 if (deserialized == _errorMarker || deserialized == null) {
546                                                         string info = "Type to create: " + createExpr.CreateType.BaseType + System.Environment.NewLine +
547                                                                 "Name: " + name + System.Environment.NewLine +
548                                                                 "addToContainer: " + addToContainer.ToString () + System.Environment.NewLine +
549                                                                 "Parameters Count: " + createExpr.Parameters.Count + System.Environment.NewLine;
550         
551                                                         for (int i=0; i < arguments.Length; i++) {
552                                                                 info += "Parameter Number: " + i.ToString () + System.Environment.NewLine +
553                                                                         "Parameter Type: " + (arguments[i] == null ? "null" : arguments[i].GetType ().Name) +
554                                                                         System.Environment.NewLine +
555                                                                         "Parameter '" + i.ToString () + "' Value: " + arguments[i].ToString () + System.Environment.NewLine;
556                                                         }
557                                                         ReportError (manager, 
558                                                                      "Unable to create an instance of type '" + createExpr.CreateType.BaseType + "'",
559                                                                      info);
560                                                         errorOccurred = true;
561                                                 }
562                                         }
563                                 }
564                         }
565
566                         // CodeArrayCreateExpression
567                         //
568                         CodeArrayCreateExpression arrayCreateExpr = expression as CodeArrayCreateExpression;
569                         if (deserialized == null && arrayCreateExpr != null) {
570                                 Type arrayType = manager.GetType (arrayCreateExpr.CreateType.BaseType);
571                                 if (arrayType == null) {
572                                         ReportError (manager, "Type '" + arrayCreateExpr.CreateType.BaseType + "' not found." + 
573                                                      "Are you missing a reference?");
574                                         errorOccurred = true;
575                                 } else {
576                                         ArrayList initializers = new ArrayList ();
577                                         Type elementType = arrayType.GetElementType ();
578                                         deserialized = Array.CreateInstance (arrayType, arrayCreateExpr.Initializers.Count);
579                                         for (int i = 0; i < arrayCreateExpr.Initializers.Count; i++) {
580                                                 object element = this.DeserializeExpression (manager, null, arrayCreateExpr.Initializers[i]);
581                                                 errorOccurred = (element == _errorMarker);
582                                                 if (!errorOccurred) {
583                                                         if (arrayType.IsInstanceOfType (element)) {
584                                                                 initializers.Add (element);
585                                                         } else {
586                                                                 ReportError (manager, 
587                                                                              "Array initializer element type incompatible with array type.",
588                                                                              "Array Type: " + arrayType.Name + System.Environment.NewLine +
589                                                                              "Array Element Type: " + elementType + System.Environment.NewLine +
590                                                                              "Initializer Type: " + (element == null ? "null" : element.GetType ().Name));
591                                                                 errorOccurred = true;
592                                                         }
593                                                 }
594                                         }
595                                         if (!errorOccurred)
596                                                 initializers.CopyTo ((Array)deserialized, 0);
597                                 }
598                         }
599
600                         // CodeMethodInvokeExpression
601                         //
602                         CodeMethodInvokeExpression methodExpr = expression as CodeMethodInvokeExpression;
603                         if (deserialized == null && methodExpr != null) {
604                                 object target = this.DeserializeExpression (manager, null, methodExpr.Method.TargetObject);
605                                 object[] parameters = null;
606                                 if (target == _errorMarker || target == null) {
607                                         errorOccurred = true;
608                                 } else {
609                                         parameters = new object[methodExpr.Parameters.Count];
610                                         for (int i=0; i < methodExpr.Parameters.Count; i++) {
611                                                 parameters[i] = this.DeserializeExpression (manager, null, methodExpr.Parameters[i]);
612                                                 if (parameters[i] == _errorMarker) {
613                                                         errorOccurred = true;
614                                                         break;
615                                                 }
616                                         }
617                                 }
618
619                                 if (!errorOccurred) {
620                                         MethodInfo method = null;
621                                         if (target is Type) {
622                                                 method = GetExactMethod ((Type)target, methodExpr.Method.MethodName, 
623                                                                                                  BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.Static,
624                                                                                                  parameters);
625                                         } else {
626                                                 method = GetExactMethod (target.GetType(), methodExpr.Method.MethodName, 
627                                                                                                  BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.Instance,
628                                                                                                  parameters);
629                                         }
630         
631                                         if (method != null) {
632                                                 deserialized = method.Invoke (target, parameters);
633                                         } else {
634                                                 string info = 
635                                                         "Method Name: " + methodExpr.Method.MethodName + System.Environment.NewLine +
636                                                         "Method is: " + (target is Type ? "static" : "instance") + System.Environment.NewLine +
637                                                         "Method Holder Type: " + (target is Type ? ((Type)target).Name : target.GetType ().Name) + System.Environment.NewLine +
638                                                         "Parameters Count: " + methodExpr.Parameters.Count + System.Environment.NewLine +
639                                                         System.Environment.NewLine;
640
641                                                 for (int i = 0; i < parameters.Length; i++) {
642                                                         info += "Parameter Number: " + i.ToString () + System.Environment.NewLine +
643                                                                 "Parameter Type: " + (parameters[i] == null ? "null" : parameters[i].GetType ().Name) +
644                                                                 System.Environment.NewLine +
645                                                                 "Parameter " + i.ToString () + " Value: " + parameters[i].ToString () + System.Environment.NewLine;
646                                                 }
647                                                 ReportError (manager, 
648                                                              "Method '" + methodExpr.Method.MethodName + "' missing in type '" + 
649                                                              (target is Type ? ((Type)target).Name : target.GetType ().Name + "'"),
650                                                              info);
651                                                 errorOccurred = true;
652                                         }
653                                 }
654                         }
655
656                         // CodeTypeReferenceExpression
657                         //
658                         CodeTypeReferenceExpression typeRef = expression as CodeTypeReferenceExpression;
659                         if (deserialized == null && typeRef != null) {
660                                 deserialized = manager.GetType (typeRef.Type.BaseType);
661                                 if (deserialized == null) {
662                                         ReportError (manager, "Type '" + typeRef.Type.BaseType + "' not found." + 
663                                                      "Are you missing a reference?");
664                                         errorOccurred = true;
665                                 }
666                         }
667
668                         // CodeCastExpression
669                         // 
670                         CodeCastExpression castExpr = expression as CodeCastExpression;
671                         if (deserialized == null && castExpr != null) {
672                                 Type targetType = manager.GetType (castExpr.TargetType.BaseType);
673                                 object instance = DeserializeExpression (manager, null, castExpr.Expression);
674                                 if (instance != null && instance != _errorMarker && targetType != null) {
675                                         IConvertible convertible = instance as IConvertible;
676                                         if (convertible != null) {
677                                                 try {
678                                                         instance = convertible.ToType (targetType, null);
679                                                 } catch {
680                                                         errorOccurred = true;
681                                                 }
682                                         } else {
683                                                 errorOccurred = true;
684                                         }
685                                         if (errorOccurred) {
686                                                 ReportError (manager, "Unable to convert type '" + instance.GetType ().Name + 
687                                                              "' to type '" + castExpr.TargetType.BaseType + "'",
688                                                              "Target Type: " + castExpr.TargetType.BaseType + System.Environment.NewLine +
689                                                              "Instance Type: " + (instance == null ? "null" : instance.GetType ().Name) + System.Environment.NewLine +
690                                                              "Instance Value: " + (instance == null ? "null" : instance.ToString()) + System.Environment.NewLine +
691                                                              "Instance is IConvertible: " + (instance is IConvertible).ToString());
692                                         }
693
694                                         deserialized = instance;
695                                 }
696                         }
697
698
699                         // CodeBinaryOperatorExpression
700                         //
701                         CodeBinaryOperatorExpression binOperator = expression as CodeBinaryOperatorExpression;
702                         if (deserialized == null && binOperator != null) {
703                                 string errorText = null;
704                                 IConvertible left = null;
705                                 IConvertible right = null;
706                                 switch (binOperator.Operator) {
707                                         case CodeBinaryOperatorType.BitwiseOr:
708                                                 left = DeserializeExpression (manager, null, binOperator.Left) as IConvertible;
709                                                 right = DeserializeExpression (manager, null, binOperator.Right) as IConvertible;
710                                                 if (left is Enum && right is Enum) {
711                                                         deserialized = Enum.ToObject (left.GetType (), Convert.ToInt64 (left) | Convert.ToInt64 (right));
712                                                 } else {
713                                                         errorText = "CodeBinaryOperatorType.BitwiseOr allowed only on Enum types";
714                                                         errorOccurred = true;
715                                                 }
716                                                 break;
717                                         default:
718                                                 errorText = "Unsupported CodeBinaryOperatorType: " + binOperator.Operator.ToString ();
719                                                 errorOccurred = true;
720                                                 break;
721                                 }
722
723                                 if (errorOccurred) {
724                                         string info = "BinaryOperator Type: " + binOperator.Operator.ToString() + System.Environment.NewLine +
725                                                 "Left Type: " + (left == null ? "null" : left.GetType().Name) + System.Environment.NewLine +
726                                                 "Left Value: " + (left == null ? "null" : left.ToString ()) + System.Environment.NewLine +
727                                                 "Left Expression Type: " + binOperator.Left.GetType ().Name + System.Environment.NewLine +
728                                                 "Right Type: " + (right == null ? "null" : right.GetType().Name) + System.Environment.NewLine +
729                                                 "Right Value: " + (right == null ? "null" : right.ToString ()) + System.Environment.NewLine +
730                                                 "Right Expression Type: " + binOperator.Right.GetType ().Name;
731                                         ReportError (manager, errorText, info);
732                                 }
733                         }
734
735
736                         if (!errorOccurred) {
737                                 if (deserialized == null && !(expression is CodePrimitiveExpression) && !(expression is CodeMethodInvokeExpression)) {
738                                         ReportError (manager, "Unsupported Expression Type: " + expression.GetType ().Name);
739                                         errorOccurred = true;
740                                 }
741                         }
742
743                         if (errorOccurred)
744                                 deserialized = _errorMarker;
745                         return deserialized;
746                 }
747
748                 // Searches for a method on type that matches argument types
749                 //
750                 private MethodInfo GetExactMethod (Type type, string methodName, BindingFlags flags, ICollection argsCollection)
751                 {
752                         object[] arguments = null;
753                         Type[] types = Type.EmptyTypes;
754
755                         if (argsCollection != null) {
756                                 arguments = new object[argsCollection.Count];
757                                 types = new Type[argsCollection.Count];
758                                 argsCollection.CopyTo (arguments, 0);
759
760                                 for (int i=0; i < arguments.Length; i++) {
761                                         if (arguments[i] == null)
762                                                 types[i] = null;
763                                         else
764                                                 types[i] = arguments[i].GetType ();
765                                 }
766                         }
767
768                         return type.GetMethod (methodName, flags, null, types, null);
769                 }
770
771                 protected void DeserializeStatement (IDesignerSerializationManager manager, CodeStatement statement)
772                 {
773                         if (statement == null)
774                                 throw new ArgumentNullException ("statement");
775                         if (manager == null)
776                                 throw new ArgumentNullException ("manager");
777
778                         // CodeAssignStatement
779                         //
780                         CodeAssignStatement assignment = statement as CodeAssignStatement;
781                         if (assignment != null)
782                                 DeserializeAssignmentStatement (manager, assignment);
783
784                         // CodeExpressionStatement
785                         //
786                         CodeExpressionStatement expression = statement as CodeExpressionStatement;
787                         if (expression != null)
788                                 this.DeserializeExpression (manager, null, expression.Expression);
789
790                         // CodeAttachEventStatement
791                         //
792                         CodeAttachEventStatement attachStatement = statement as CodeAttachEventStatement;
793                         if (attachStatement != null) {
794                                 string methodName = null;
795
796                                 CodeObjectCreateExpression createExpr = attachStatement.Listener as CodeObjectCreateExpression;
797                                 if (createExpr != null && createExpr.Parameters.Count == 1 ) { // += new EventType (method)
798                                         CodeMethodReferenceExpression handlerRef = createExpr.Parameters[0] as CodeMethodReferenceExpression;
799                                         if (handlerRef != null)
800                                                 methodName = handlerRef.MethodName;
801                                 }
802
803                                 CodeDelegateCreateExpression delegateCreateExpr = attachStatement.Listener as CodeDelegateCreateExpression;
804                                 if (delegateCreateExpr != null)// += new EventType (method)
805                                         methodName = delegateCreateExpr.MethodName;
806
807                                 CodeMethodReferenceExpression methodRef = attachStatement.Listener as CodeMethodReferenceExpression;
808                                 if (methodRef != null) // += method
809                                         methodName = methodRef.MethodName;
810
811                                 object component = DeserializeExpression (manager, null, attachStatement.Event.TargetObject);
812                                 if (component != null && component != _errorMarker && methodName != null) {
813                                         string error = null;
814                                         EventDescriptor eventDescriptor = TypeDescriptor.GetEvents (component)[attachStatement.Event.EventName];
815                                         if (eventDescriptor != null) {
816                                                 IEventBindingService service = manager.GetService (typeof (IEventBindingService)) as IEventBindingService;
817                                                 if (service != null)
818                                                         service.GetEventProperty (eventDescriptor).SetValue (component, methodName);
819                                                 else
820                                                         error = "IEventBindingService missing";
821                                         } else {
822                                                 error = "No event '" + attachStatement.Event.EventName + 
823                                                         "' found in type '" + component.GetType ().Name + "'";
824                                         }
825
826                                         if (error != null) {
827                                                 ReportError (manager, error, "Method Name: " + methodName + System.Environment.NewLine +
828                                                         "Event Name: " + attachStatement.Event.EventName + System.Environment.NewLine +
829                                                         "Listener Expression Type: " + methodRef.GetType ().Name + System.Environment.NewLine +
830                                                         "Event Holder Type: " + component.GetType ().Name + System.Environment.NewLine +
831                                                         "Event Holder Expression Type: " + attachStatement.Event.TargetObject.GetType ().Name);
832                                         }
833                                 }
834                         }
835                 }
836
837                 private void DeserializeAssignmentStatement (IDesignerSerializationManager manager, CodeAssignStatement statement)
838                 {
839                         CodeExpression leftExpr = statement.Left;
840                         
841                         // Assign to a Property
842                         //
843                         CodePropertyReferenceExpression propRef = leftExpr as CodePropertyReferenceExpression;
844                         if (propRef != null) {
845                                 object propertyHolder = DeserializeExpression (manager, null, propRef.TargetObject);
846                                 object value = null;
847                                 if (propertyHolder != null && propertyHolder != _errorMarker)
848                                         value = DeserializeExpression (manager, null, statement.Right);
849
850                                 if (value != null && value != _errorMarker && propertyHolder != null) {
851                                         PropertyDescriptor property = TypeDescriptor.GetProperties (propertyHolder)[propRef.PropertyName];
852                                         if (property != null) {
853                                                 property.SetValue (propertyHolder, value);
854                                         } else {
855                                                 ReportError (manager, 
856                                                              "Missing property '" + propRef.PropertyName + 
857                                                              "' in type '" + propertyHolder.GetType ().Name + "'");
858                                         }
859                                 }
860                         }
861                         
862                         // Assign to a Field
863                         // 
864                         CodeFieldReferenceExpression fieldRef = leftExpr as CodeFieldReferenceExpression;
865                         if (fieldRef != null && fieldRef.FieldName != null) {
866                                 // Note that if the Right expression is a CodeCreationExpression the component will be created in this call
867                                 //
868                                 object fieldHolder = DeserializeExpression (manager, null, fieldRef.TargetObject);
869                                 object value = null;
870                                 if (fieldHolder != null && fieldHolder != _errorMarker)
871                                         value = DeserializeExpression (manager, fieldRef.FieldName, statement.Right);
872                                 FieldInfo field = null;
873
874                                 RootContext context = manager.Context[typeof (RootContext)] as RootContext;
875                                 if (fieldHolder != null && fieldHolder != _errorMarker && value != _errorMarker) {
876                                         if (fieldRef.TargetObject is CodeThisReferenceExpression && context != null && context.Value == fieldHolder) {
877                                                 // Do not deserialize the fields of the root component, because the root component type 
878                                                 // is actually an instance of the its parent type, e.g: CustomControl : _UserControl_
879                                                 // and thus it doesn't contain the fields. The trick is that once DeserializeExpression 
880                                                 // is called on a CodeObjectCreateExpression the component is created and is added to the name-instance
881                                                 // table.
882                                                 // 
883                                         } else {
884                                                 if (fieldHolder is Type) // static field
885                                                         field = ((Type)fieldHolder).GetField (fieldRef.FieldName, 
886                                                                                               BindingFlags.GetField | BindingFlags.Public | BindingFlags.Static);
887                                                 else // instance field
888                                                         field = fieldHolder.GetType().GetField (fieldRef.FieldName, 
889                                                                                                 BindingFlags.GetField | BindingFlags.Public | BindingFlags.Instance);
890                                                 if (field != null)
891                                                         field.SetValue (fieldHolder, value);
892                                                 else {
893                                                         ReportError (manager, "Field '" + fieldRef.FieldName + "' missing in type '" +
894                                                                      fieldHolder.GetType ().Name + "'",
895                                                                      "Field Name: " + fieldRef.FieldName + System.Environment.NewLine +
896                                                                      "Field is: " + (fieldHolder is Type ? "static" : "instance") + System.Environment.NewLine +
897                                                                      "Field Value: " + (value == null ? "null" : value.ToString()) + System.Environment.NewLine +
898                                                                      "Field Holder Type: " + fieldHolder.GetType ().Name + System.Environment.NewLine +
899                                                                      "Field Holder Expression Type: " + fieldRef.TargetObject.GetType ().Name);
900                                                 }
901                                         }
902                                 }
903                         }
904
905                         // Assign to a Variable
906                         // 
907                         CodeVariableReferenceExpression varRef = leftExpr as CodeVariableReferenceExpression;
908                         if (varRef != null && varRef.VariableName != null) {
909                                 object value = DeserializeExpression (manager, varRef.VariableName, statement.Right);
910                                 // If .Right is not CodeObjectCreateExpression the instance won't be assigned a name, 
911                                 // so do it ourselves
912                                 if (value != _errorMarker && manager.GetName (value) == null)
913                                         manager.SetName (value, varRef.VariableName);
914                         }
915                 }
916
917                 internal void ReportError (IDesignerSerializationManager manager, string message)
918                 {
919                         this.ReportError (manager, message, String.Empty);
920                 }
921
922                 internal void ReportError (IDesignerSerializationManager manager, string message, string details)
923                 {
924                         try {
925                                 throw new Exception (message);
926                         } catch (Exception e) {
927                                 e.Data["Details"] = message + Environment.NewLine + Environment.NewLine + details;
928                                 manager.ReportError (e);
929                         }
930                 }
931
932 #region Resource Serialization - TODO
933                 protected CodeExpression SerializeToResourceExpression (IDesignerSerializationManager manager, object value) 
934                 {
935                         throw new NotImplementedException ();
936                 }
937                 
938                 protected CodeExpression SerializeToResourceExpression (IDesignerSerializationManager manager, object value, 
939                                                                         bool ensureInvariant) 
940                 {
941                         throw new NotImplementedException ();
942                 }
943                 
944                 protected void SerializePropertiesToResources (IDesignerSerializationManager manager, CodeStatementCollection statements, 
945                                                                object value, Attribute[] filter) 
946                 {
947                         throw new NotImplementedException ();
948                 }
949
950                 protected void SerializeResource (IDesignerSerializationManager manager, string resourceName, object value)
951                 {
952                         throw new NotImplementedException ();
953                 }
954
955                 protected void SerializeResourceInvariant (IDesignerSerializationManager manager, string resourceName, object value) 
956                 {
957                         throw new NotImplementedException ();
958                 }
959
960                 protected void DeserializePropertiesFromResources (IDesignerSerializationManager manager, object value, Attribute[] filter)
961                 {
962                         throw new NotImplementedException ();
963                 }
964 #endregion
965         }
966 }
967 #endif