예제 #1
0
        /// <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);
        }
예제 #2
0
        /// <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);
        }