/// <include file='doc\InstanceDescriptorCodeDomSerializer.uex' path='docs/doc[@for="InstanceDescriptorCodeDomSerializer.SerializeInstanceDescriptor"]/*' /> /// <devdoc> /// Serializes the given instance descriptor into a code model expression. /// </devdoc> private object SerializeInstanceDescriptor(IDesignerSerializationManager manager, object value, InstanceDescriptor descriptor) { Debug.WriteLineIf(traceSerialization.TraceVerbose, "InstanceDescriptorCodeDomSerializer::SerializeInstanceDescriptor"); Debug.Indent(); Debug.WriteLineIf(traceSerialization.TraceVerbose, "Member: " + descriptor.MemberInfo.Name); Debug.WriteLineIf(traceSerialization.TraceVerbose, "Argument count: " + descriptor.Arguments.Count); // Serialize all of the arguments. // CodeExpression[] arguments = new CodeExpression[descriptor.Arguments.Count]; int i = 0; bool paramsOk = true; foreach (object argument in descriptor.Arguments) { CodeValueExpression codeValue = new CodeValueExpression(null, argument, (argument != null ? argument.GetType() : null)); manager.Context.Push(codeValue); try { arguments[i] = SerializeToExpression(manager, argument); if (arguments[i] == null) { Debug.WriteLineIf(traceSerialization.TraceWarning, "WARNING: Parameter " + i.ToString() + " in instance descriptor call " + descriptor.GetType().Name + " could not be serialized."); paramsOk = false; break; } } finally { manager.Context.Pop(); } i++; } CodeExpression expression = null; if (paramsOk) { Type expressionType = descriptor.MemberInfo.DeclaringType; CodeTypeReference typeRef = new CodeTypeReference(expressionType); if (descriptor.MemberInfo is ConstructorInfo) { expression = new CodeObjectCreateExpression(typeRef, arguments); } else if (descriptor.MemberInfo is MethodInfo) { CodeTypeReferenceExpression typeRefExp = new CodeTypeReferenceExpression(typeRef); CodeMethodReferenceExpression methodRef = new CodeMethodReferenceExpression(typeRefExp, descriptor.MemberInfo.Name); expression = new CodeMethodInvokeExpression(methodRef, arguments); expressionType = ((MethodInfo)descriptor.MemberInfo).ReturnType; } else if (descriptor.MemberInfo is PropertyInfo) { CodeTypeReferenceExpression typeRefExp = new CodeTypeReferenceExpression(typeRef); CodePropertyReferenceExpression propertyRef = new CodePropertyReferenceExpression(typeRefExp, descriptor.MemberInfo.Name); Debug.Assert(arguments.Length == 0, "Property serialization does not support arguments"); expression = propertyRef; expressionType = ((PropertyInfo)descriptor.MemberInfo).PropertyType; } else if (descriptor.MemberInfo is FieldInfo) { Debug.Assert(arguments.Length == 0, "Field serialization does not support arguments"); CodeTypeReferenceExpression typeRefExp = new CodeTypeReferenceExpression(typeRef); expression = new CodeFieldReferenceExpression(typeRefExp, descriptor.MemberInfo.Name); expressionType = ((FieldInfo)descriptor.MemberInfo).FieldType; } else { Debug.Fail("Unrecognized reflection type in instance descriptor: " + descriptor.MemberInfo.GetType().Name); } // Finally, check to see if our value is assignable from the expression type. If not, // then supply a cast. The value may be an internal or protected type; if it is, // then walk up its hierarchy until we find one that is public. // Type targetType = value.GetType(); while (!targetType.IsPublic) { targetType = targetType.BaseType; } if (!targetType.IsAssignableFrom(expressionType)) { Debug.WriteLineIf(traceSerialization.TraceVerbose, "Target type of " + targetType.Name + " is not assignable from " + expressionType.Name + ". Supplying cast."); expression = new CodeCastExpression(targetType, expression); } } Debug.Unindent(); return(expression); }
/// <include file='doc\InstanceDescriptorCodeDomSerializer.uex' path='docs/doc[@for="InstanceDescriptorCodeDomSerializer.Serialize"]/*' /> /// <devdoc> /// Serializes the given object into a CodeDom object. /// </devdoc> public override object Serialize(IDesignerSerializationManager manager, object value) { object expression = null; Debug.WriteLineIf(traceSerialization.TraceVerbose, "InstanceDescriptorCodeDomSerializer::Serialize"); Debug.Indent(); // To serialize a primitive type, we must assign its value to the current statement. We get the current // statement by asking the context. object statement = manager.Context.Current; Debug.Assert(statement != null, "Statement is null -- we need a context to be pushed for instance descriptors to serialize"); Debug.WriteLineIf(traceSerialization.TraceVerbose, "Value: " + value.ToString()); Debug.WriteLineIf(traceSerialization.TraceVerbose && statement != null, "Statement: " + statement.GetType().Name); TypeConverter converter = TypeDescriptor.GetConverter(value); InstanceDescriptor descriptor = (InstanceDescriptor)converter.ConvertTo(value, typeof(InstanceDescriptor)); if (descriptor != null) { expression = SerializeInstanceDescriptor(manager, value, descriptor); } else { Debug.WriteLineIf(traceSerialization.TraceError, "*** Converter + " + converter.GetType().Name + " failed to give us an instance descriptor"); } // Ok, we have the "new Foo(arg, arg, arg)" done. Next, check to see if the instance // descriptor has given us a complete representation of the object. If not, we must // go through the additional work of creating a local variable and saving properties. // if (descriptor != null && !descriptor.IsComplete) { Debug.WriteLineIf(traceSerialization.TraceVerbose, "Incomplete instance descriptor; creating local variable declaration and serializing properties."); CodeStatementCollection statements = (CodeStatementCollection)manager.Context[typeof(CodeStatementCollection)]; Debug.WriteLineIf(traceSerialization.TraceError && statements == null, "*** No CodeStatementCollection on context stack so we can generate a local variable statement."); if (statements != null) { MemberInfo mi = descriptor.MemberInfo; Type targetType; if (mi is PropertyInfo) { targetType = ((PropertyInfo)mi).PropertyType; } else if (mi is MethodInfo) { targetType = ((MethodInfo)mi).ReturnType; } else { targetType = mi.DeclaringType; } string localName = manager.GetName(value); if (localName == null) { string baseName; INameCreationService ns = (INameCreationService)manager.GetService(typeof(INameCreationService)); Debug.WriteLineIf(traceSerialization.TraceWarning && (ns == null), "WARNING: Need to generate name for local variable but we have no service."); if (ns != null) { baseName = ns.CreateName(null, targetType); } else { baseName = targetType.Name.ToLower(CultureInfo.InvariantCulture); } int suffixIndex = 1; // Declare this name to the serializer. If there is already a name defined, // keep trying. // while (true) { localName = baseName + suffixIndex.ToString(); if (manager.GetInstance(localName) == null) { manager.SetName(value, localName); break; } suffixIndex++; } } Debug.WriteLineIf(traceSerialization.TraceVerbose, "Named local variable " + localName); CodeVariableDeclarationStatement localStatement = new CodeVariableDeclarationStatement(targetType, localName); localStatement.InitExpression = (CodeExpression)expression; statements.Add(localStatement); expression = new CodeVariableReferenceExpression(localName); // Create a CodeValueExpression to place on the context stack. CodeValueExpression cve = new CodeValueExpression((CodeExpression)expression, value); manager.Context.Push(cve); try { // Now that we have hooked the return expression up and declared the local, // it's time to save off the properties for the object. // SerializeProperties(manager, statements, value, runTimeProperties); } finally { Debug.Assert(manager.Context.Current == cve, "Context stack corrupted"); manager.Context.Pop(); } } } Debug.Unindent(); return(expression); }
/// <include file='doc\CollectionCodeDomSerializer.uex' path='docs/doc[@for="CollectionCodeDomSerializer.SerializeViaAddRange"]/*' /> /// <devdoc> /// Serializes the given collection by creating an array and passing it to the AddRange method. /// </devdoc> private object SerializeViaAddRange( IDesignerSerializationManager manager, CodePropertyReferenceExpression propRef, ICollection collection, MethodInfo addRangeMethod, ParameterInfo parameter, object targetObject) { Debug.WriteLineIf(traceSerialization.TraceVerbose, "CollectionCodeDomSerializer::SerializeViaAddRange"); Debug.Indent(); Debug.WriteLineIf(traceSerialization.TraceVerbose, "Collection: " + collection.GetType().Name); Debug.WriteLineIf(traceSerialization.TraceVerbose, "Elements: " + collection.Count.ToString()); CodeStatementCollection statements = new CodeStatementCollection(); MethodInfo clearMethod = collection.GetType().GetMethod("Clear", new Type[0]); if (clearMethod != null) { PropertyDescriptor clearProp = manager.Properties["ClearCollections"]; if (clearProp != null && clearProp.PropertyType == typeof(bool) && ((bool)clearProp.GetValue(manager) == true)) { // insert code here to clear the collecion... // statements.Add(new CodeMethodInvokeExpression(propRef, "Clear")); } } if (collection.Count == 0) { Debug.Unindent(); return(statements); } // We must walk the collection looking for privately inherited objects. If we find them, // we need to exclude them from the array. // ArrayList arrayList = new ArrayList(collection.Count); bool isTargetInherited = false; InheritedPropertyDescriptor inheritedDesc = manager.Context[typeof(PropertyDescriptor)] as InheritedPropertyDescriptor; if (inheritedDesc != null) { isTargetInherited = true; collection = GetCollectionDelta(inheritedDesc.OriginalValue as ICollection, collection); if (collection.Count == 0) { Debug.Unindent(); return(statements); } } CodeValueExpression codeValue = new CodeValueExpression(null, collection, parameter.ParameterType.GetElementType()); manager.Context.Push(codeValue); try { foreach (object o in collection) { // If this object is being privately inherited, it cannot be inside // this collection. // bool genCode = !(o is IComponent); if (!genCode) { InheritanceAttribute ia = (InheritanceAttribute)TypeDescriptor.GetAttributes(o)[typeof(InheritanceAttribute)]; if (ia != null) { if (ia.InheritanceLevel == InheritanceLevel.InheritedReadOnly) { genCode = false; } else if (ia.InheritanceLevel == InheritanceLevel.Inherited && isTargetInherited) { genCode = false; } else { genCode = true; } } else { genCode = true; } } if (genCode) { CodeExpression exp = SerializeToExpression(manager, o); if (exp != null) { arrayList.Add(exp); } } } } finally { manager.Context.Pop(); } if (arrayList.Count > 0) { // Now convert the array list into an array create expression. // CodeTypeReference elementTypeRef = new CodeTypeReference(parameter.ParameterType.GetElementType()); // Now create an ArrayCreateExpression, and fill its initializers. // CodeArrayCreateExpression arrayCreate = new CodeArrayCreateExpression(); arrayCreate.CreateType = elementTypeRef; foreach (CodeExpression exp in arrayList) { arrayCreate.Initializers.Add(exp); } CodeMethodReferenceExpression methodRef = new CodeMethodReferenceExpression(propRef, addRangeMethod.Name); CodeMethodInvokeExpression methodInvoke = new CodeMethodInvokeExpression(); methodInvoke.Method = methodRef; methodInvoke.Parameters.Add(arrayCreate); statements.Add(new CodeExpressionStatement(methodInvoke)); } Debug.Unindent(); return(statements); }
/// <include file='doc\CollectionCodeDomSerializer.uex' path='docs/doc[@for="CollectionCodeDomSerializer.SerializeViaAdd"]/*' /> /// <devdoc> /// Serializes the given collection by creating multiple calls to an Add method. /// </devdoc> private object SerializeViaAdd( IDesignerSerializationManager manager, CodePropertyReferenceExpression propRef, ICollection collection, MethodInfo addMethod, ParameterInfo parameter, object targetObject) { Debug.WriteLineIf(traceSerialization.TraceVerbose, "CollectionCodeDomSerializer::SerializeViaAdd"); Debug.Indent(); Debug.WriteLineIf(traceSerialization.TraceVerbose, "Collection: " + collection.GetType().Name); Debug.WriteLineIf(traceSerialization.TraceVerbose, "Elements: " + collection.Count.ToString()); // Here we need to invoke Add once for each and every item in the collection. We can re-use the property // reference and method reference, but we will need to recreate the invoke statement each time. // CodeStatementCollection statements = new CodeStatementCollection(); CodeMethodReferenceExpression methodRef = new CodeMethodReferenceExpression(propRef, addMethod.Name); MethodInfo clearMethod = collection.GetType().GetMethod("Clear", new Type[0]); if (clearMethod != null) { PropertyDescriptor clearProp = manager.Properties["ClearCollections"]; if (clearProp != null) { // insert code here to clear the collecion... // statements.Add(new CodeMethodInvokeExpression(propRef, "Clear")); } } bool isTargetInherited = false; InheritedPropertyDescriptor inheritedDesc = manager.Context[typeof(PropertyDescriptor)] as InheritedPropertyDescriptor; if (inheritedDesc != null) { isTargetInherited = true; collection = GetCollectionDelta(inheritedDesc.OriginalValue as ICollection, collection); if (collection.Count == 0) { Debug.Unindent(); return(statements); } } foreach (object o in collection) { // If this object is being privately inherited, it cannot be inside // this collection. // bool genCode = !(o is IComponent); if (!genCode) { InheritanceAttribute ia = (InheritanceAttribute)TypeDescriptor.GetAttributes(o)[typeof(InheritanceAttribute)]; if (ia != null) { if (ia.InheritanceLevel == InheritanceLevel.InheritedReadOnly) { genCode = false; } else if (ia.InheritanceLevel == InheritanceLevel.Inherited && isTargetInherited) { genCode = false; } else { genCode = true; } } else { genCode = true; } } if (genCode) { CodeMethodInvokeExpression statement = new CodeMethodInvokeExpression(); statement.Method = methodRef; CodeValueExpression codeValue = new CodeValueExpression(null, o, parameter.ParameterType); manager.Context.Push(codeValue); CodeExpression serializedObj = null; try { serializedObj = SerializeToExpression(manager, o); } finally { manager.Context.Pop(); } if (serializedObj != null) { statement.Parameters.Add(serializedObj); statements.Add(statement); } } } Debug.Unindent(); return(statements); }
/// <include file='doc\CollectionCodeDomSerializer.uex' path='docs/doc[@for="CollectionCodeDomSerializer.SerializeArray"]/*' /> /// <devdoc> /// Serializes the given array. /// </devdoc> private object SerializeArray(IDesignerSerializationManager manager, CodePropertyReferenceExpression propRef, Type asType, Array array, object targetObject) { object result = null; Debug.WriteLineIf(traceSerialization.TraceVerbose, "CollectionCodeDomSerializer::SerializeArray"); Debug.Indent(); if (array.Rank != 1) { Debug.WriteLineIf(traceSerialization.TraceError, "*** Cannot serialize arrays with rank > 1. ***"); manager.ReportError(SR.GetString(SR.SerializerInvalidArrayRank, array.Rank.ToString())); } else { // For an array, we need an array create expression. First, get the array type // Type elementType = null; if (asType != null) { elementType = asType; } else { elementType = array.GetType().GetElementType(); } CodeTypeReference elementTypeRef = new CodeTypeReference(elementType); Debug.WriteLineIf(traceSerialization.TraceVerbose, "Array type: " + elementType.Name); Debug.WriteLineIf(traceSerialization.TraceVerbose, "Length:" + array.Length.ToString()); // Now create an ArrayCreateExpression, and fill its initializers. // CodeArrayCreateExpression arrayCreate = new CodeArrayCreateExpression(); arrayCreate.CreateType = elementTypeRef; bool arrayOk = true; ICollection collection = array; bool isTargetInherited = false; IComponent comp = targetObject as IComponent; if (comp != null) { InheritanceAttribute ia = (InheritanceAttribute)TypeDescriptor.GetAttributes(comp)[typeof(InheritanceAttribute)]; isTargetInherited = (ia != null && ia.InheritanceLevel == InheritanceLevel.Inherited); } if (isTargetInherited) { InheritedPropertyDescriptor inheritedDesc = manager.Context[typeof(PropertyDescriptor)] as InheritedPropertyDescriptor; if (inheritedDesc != null) { collection = GetCollectionDelta(inheritedDesc.OriginalValue as ICollection, array); } } CodeValueExpression codeValue = new CodeValueExpression(null, collection, elementType); manager.Context.Push(codeValue); try { foreach (object o in collection) { // If this object is being privately inherited, it cannot be inside // this collection. Since we're writing an entire array here, we // cannot write any of it. // if (o is IComponent && TypeDescriptor.GetAttributes(o).Contains(InheritanceAttribute.InheritedReadOnly)) { arrayOk = false; break; } object expression = SerializeToExpression(manager, o); if (expression is CodeExpression) { arrayCreate.Initializers.Add((CodeExpression)expression); } else { arrayOk = false; break; } } } finally { manager.Context.Pop(); } // if we weren't given a property, we're done. Otherwise, we must create an assign statement for // the property. // if (arrayOk) { if (propRef != null) { result = new CodeAssignStatement(propRef, arrayCreate); } else { result = arrayCreate; } } } Debug.Unindent(); return(result); }
/// <include file='doc\CollectionCodeDomSerializer.uex' path='docs/doc[@for="CollectionCodeDomSerializer.Serialize"]/*' /> /// <devdoc> /// Serializes the given object into a CodeDom object. /// </devdoc> public override object Serialize(IDesignerSerializationManager manager, object value) { object result = null; Debug.WriteLineIf(traceSerialization.TraceVerbose, "CollectionCodeDomSerializer::Serialize"); Debug.Indent(); // We serialize collections as follows: // // If the collection is an array, we write out the array. // // If the collection has a method called AddRange, we will // call that, providing an array. // // If the colleciton has an Add method, we will call it // repeatedly. // // If the collection is an IList, we will cast to IList // and add to it. // // If the collection has no add method, but is marked // with PersistContents, we will enumerate the collection // and serialize each element. // Check to see if there is a CodePropertyReferenceExpression on the stack. If there is, // we can use it as a guide for serialization. // object context = manager.Context.Current; if (context is CodeValueExpression) { CodeValueExpression valueEx = (CodeValueExpression)context; if (valueEx.Value == value) { context = valueEx.Expression; } } if (context is CodePropertyReferenceExpression) { Debug.WriteLineIf(traceSerialization.TraceVerbose, "Property reference encountered on context stack."); // Only serialize if the value is a collection. // Debug.Assert(value is ICollection, "Collection serializer invoked for non-collection: " + (value == null ? "(null)" : value.GetType().Name)); if (value is ICollection) { CodePropertyReferenceExpression propRef = (CodePropertyReferenceExpression)context; object targetObject = DeserializeExpression(manager, null, propRef.TargetObject); Debug.WriteLineIf(traceSerialization.TraceWarning && targetObject == null, "WARNING: Failed to deserialize property reference target"); if (targetObject != null) { PropertyDescriptor prop = TypeDescriptor.GetProperties(targetObject)[propRef.PropertyName]; if (prop != null) { Type propertyType = prop.PropertyType; if (typeof(Array).IsAssignableFrom(propertyType)) { Debug.WriteLineIf(traceSerialization.TraceVerbose, "Collection is array"); result = SerializeArray(manager, propRef, propertyType.GetElementType(), (Array)value, targetObject); } else { Debug.WriteLineIf(traceSerialization.TraceVerbose, "Searching for AddRange or Add"); MethodInfo[] methods = propertyType.GetMethods(BindingFlags.Public | BindingFlags.Instance); MethodInfo addRange = null; MethodInfo add = null; ParameterInfo[] parameters = null; foreach (MethodInfo method in methods) { if (method.Name.Equals("AddRange")) { parameters = method.GetParameters(); if (parameters.Length == 1 && parameters[0].ParameterType.IsArray) { addRange = method; if (PreferAddRange) { break; } } } if (method.Name.Equals("Add")) { parameters = method.GetParameters(); if (parameters.Length == 1) { add = method; if (!PreferAddRange) { break; } } } } if (!PreferAddRange && addRange != null && add != null) { addRange = null; } if (addRange != null) { result = SerializeViaAddRange(manager, propRef, (ICollection)value, addRange, parameters[0], targetObject); } else if (add != null) { result = SerializeViaAdd(manager, propRef, (ICollection)value, add, parameters[0], targetObject); } } } } } } else { Debug.WriteLineIf(traceSerialization.TraceVerbose, "No property reference encountered on context stack, serializing as array expression."); if (value is Array) { result = SerializeArray(manager, null, null, (Array)value, null); } } Debug.Unindent(); return(result); }