ComponentCodeDomSerializer.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ DotNET / DotNET / 8.0 / untmp / whidbey / REDBITS / ndp / fx / src / Designer / CompMod / System / ComponentModel / Design / Serialization / ComponentCodeDomSerializer.cs / 1 / ComponentCodeDomSerializer.cs

                             
//------------------------------------------------------------------------------
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
//  
//-----------------------------------------------------------------------------
 
/* 
 */
namespace System.ComponentModel.Design.Serialization { 

    using System;
    using System.Design;
    using System.CodeDom; 
    using System.Configuration;
    using System.Collections; 
    using System.ComponentModel; 
    using System.ComponentModel.Design;
    using System.Diagnostics; 
    using System.Reflection;
    using System.Text;

    internal class ComponentCodeDomSerializer : CodeDomSerializer { 

        private static readonly Type[] _containerConstructor = new Type[] {typeof(IContainer)}; 
        private static readonly Attribute[] _runTimeFilter = new Attribute[] { DesignOnlyAttribute.No }; 
        private static readonly Attribute[] _designTimeFilter = new Attribute[] { DesignOnlyAttribute.Yes };
        private static ComponentCodeDomSerializer _default; 

        /// 
        /// 
        ///     Retrieves a default static instance of this serializer. 
        /// 
        internal new static ComponentCodeDomSerializer Default { 
            get { 
                if (_default == null) {
                    _default = new ComponentCodeDomSerializer(); 
                }
                return _default;
            }
        } 

        ///  
        ///     Determines if we can cache the results of serializing a component. 
        /// 
 		private bool CanCacheComponent(IDesignerSerializationManager manager, object value, PropertyDescriptorCollection props) 
		{
			IComponent comp = value as IComponent;

            if (comp != null) { 
                if (comp.Site != null) {
                    INestedSite nestedSite = comp.Site as INestedSite; 
                    if (nestedSite != null && !string.IsNullOrEmpty(nestedSite.FullName)) { 
                        return false;
                    } 
                }

				if (props == null)
 				{ 
					props = TypeDescriptor.GetProperties(comp);
 				} 
 				foreach (PropertyDescriptor property in props) { 
                    if (typeof(IComponent).IsAssignableFrom(property.PropertyType) && !property.Attributes.Contains(DesignerSerializationVisibilityAttribute.Hidden)) {
                        MemberCodeDomSerializer memberSerializer = (MemberCodeDomSerializer)manager.GetSerializer(property.GetType(), typeof(MemberCodeDomSerializer)); 

                        if (memberSerializer != null && memberSerializer.ShouldSerialize(manager, value, property))
                            return false;
                    } 
                }
            } 
 
            return true;
        } 

        /// 
        ///    This method is invoked during deserialization to obtain an instance of an object.  When this is called, an instance
        ///    of the requested type should be returned.  This implementation calls base and then tries to deserialize design 
        ///    time properties for the component.
        ///  
        protected override object DeserializeInstance(IDesignerSerializationManager manager, Type type, object[] parameters, string name, bool addToContainer) { 

            object instance = base.DeserializeInstance(manager, type, parameters, name, addToContainer); 

            if (instance != null) {
                Trace("Deserializing design time properties for {0}", manager.GetName(instance));
                DeserializePropertiesFromResources(manager, instance, _designTimeFilter); 
            }
 
            return instance; 
        }
 
        /// 
        /// 
        ///     Serializes the given object into a CodeDom object.
        ///  
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2102:CatchNonClsCompliantExceptionsInGeneralHandlers")]
        public override object Serialize(IDesignerSerializationManager manager, object value) { 
            CodeStatementCollection statements = null; 
			PropertyDescriptorCollection props = TypeDescriptor.GetProperties(value);
 			using (TraceScope("ComponentCodeDomSerializer::Serialize")) { 
                if (manager == null || value == null) {
                    throw new ArgumentNullException(manager == null ? "manager" : "value");
                }
 
                if (IsSerialized(manager, value)) {
                    Debug.Fail("Serialize is being called twice for the same component"); 
                    return GetExpression(manager, value); 
                }
 
                // If the object is being inherited, we will will not emit a variable declaration.  Also, we won't
                // do any serialization at all if the object is privately inherited.
                InheritanceLevel inheritanceLevel = InheritanceLevel.NotInherited;
                InheritanceAttribute inheritanceAttribute = (InheritanceAttribute)TypeDescriptor.GetAttributes(value)[typeof(InheritanceAttribute)]; 

                if (inheritanceAttribute != null) { 
                    inheritanceLevel = inheritanceAttribute.InheritanceLevel; 
                }
 
                // First, skip everything if we're privately inherited.  We cannot write any code that would affect this
                // component.
                TraceIf(inheritanceLevel == InheritanceLevel.InheritedReadOnly, "Skipping read only inherited component");
                if (inheritanceLevel != InheritanceLevel.InheritedReadOnly) { 

                    // Things we need to know: 
                    // 
                    // 1.  What expression should we use for the left hand side
                    //      a) already given to us via GetExpression? 
                    //      b) a local variable?
                    //      c) a member variable?
                    //
                    // 2.  Should we generate an init expression for this 
                    //     object?
                    //      a) Inherited or existing expression: no 
                    //      b) otherwise, yes. 

                    statements = new CodeStatementCollection(); 
                    CodeTypeDeclaration typeDecl = manager.Context[typeof(CodeTypeDeclaration)] as CodeTypeDeclaration;
                    RootContext rootCxt = manager.Context[typeof(RootContext)] as RootContext;
                    CodeExpression assignLhs = null;
                    CodeExpression assignRhs; 

                    // Defaults for components 
                    bool generateLocal = false; 
                    bool generateField = true;
                    bool generateObject = true; 
                    bool isComplete = false;

                    assignLhs = GetExpression(manager, value);
 
                    if (assignLhs != null) {
                        Trace("Existing expression for LHS of value"); 
                        generateLocal = false; 
                        generateField = false;
                        generateObject = false; 

                         // VSWhidbey 312327: if we have an existing expression and this is not
                         // a sited component, do not serialize it.  We need this for Everett / 1.0
                         // backwards compat (even though it's wrong). 
                         IComponent comp = value as IComponent;
                         if (comp != null && comp.Site == null) { 
                             // And, VSWhidbey 445114:  Everett detected when we were in a serialize content 
                             // property and would still serialize it.  This code reverses what the
                             // outer if block does for this specific case.  We also need this 
                             // for Everett / 1.0 backwards compat.
                             ExpressionContext expCxt = manager.Context[typeof(ExpressionContext)] as ExpressionContext;
                             if (expCxt == null || expCxt.PresetValue != value) {
                                 isComplete = true; 
                             }
                         } 
                    } 
                    else {
                        Trace("Creating LHS expression"); 
						if (inheritanceLevel == InheritanceLevel.NotInherited) {
                            // See if there is a "GenerateMember" property.  If so,
                            // we might want to generate a local variable.  Otherwise,
                            // we want to generate a field. 
                            PropertyDescriptor generateProp = props["GenerateMember"];
                            if (generateProp != null && generateProp.PropertyType == typeof(bool) && !(bool)generateProp.GetValue(value)) { 
                                Trace("Object GenerateMember property wants a local variable"); 
                                generateLocal = true;
                                generateField = false; 
                            }
                        }
                        else {
                            generateObject = false; 
                        }
 
                        if (rootCxt == null) { 
                            generateLocal = true;
                            generateField = false; 
                        }
                    }

                    // Push the component being serialized onto the stack.  It may be handy to 
                    // be able to discover this.
                    manager.Context.Push(value); 
                    manager.Context.Push(statements); 

                    try { 

                        string name = manager.GetName(value);

                        Type type = TypeDescriptor.GetReflectionType(value); 
                        string typeName = TypeDescriptor.GetClassName(value);
 
                        // Output variable / field declarations if we need to 
                        if ((generateField || generateLocal) && name != null) {
                            if (generateField) { 

                                if (inheritanceLevel == InheritanceLevel.NotInherited) {
                                    // We need to generate the field declaration.  See if there is a modifiers property on
                                    // the object.  If not, look for a DefaultModifies, and finally assume it's private. 
                                    CodeMemberField field = new CodeMemberField(typeName, name);
                                    PropertyDescriptor modifersProp = props["Modifiers"]; 
                                    MemberAttributes fieldAttrs; 

                                    if (modifersProp == null) { 
                                        modifersProp = props["DefaultModifiers"];
                                    }

                                    if (modifersProp != null && modifersProp.PropertyType == typeof(MemberAttributes)) { 
                                        fieldAttrs = (MemberAttributes)modifersProp.GetValue(value);
                                    } 
                                    else { 
                                        TraceWarning("No Modifiers or DefaultModifiers property on component {0}. We must assume private.", name);
                                        fieldAttrs = MemberAttributes.Private; 
                                    }

                                    field.Attributes = fieldAttrs;
                                    typeDecl.Members.Add(field); 
                                    Trace("Field {0} {1} {2} created.", fieldAttrs, typeName, name);
                                } 
 
                                // Next, create a nice LHS for our pending assign statement, when we hook up the variable.
                                assignLhs = new CodeFieldReferenceExpression(rootCxt.Expression, name); 
                            }
                            else {
                                if (inheritanceLevel == InheritanceLevel.NotInherited) {
                                    CodeVariableDeclarationStatement local = new CodeVariableDeclarationStatement(typeName, name); 

                                    statements.Add(local); 
                                    Trace("Local {0} {1} created.", typeName, name); 
                                }
 
                                assignLhs = new CodeVariableReferenceExpression(name);
                            }
                        }
 
                        // Now output an object create if we need to.  We always see if there is a
                        // type converter that can provide us guidance 
 
                        if (generateObject) {
                            // Ok, now that we've decided if we have a local or a member variable, its now time to serialize the rest of the code. 
                            // The first step is to create an assign statement to "new" the object.  For that, we need to know if
                            // the component wants a special IContainer constructor or not.  For that to be valid we must also know
                            // that we can get to an actual IContainer.
                            IContainer container = manager.GetService(typeof(IContainer)) as IContainer; 
                            ConstructorInfo ctor = TypeDescriptor.GetReflectionType(value).GetConstructor(BindingFlags.ExactBinding | BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly, null, _containerConstructor, null);
 
                            if (ctor != null && container != null) { 
                                Trace("Component has IContainer constructor.");
                                assignRhs = new CodeObjectCreateExpression(typeName, new CodeExpression[] { 
                                    SerializeToExpression(manager, container)
                                });
                            }
                            else { 
                                // For compat reasons we ignore the isCompleteOld value here.
                                // See VSWhidbey 415411 for more information. 
                                bool isCompleteOld; 
                                assignRhs = SerializeCreationExpression(manager, value, out isCompleteOld);
                                Debug.Assert(isCompleteOld == isComplete, "CCDS Differing"); 
                            }

                            TraceErrorIf(assignRhs == null, "No RHS code assign for object {0}", value);
                            if (assignRhs != null) { 

                                if (assignLhs == null) { 
                                    // We cannot do much more for this object.  If isComplete is true, 
                                    // then the RHS now becomes our LHS.  Otherwise, I'm afraid we have
                                    // just failed to serialize this object. 
                                    if (isComplete) {
                                        assignLhs = assignRhs;
                                    }
                                    else { 
                                        TraceError("Incomplete serialization of object, abandoning serialization.");
                                    } 
                                } 
                                else {
                                    CodeAssignStatement assign = new CodeAssignStatement(assignLhs, assignRhs); 
                                    statements.Add(assign);
                                }
                            }
                        } 

                        if (assignLhs != null) { 
                            SetExpression(manager, value, assignLhs); 
                        }
 
                        // It should practically be an assert that isComplete is false, but someone may
                        // have a really funky component.
                        if (assignLhs != null && !isComplete) {
                            // VSWhidbey #111957 -.NET CF needs us to verify that the ISupportInitialize interface exists 
                            // (they do not support this interface and will modify their DSM to resolve the type to null).
                            bool supportInitialize = (value is ISupportInitialize) && manager.GetType(typeof(ISupportInitialize).FullName) != null; 
                            bool persistSettings = (value is IPersistComponentSettings) && ((IPersistComponentSettings)value).SaveSettings && manager.GetType(typeof(IPersistComponentSettings).FullName) != null; 

                            // We implement statement caching only for the main code generation phase.  We don't implement it for other 
                            // serialization managers.  How do we tell the difference?  The main serialization manager exists as a service.
                            IDesignerSerializationManager mainManager = (IDesignerSerializationManager)manager.GetService(typeof(IDesignerSerializationManager));

                            if (supportInitialize) { 
                                Trace("Object implements ISupportInitialize.");
                                SerializeSupportInitialize(manager, statements, assignLhs, value, "BeginInit"); 
                            } 
                            SerializePropertiesToResources(manager, statements, value, _designTimeFilter);
 
                            // Writing out properties is expensive.  But, we're very smart and we cache the results
                            // in ComponentCache.  See if we have cached results.  If so, use 'em.  If not, generate
                            // code and then see if we can cache the results for later.
                            ComponentCache cache = (ComponentCache)manager.GetService(typeof(ComponentCache)); 
                            ComponentCache.Entry entry = null;
                            if (cache == null) { 
                                IServiceContainer sc = (IServiceContainer)manager.GetService(typeof(IServiceContainer)); 

                                if (sc != null) { 
                                    cache = new ComponentCache(manager);
                                    sc.AddService(typeof(ComponentCache), cache);
                                }
                            } 
                            else {
                                if (manager == mainManager && cache != null && cache.Enabled) { 
                                    entry = cache[value]; 
                                }
                            } 

                            if (entry == null || entry.Tracking) {

                                // Pushing the entry here allows it to be found by the resource code dom serializer, 
                                // which will add data to the ResourceBlob property on the entry.
                                if (entry == null) { 
                                    entry = new ComponentCache.Entry(cache); 

                                    // VSWhidbey 410415 
                                    // We cache components even if they're not valid so dependencies are
                                    // still tracked correctly (see comment below).  The problem is, we will create a
                                    // new entry object even if there is still an existing one that is just invalid, and it
                                    // might have depenendecies that will be lost. 
                                    // we need to make sure we copy oevr any dependencies that are also tracked.
                                    ComponentCache.Entry oldEntry = null; 
                                    oldEntry = cache.GetEntryAll(value); 
                                    if (oldEntry != null && oldEntry.Dependencies != null && oldEntry.Dependencies.Count > 0) {
                                        foreach(object dependency in oldEntry.Dependencies) { 
                                            entry.AddDependency(dependency);
                                        }
                                    }
 
                                }
                                entry.Component = value; // we need to link the cached entry with its corresponding component right away, before it's put in the context 
                                                        // see CodeDomSerializerBase.cs::GetExpression for usage 

                                // This entry will only be used if the valid bit is set. 
                                // This is useful because we still need to setup depedency relationships
                                // between components even if they are not cached.  See VSWhidbey 263053.
                                bool correctManager = manager == mainManager;
                                entry.Valid = correctManager && CanCacheComponent(manager, value, props); 

                                if (correctManager && cache != null && cache.Enabled) { 
                                    manager.Context.Push(cache); 
                                    manager.Context.Push(entry);
                                } 


                                try {
                                    entry.Statements = new CodeStatementCollection(); 
                                    SerializeProperties(manager, entry.Statements, value, _runTimeFilter);
                                    SerializeEvents(manager, entry.Statements, value, null); 
 
                                    foreach (CodeStatement statement in entry.Statements) {
                                        CodeVariableDeclarationStatement local = statement as CodeVariableDeclarationStatement; 
                                        if (local != null) {
                                            entry.Tracking = true;
                                            break;
                                        } 
                                    }
 
                                    if (entry.Statements.Count > 0) { 

                                        // if we added some statements, insert the comments 
                                        //
                                        entry.Statements.Insert(0, new CodeCommentStatement(string.Empty));
                                        entry.Statements.Insert(0, new CodeCommentStatement(name));
                                        entry.Statements.Insert(0, new CodeCommentStatement(string.Empty)); 

                                        // 
                                        // cache the statements for future usage if possible. We only do this for the main serialization manager, not 
                                        // for any other seriallization managers that may be calling us for undo or clipboard functions.
                                        if (correctManager && cache != null && cache.Enabled) { 
                                            cache[value] = entry;
                                        }
                                    }
                                } 
                                finally {
                                    if (correctManager && cache != null && cache.Enabled) { 
                                        Debug.Assert(manager.Context.Current == entry, "Context stack corrupted"); 
                                        manager.Context.Pop();
                                        manager.Context.Pop(); 
                                    }
                                }
                            }
                            else { 
                                // If we got a cache entry, we will need to take all the resources out of
                                // it and apply them too. 
                                if ((entry.Resources != null || entry.Metadata != null) && cache != null && cache.Enabled) { 
                                    ResourceCodeDomSerializer res = ResourceCodeDomSerializer.Default;
                                    res.ApplyCacheEntry(manager, entry); 
                                }
                            }

                            // Regarless, apply statements.  Either we created them or we got them 
                            // out of the cache.
                            statements.AddRange(entry.Statements); 
 
                            if (persistSettings) {
                                SerializeLoadComponentSettings(manager, statements, assignLhs, value); 
                            }

                            if (supportInitialize) {
                                SerializeSupportInitialize(manager, statements, assignLhs, value, "EndInit"); 
                            }
                        } 
                    } 
                    catch (CheckoutException) {
                        throw; 
                    }
                    catch (Exception ex) {
                        manager.ReportError(ex);
                    } 
                    finally {
                        Debug.Assert(manager.Context.Current == statements, "Context stack corrupted"); 
                        manager.Context.Pop(); 
                        manager.Context.Pop();
                    } 
                }
            }

            return statements; 
        }
 
        ///  
        /// 
        ///     This emits a method invoke to IPersistComponentSettings.LoadComponentSettings. 
        /// 
        private void SerializeLoadComponentSettings(IDesignerSerializationManager manager, CodeStatementCollection statements, CodeExpression valueExpression, object value) {
            Trace("Emitting LoadComponentSettings");
 
            CodeTypeReference type = new CodeTypeReference(typeof(IPersistComponentSettings));
            CodeCastExpression castExp = new CodeCastExpression(type, valueExpression); 
            CodeMethodReferenceExpression method = new CodeMethodReferenceExpression(castExp, "LoadComponentSettings"); 
            CodeMethodInvokeExpression methodInvoke = new CodeMethodInvokeExpression();
 
            methodInvoke.Method = method;

            CodeExpressionStatement statement = new CodeExpressionStatement(methodInvoke);
            statement.UserData["statement-ordering"] = "end"; 

            statements.Add(statement); 
        } 

        ///  
        /// 
        ///     This emits a method invoke to ISupportInitialize.
        /// 
        private void SerializeSupportInitialize(IDesignerSerializationManager manager, CodeStatementCollection statements, CodeExpression valueExpression, object value, string methodName) { 
            Trace("Emitting {0}", methodName);
 
            CodeTypeReference type = new CodeTypeReference(typeof(ISupportInitialize)); 
            CodeCastExpression castExp = new CodeCastExpression(type, valueExpression);
            CodeMethodReferenceExpression method = new CodeMethodReferenceExpression(castExp, methodName); 
            CodeMethodInvokeExpression methodInvoke = new CodeMethodInvokeExpression();

            methodInvoke.Method = method;
 
            CodeExpressionStatement statement = new CodeExpressionStatement(methodInvoke);
 
            if (methodName == "BeginInit") { 
                statement.UserData["statement-ordering"] = "begin";
            } 
            else {
                statement.UserData["statement-ordering"] = "end";
            }
 
            statements.Add(statement);
        } 
    } 
}
 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.


                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK