Code:
/ FX-1434 / FX-1434 / 1.0 / untmp / whidbey / REDBITS / ndp / fx / src / Designer / CompMod / System / ComponentModel / Design / Serialization / RootCodeDomSerializer.cs / 1 / RootCodeDomSerializer.cs
//------------------------------------------------------------------------------ //// Copyright (c) Microsoft Corporation. All rights reserved. // //----------------------------------------------------------------------------- /* */ namespace System.ComponentModel.Design.Serialization { using System.Design; using System; using System.CodeDom; using System.CodeDom.Compiler; using System.Collections; using System.Collections.Specialized; using System.ComponentModel; using System.ComponentModel.Design; using System.Diagnostics; using System.Resources; using System.Runtime.Serialization; using System.Globalization; /// ******************************************************************************************* /// NOTE: /// /// This class is NOT used for Whidbey. It has been replaced by TypeCodeDomSerializer as root /// serializers are no longer in vogue. It is still here because we need to be compatible with /// existing code bases that use root serialization. Don't remove it, but be careful when fixing /// bugs because you might not be changing the right bits. /// /// ******************************************************************************************* /// ////// /// This is our root serialization object. It is responsible for organizing all of the /// serialization for subsequent objects. This inherits from ComponentCodeDomSerializer /// in order to share useful methods. /// internal sealed class RootCodeDomSerializer : ComponentCodeDomSerializer { // Used only during deserialization to provide name to object mapping. // private IDictionary nameTable; private IDictionary statementTable; private CodeMemberMethod initMethod; private bool containerRequired; private static readonly Attribute[] designTimeProperties = new Attribute[] { DesignOnlyAttribute.Yes}; private static readonly Attribute[] runTimeProperties = new Attribute[] { DesignOnlyAttribute.No}; ////// /// The name of the IContainer we will use for components that require a container. /// Note that compnent model serializer also has this property. /// public string ContainerName { get { return "components"; } } ////// /// The component serializer will set this to true if it emitted a compnent declaration that required /// a container. /// public bool ContainerRequired { get { return containerRequired; } set { containerRequired = value; } } ////// /// The name of the method we will serialize into. We always use this, so if there /// is a need to change it down the road, we can make it virtual. /// public string InitMethodName { get { return "InitializeComponent"; } } ////// /// Unility method that adds the given statement to our statementTable dictionary under the /// given name. /// private void AddStatement(string name, CodeStatement statement) { OrderedCodeStatementCollection statements = (OrderedCodeStatementCollection)statementTable[name]; if (statements == null) { statements = new OrderedCodeStatementCollection(); // push in an order key so we know what position this item was in the list of declarations. // this allows us to preserve ZOrder. // statements.Order = statementTable.Count; statements.Name = name; statementTable[name] = statements; } statements.Add(statement); } ////// /// Deserilizes the given CodeDom element into a real object. This /// will use the serialization manager to create objects and resolve /// data types. The root of the object graph is returned. /// public override object Deserialize(IDesignerSerializationManager manager, object codeObject) { if (manager == null || codeObject == null) { throw new ArgumentNullException( manager == null ? "manager" : "codeObject"); } object documentObject = null; using (TraceScope("RootCodeDomSerializer::Deserialize")) { if (!(codeObject is CodeTypeDeclaration)) { Debug.Fail("RootCodeDomSerializer::Deserialize requires a CodeTypeDeclaration to parse"); throw new ArgumentException(SR.GetString(SR.SerializerBadElementType, typeof(CodeTypeDeclaration).FullName)); } // Determine case-sensitivity // bool caseInsensitive = false; CodeDomProvider provider = manager.GetService(typeof(CodeDomProvider)) as CodeDomProvider; TraceWarningIf(provider == null, "CodeDomProvider is not a service provided by the serialization manager. We use this to determine case sensitivity. Assuming language is not case sensitive."); if (provider != null) { caseInsensitive = ((provider.LanguageOptions & LanguageOptions.CaseInsensitive) != 0); } // Get and initialize the document type. // CodeTypeDeclaration docType = (CodeTypeDeclaration)codeObject; CodeTypeReference baseType = null; Type type = null; foreach (CodeTypeReference typeRef in docType.BaseTypes) { Type t = manager.GetType(GetTypeNameFromCodeTypeReference(manager, typeRef)); if (t != null && !(t.IsInterface)) { baseType = typeRef; type = t; break; } } Trace("Document type: {0} of type {1}", docType.Name, baseType.BaseType); if (type == null) { Exception ex = new SerializationException(SR.GetString(SR.SerializerTypeNotFound, baseType.BaseType)); ex.HelpLink = SR.SerializerTypeNotFound; throw ex; } if (type.IsAbstract) { Exception ex = new SerializationException(SR.GetString(SR.SerializerTypeAbstract, type.FullName)); ex.HelpLink = SR.SerializerTypeAbstract; throw ex; } ResolveNameEventHandler onResolveName = new ResolveNameEventHandler(OnResolveName); manager.ResolveName += onResolveName; // HACK for backwards compatibility. if (!(manager is DesignerSerializationManager)) { manager.AddSerializationProvider(new CodeDomSerializationProvider()); } documentObject = manager.CreateInstance(type, null, docType.Name, true); // Now that we have the document type, we create a nametable and fill it with member declarations. // During this time we also search for our initialization method and save it off for later // processing. // nameTable = new HybridDictionary(docType.Members.Count, caseInsensitive); statementTable = new HybridDictionary(docType.Members.Count, caseInsensitive); initMethod = null; RootContext rootExp = new RootContext(new CodeThisReferenceExpression(), documentObject); manager.Context.Push(rootExp); try { foreach (CodeTypeMember member in docType.Members) { if (member is CodeMemberField) { if (string.Compare(member.Name, docType.Name, caseInsensitive, CultureInfo.InvariantCulture) != 0) { // always skip members with the same name as the type -- because that's the name // we use when we resolve "base" and "this" items... // nameTable[member.Name] = member; } // [....]: I added this because C# doesn't allow member names to match enclosing class names: // // public class Foo { // public int Foo; // } // // doesn't compile. So I wanted to stop users from getting into this state but VB allows this so this could // break some existing forms. Since the compiler does a pretty good job of catching this with a meaningful error // and we don't let you change the name of a member to match the class name (since both are sited components), // this happens somewhat automatically. // // // // //else { // // see if the type of the field is a component... // // // string typeName = ((CodeMemberField)member).Type.BaseType; // Type fieldType = manager.GetType(typeName); // if (fieldType != null && typeof(IComponent).IsAssignableFrom(fieldType)) { // throw new Exception(SR.GetString(SR.SerializerMemberNameSameAsTypeName, member.Name)); // // (from system.design.txt) SerializerMemberNameSameAsTypeName=Member name '{0}' cannot be the same as the enclosing type name. // } //} } else if (initMethod == null && member is CodeMemberMethod) { CodeMemberMethod method = (CodeMemberMethod)member; if ((string.Compare(method.Name, InitMethodName, caseInsensitive, CultureInfo.InvariantCulture) == 0) && method.Parameters.Count == 0) { initMethod = method; } } } Trace("Encountered {0} members to deserialize.", nameTable.Keys.Count); TraceWarningIf(initMethod == null, "Init method {0} wasn't found.", InitMethodName); // We have the members, and possibly the init method. Walk the init method looking for local variable declarations, // and add them to the pile too. // if (initMethod != null) { foreach (CodeStatement statement in initMethod.Statements) { CodeVariableDeclarationStatement local = statement as CodeVariableDeclarationStatement; if (local != null) { nameTable[local.Name] = statement; } } } // Check for the case of a reference that has the same variable name as our root // object. If we find such a reference, we pre-populate the name table with our // document object. We don't really have to populate, but it is very important // that we don't leave the original field in there. Otherwise, we will try to // load up the field, and since the class we're designing doesn't yet exist, this // will cause an error. // if (nameTable[docType.Name] != null) { nameTable[docType.Name] = documentObject; } // We fill a "statement table" for everything in our init method. This statement // table is a dictionary whose keys contain object names and whose values contain // a statement collection of all statements with a LHS resolving to an object // by that name. // if (initMethod != null) { FillStatementTable(initMethod, docType.Name); } // Interesting problem. The CodeDom parser may auto generate statements // that are associated with other methods. VB does this, for example, to // create statements automatically for Handles clauses. The problem with // this technique is that we will end up with statements that are related // to variables that live solely in user code and not in InitializeComponent. // We will attempt to construct instances of these objects with limited // success. To guard against this, we check to see if the manager // even supports this feature, and if it does, we must walk each // statement. // PropertyDescriptor supportGenerate = manager.Properties["SupportsStatementGeneration"]; if (supportGenerate != null && supportGenerate.PropertyType == typeof(bool) && ((bool)supportGenerate.GetValue(manager)) == true) { // Ok, we must do the more expensive work of validating the statements we get. // foreach (string name in nameTable.Keys) { OrderedCodeStatementCollection statements = (OrderedCodeStatementCollection)statementTable[name]; if (statements != null) { bool acceptStatement = false; foreach (CodeStatement statement in statements) { object genFlag = statement.UserData["GeneratedStatement"]; if (genFlag == null || !(genFlag is bool) || !((bool)genFlag)) { acceptStatement = true; break; } } if (!acceptStatement) { statementTable.Remove(name); } } } } // Design time properties must be resolved before runtime properties to make // sure that properties like "language" get established before we need to read // values out the resource bundle. // Trace("--------------------------------------------------------------------"); Trace(" Beginning deserialization of {0} (design time)", docType.Name); Trace("--------------------------------------------------------------------"); // Deserialize design time properties for the root component and any inherited component. // IContainer container = (IContainer)manager.GetService(typeof(IContainer)); if (container != null) { foreach (object comp in container.Components) { DeserializePropertiesFromResources(manager, comp, designTimeProperties); } } // make sure we have fully deserialized everything that is referenced in the statement table. // object[] keyValues = new object[statementTable.Values.Count]; statementTable.Values.CopyTo(keyValues, 0); // sort by the order so we deserialize in the same order the objects // were decleared in. // Array.Sort(keyValues, StatementOrderComparer.Default); foreach (OrderedCodeStatementCollection statements in keyValues) { string name = statements.Name; if (name != null && !name.Equals(docType.Name)) { DeserializeName(manager, name); } } // Now do the runtime part of the // we must do the document class itself. // Trace("--------------------------------------------------------------------"); Trace(" Beginning deserialization of {0} (run time)", docType.Name); Trace("--------------------------------------------------------------------"); CodeStatementCollection rootStatements = (CodeStatementCollection)statementTable[docType.Name]; if (rootStatements != null && rootStatements.Count > 0) { foreach (CodeStatement statement in rootStatements) { DeserializeStatement(manager, statement); } } } finally { manager.ResolveName -= onResolveName; initMethod = null; nameTable = null; statementTable = null; Debug.Assert(manager.Context.Current == rootExp, "Context stack corrupted"); manager.Context.Pop(); } } return documentObject; } ////// /// This takes the given name and deserializes it from our name table. Before blindly /// deserializing it checks the contents of the name table to see if the object already /// exists within it. We do this because deserializing one object may call back /// into us through OnResolveName and deserialize another. /// [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2102:CatchNonClsCompliantExceptionsInGeneralHandlers")] private object DeserializeName(IDesignerSerializationManager manager, string name) { string typeName = null; Type type = null; object value = nameTable[name]; using (TraceScope("RootCodeDomSerializer::DeserializeName")) { Trace("Name: {0}", name); // If the name we're looking for isn't in our dictionary, we return null. It is up to the caller // to decide if this is an error or not. // CodeMemberField field = null; TraceIf(!(value is CodeObject), "Name already deserialized. Type: {0}", (value == null ? "(null)" : value.GetType().Name)); CodeObject codeObject = value as CodeObject; if (codeObject != null) { // If we fail, don't return a CodeDom element to the caller! // value = null; // Clear out our nametable entry here -- A badly written serializer may cause a recursion here, and // we want to stop it. // nameTable[name] = null; // What kind of code object is this? // Trace("CodeDom type: {0}", codeObject.GetType().Name); if (codeObject is CodeVariableDeclarationStatement) { CodeVariableDeclarationStatement declaration = (CodeVariableDeclarationStatement)codeObject; typeName = GetTypeNameFromCodeTypeReference(manager, declaration.Type); } else if (codeObject is CodeMemberField) { field = (CodeMemberField)codeObject; typeName = GetTypeNameFromCodeTypeReference(manager, field.Type); } } else if (value != null) { return value; } else { IContainer container = (IContainer)manager.GetService(typeof(IContainer)); if (container != null) { Trace("Try to get the type name from the container: {0}", name); IComponent comp = container.Components[name]; if (comp != null) { typeName = comp.GetType().FullName; // we had to go to the host here, so there isn't a nametable entry here -- // push in the component here so we don't accidentally recurse when // we try to deserialize this object. // nameTable[name] = comp; } } } // Special case our container name to point to the designer host -- it is our container at design time. // if (name.Equals(ContainerName)) { IContainer container = (IContainer)manager.GetService(typeof(IContainer)); if (container != null) { Trace("Substituted serialization manager's container"); value = container; } } else if (typeName != null) { // Default case -- something that needs to be deserialized // type = manager.GetType(typeName); if (type == null) { TraceError("Type does not exist: {0}", typeName); manager.ReportError(new SerializationException(SR.GetString(SR.SerializerTypeNotFound, typeName))); } else { CodeStatementCollection statements = (CodeStatementCollection)statementTable[name]; if (statements != null && statements.Count > 0) { CodeDomSerializer serializer = (CodeDomSerializer)manager.GetSerializer(type, typeof(CodeDomSerializer)); if (serializer == null) { // We report this as an error. This indicates that there are code statements // in initialize component that we do not know how to load. // TraceError("Type referenced in init method has no serializer: {0}", type.Name); manager.ReportError(SR.GetString(SR.SerializerNoSerializerForComponent, type.FullName)); } else { Trace("--------------------------------------------------------------------"); Trace(" Beginning deserialization of {0}", name); Trace("--------------------------------------------------------------------"); try { value = serializer.Deserialize(manager, statements); // Search for a modifiers property, and set it. // if (value != null && field != null) { PropertyDescriptor prop = TypeDescriptor.GetProperties(value)["Modifiers"]; if (prop != null && prop.PropertyType == typeof(MemberAttributes)) { MemberAttributes modifiers = field.Attributes & MemberAttributes.AccessMask; prop.SetValue(value, modifiers); } } } catch (Exception ex) { manager.ReportError(ex); } } } } } nameTable[name] = value; } return value; } ////// /// This method enumerates all the statements in the given method. For those statements who /// have a LHS that points to a name in our nametable, we add the statement to a Statement /// Collection within the statementTable dictionary. This allows us to very quickly /// put to gether what statements are associated with what names. /// private void FillStatementTable(CodeMemberMethod method, string className) { using (TraceScope("RootCodeDomSerializer::FillStatementTable")) { // Look in the method body to try to find statements with a LHS that // points to a name in our nametable. // foreach (CodeStatement statement in method.Statements) { CodeExpression expression = null; if (statement is CodeAssignStatement) { Trace("Processing CodeAssignStatement"); expression = ((CodeAssignStatement)statement).Left; } else if (statement is CodeAttachEventStatement) { Trace("Processing CodeAttachEventStatement"); expression = ((CodeAttachEventStatement)statement).Event; } else if (statement is CodeRemoveEventStatement) { Trace("Processing CodeRemoveEventStatement"); expression = ((CodeRemoveEventStatement)statement).Event; } else if (statement is CodeExpressionStatement) { Trace("Processing CodeExpressionStatement"); expression = ((CodeExpressionStatement)statement).Expression; } else if (statement is CodeVariableDeclarationStatement) { // Local variables are different because their LHS contains no expression. // Trace("Processing CodeVariableDeclarationStatement"); CodeVariableDeclarationStatement localVar = (CodeVariableDeclarationStatement)statement; if (localVar.InitExpression != null && nameTable.Contains(localVar.Name)) { AddStatement(localVar.Name, localVar); } expression = null; } if (expression != null) { // Simplify the expression as much as we can, looking for our target // object in the process. If we find an expression that refers to our target // object, we're done and can move on to the next statement. // while (true) { if (expression is CodeCastExpression) { Trace("Simplifying CodeCastExpression"); expression = ((CodeCastExpression)expression).Expression; } else if (expression is CodeDelegateCreateExpression) { Trace("Simplifying CodeDelegateCreateExpression"); expression = ((CodeDelegateCreateExpression)expression).TargetObject; } else if (expression is CodeDelegateInvokeExpression) { Trace("Simplifying CodeDelegateInvokeExpression"); expression = ((CodeDelegateInvokeExpression)expression).TargetObject; } else if (expression is CodeDirectionExpression) { Trace("Simplifying CodeDirectionExpression"); expression = ((CodeDirectionExpression)expression).Expression; } else if (expression is CodeEventReferenceExpression) { Trace("Simplifying CodeEventReferenceExpression"); expression = ((CodeEventReferenceExpression)expression).TargetObject; } else if (expression is CodeMethodInvokeExpression) { Trace("Simplifying CodeMethodInvokeExpression"); expression = ((CodeMethodInvokeExpression)expression).Method; } else if (expression is CodeMethodReferenceExpression) { Trace("Simplifying CodeMethodReferenceExpression"); expression = ((CodeMethodReferenceExpression)expression).TargetObject; } else if (expression is CodeArrayIndexerExpression) { Trace("Simplifying CodeArrayIndexerExpression"); expression = ((CodeArrayIndexerExpression)expression).TargetObject; } else if (expression is CodeFieldReferenceExpression) { // For fields we need to check to see if the field name is equal to the target object. // If it is, then we have the expression we want. We can add the statement here // and then break out of our loop. // // Note: We cannot validate that this is a name in our nametable. The nametable // only contains names we have discovered through code parsing and will not include // data from any inherited objects. We accept the field now, and then fail later // if we try to resolve it to an object and we can't find it. // CodeFieldReferenceExpression field = (CodeFieldReferenceExpression)expression; if (field.TargetObject is CodeThisReferenceExpression) { AddStatement(field.FieldName, statement); break; } else { Trace("Simplifying CodeFieldReferenceExpression"); expression = field.TargetObject; } } else if (expression is CodePropertyReferenceExpression) { // For properties we need to check to see if the property name is equal to the target object. // If it is, then we have the expression we want. We can add the statement here // and then break out of our loop. // CodePropertyReferenceExpression property = (CodePropertyReferenceExpression)expression; if (property.TargetObject is CodeThisReferenceExpression && nameTable.Contains(property.PropertyName)) { AddStatement(property.PropertyName, statement); break; } else { Trace("Simplifying CodePropertyReferenceExpression"); expression = property.TargetObject; } } else if (expression is CodeVariableReferenceExpression) { // For variables we need to check to see if the variable name is equal to the target object. // If it is, then we have the expression we want. We can add the statement here // and then break out of our loop. // CodeVariableReferenceExpression variable = (CodeVariableReferenceExpression)expression; if (nameTable.Contains(variable.VariableName)) { AddStatement(variable.VariableName, statement); } else { TraceWarning("Variable {0} used before it was declared.", variable.VariableName); } break; } else if (expression is CodeThisReferenceExpression || expression is CodeBaseReferenceExpression) { // We cannot go any further than "this". So, we break out // of the loop. We file this statement under the root object. // AddStatement(className, statement); break; } else { // We cannot simplify this expression any further, so we stop looping. // break; } } } } } } ////// /// If this statement is a method invoke, this gets the name of the method. /// Otherwise, it returns null. /// private string GetMethodName(object statement) { string name = null; while(name == null) { if (statement is CodeExpressionStatement) { statement = ((CodeExpressionStatement)statement).Expression; } else if (statement is CodeMethodInvokeExpression) { statement = ((CodeMethodInvokeExpression)statement).Method; } else if (statement is CodeMethodReferenceExpression) { return ((CodeMethodReferenceExpression)statement).MethodName; } else { break; } } return name; } ////// /// Called by the serialization manager to resolve a name to an object. /// private void OnResolveName(object sender, ResolveNameEventArgs e) { Debug.Assert(nameTable != null, "OnResolveName called and we are not deserializing!"); using(TraceScope("RootCodeDomSerializer::OnResolveName")) { Trace("Name: {0}", e.Name); // If someone else already found a value, who are we to complain? // if (e.Value != null) { TraceWarning("Another name resolver has already found the value for {0}.", e.Name); } else { IDesignerSerializationManager manager = (IDesignerSerializationManager)sender; object value = DeserializeName(manager, e.Name); e.Value = value; } } } #if DEBUG static int NextSerializeSessionId = 0; #endif ////// /// Serializes the given object into a CodeDom object. /// public override object Serialize(IDesignerSerializationManager manager, object value) { if (manager == null || value == null) { throw new ArgumentNullException( manager == null ? "manager" : "value"); } // As the root serializer, we are responsible for creating the code class for our // object. We will create the class, and the init method, and then push both // on the context stack. // These will be used by other serializers to insert statements and members. // CodeTypeDeclaration docType = new CodeTypeDeclaration(manager.GetName(value)); RootContext rootExp = new RootContext(new CodeThisReferenceExpression(), value); using (TraceScope("RootCodeDomSerializer::Serialize")) { #if DEBUG int serializeSessionId = ++NextSerializeSessionId; Trace("Serializer id={0}", serializeSessionId); #endif Trace("Value: {0}", value); docType.BaseTypes.Add(value.GetType()); containerRequired = false; manager.Context.Push(rootExp); manager.Context.Push(this); manager.Context.Push(docType); // HACK for backwards compatibility. if (!(manager is DesignerSerializationManager)) { manager.AddSerializationProvider(new CodeDomSerializationProvider()); } try { TraceWarningIf(!(value is IComponent), "Object {0} is not an IComponent but the root serializer is attempting to serialize it.", value); if (value is IComponent) { ISite site = ((IComponent)value).Site; TraceWarningIf(site == null, "Object {0} is not sited but the root serializer is attempting to serialize it.", value); if (site != null) { // Do each component, skipping us, since we handle our own serialization. // ICollection components = site.Container.Components; StatementContext cxt = new StatementContext(); cxt.StatementCollection.Populate(components); manager.Context.Push(cxt); try { // This looks really sweet, but is it worth it? We take the // perf hit of a quicksort + the allocation overhead of 4 // bytes for each component. Profiles show this as a 2% // cost for a form with 100 controls. Let's meet the perf // goals first, then consider uncommenting this. // //ArrayList sortedComponents = new ArrayList(components); //sortedComponents.Sort(ComponentComparer.Default); //components = sortedComponents; foreach(IComponent component in components) { if (component != value && !IsSerialized(manager, component)) { Trace("--------------------------------------------------------------------"); Trace(" Beginning serialization of {0}", component.Site.Name); Trace("--------------------------------------------------------------------"); CodeDomSerializer ser = GetSerializer(manager, component); if (ser != null) { SerializeToExpression(manager, component); } else { TraceError("Component has no serializer: {0}", component.GetType().Name); manager.ReportError(SR.GetString(SR.SerializerNoSerializerForComponent, component.GetType().FullName)); } } } // Push the component being serialized onto the stack. It may be handy to // be able to discover this. // manager.Context.Push(value); try { Trace("--------------------------------------------------------------------"); Trace(" Beginning serialization of root component {0}", manager.GetName(value)); Trace("--------------------------------------------------------------------"); CodeDomSerializer rootSer = GetSerializer(manager, value); if (rootSer != null && !IsSerialized(manager, value)) { SerializeToExpression(manager, value); } else { TraceError("Component has no serializer: {0}", value.GetType().Name); manager.ReportError(SR.GetString(SR.SerializerNoSerializerForComponent, value.GetType().FullName)); } } finally { Debug.Assert(manager.Context.Current == value, "Context stack corrupted"); manager.Context.Pop(); } } finally { Debug.Assert(manager.Context.Current == cxt, "Context stack corrupted"); manager.Context.Pop(); } CodeMemberMethod method = new CodeMemberMethod(); method.Name = InitMethodName; method.Attributes = MemberAttributes.Private; docType.Members.Add(method); // We write the code into the method in the following order: // // components = new Container() assignment // individual component assignments // root object design time proeprties // individual component properties / events // root object properties / events // ArrayList codeElements = new ArrayList(); foreach(object o in components) { if (o != value) { codeElements.Add(cxt.StatementCollection[o]); } } CodeStatementCollection sroot = cxt.StatementCollection[value]; if (sroot != null) { codeElements.Add(cxt.StatementCollection[value]); } Trace("Assembling init method from {0} statements", codeElements.Count); if (ContainerRequired) { SerializeContainerDeclaration(manager, method.Statements); } SerializeElementsToStatements(codeElements, method.Statements); } } } finally { Debug.Assert(manager.Context.Current == docType, "Somebody messed up our context stack"); manager.Context.Pop(); manager.Context.Pop(); manager.Context.Pop(); } Trace("--------------------------------------------------------------------"); Trace(" Generated code for {0}", manager.GetName(value)); Trace("--------------------------------------------------------------------"); Trace(docType); #if DEBUG Trace("end serialize id={0}", serializeSessionId); #endif } return docType; } ////// /// This ensures that the declaration for IContainer exists in the class, and that /// the init method creates an instance of Conatiner. /// private void SerializeContainerDeclaration(IDesignerSerializationManager manager, CodeStatementCollection statements) { // Get some services we need up front. // CodeTypeDeclaration docType = (CodeTypeDeclaration)manager.Context[typeof(CodeTypeDeclaration)]; if (docType == null) { Debug.Fail("Missing CodeDom objects in context."); return; } Trace("RootCodeDomSerializer::SerializeContainerDeclaration"); // Add the definition for IContainer to the class. // Type containerType = typeof(IContainer); CodeTypeReference containerTypeRef = new CodeTypeReference(containerType); CodeMemberField componentsDeclaration = new CodeMemberField(containerTypeRef, ContainerName); componentsDeclaration.Attributes = MemberAttributes.Private; docType.Members.Add(componentsDeclaration); // Next, add the instance creation to the init method. We change containerType // here from IContainer to Container. // containerType = typeof(Container); containerTypeRef = new CodeTypeReference(containerType); CodeObjectCreateExpression objectCreate = new CodeObjectCreateExpression(); objectCreate.CreateType = containerTypeRef; CodeFieldReferenceExpression fieldRef = new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), ContainerName); CodeAssignStatement assignment = new CodeAssignStatement(fieldRef, objectCreate); statements.Add(assignment); } ////// /// Takes the given list of elements and serializes them into the statement /// collection. This performs a simple sorting algorithm as well, putting /// local variables at the top, assignments next, and statements last. /// private void SerializeElementsToStatements(ArrayList elements, CodeStatementCollection statements) { ArrayList beginInitStatements = new ArrayList(); ArrayList endInitStatements = new ArrayList(); ArrayList localVariables = new ArrayList(); ArrayList fieldAssignments = new ArrayList(); ArrayList codeStatements = new ArrayList(); foreach(object element in elements) { Trace("ElementStatement: {0}", element.GetType().FullName); if (element is CodeAssignStatement && ((CodeAssignStatement)element).Left is CodeFieldReferenceExpression) { fieldAssignments.Add(element); } else if (element is CodeVariableDeclarationStatement) { localVariables.Add(element); } else if (element is CodeStatement) { string order = ((CodeObject)element).UserData["statement-ordering"] as string; if (order != null) { switch (order) { case "begin": beginInitStatements.Add(element); break; case "end": endInitStatements.Add(element); break; case "default": default: codeStatements.Add(element); break; } } else { codeStatements.Add(element); } } else if (element is CodeStatementCollection) { CodeStatementCollection childStatements = (CodeStatementCollection)element; foreach(CodeStatement statement in childStatements) { if (statement is CodeAssignStatement && ((CodeAssignStatement)statement).Left is CodeFieldReferenceExpression) { fieldAssignments.Add(statement); } else if (statement is CodeVariableDeclarationStatement) { localVariables.Add(statement); } else { string order = statement.UserData["statement-ordering"] as string; if (order != null) { switch (order) { case "begin": beginInitStatements.Add(statement); break; case "end": endInitStatements.Add(statement); break; case "default": default: codeStatements.Add(statement); break; } } else { codeStatements.Add(statement); } } } } } // Now that we have our lists, we can actually add them in the // proper order to the statement collection. // statements.AddRange((CodeStatement[])localVariables.ToArray(typeof(CodeStatement))); statements.AddRange((CodeStatement[])fieldAssignments.ToArray(typeof(CodeStatement))); statements.AddRange((CodeStatement[])beginInitStatements.ToArray(typeof(CodeStatement))); statements.AddRange((CodeStatement[])codeStatements.ToArray(typeof(CodeStatement))); statements.AddRange((CodeStatement[])endInitStatements.ToArray(typeof(CodeStatement))); } ////// /// Serializes the root object of the object graph. /// private CodeStatementCollection SerializeRootObject(IDesignerSerializationManager manager, object value, bool designTime) { // Get some services we need up front. // CodeTypeDeclaration docType = (CodeTypeDeclaration)manager.Context[typeof(CodeTypeDeclaration)]; if (docType == null) { Debug.Fail("Missing CodeDom objects in context."); return null; } CodeStatementCollection statements = new CodeStatementCollection(); using (TraceScope("RootCodeDomSerializer::SerializeRootObject")) { Trace("Design time values: {0}", designTime.ToString()); if (designTime) { SerializeProperties(manager, statements, value, designTimeProperties); } else { SerializeProperties(manager, statements, value, runTimeProperties); SerializeEvents(manager, statements, value, null); } } return statements; } private class StatementOrderComparer : IComparer { public static readonly StatementOrderComparer Default = new StatementOrderComparer(); private StatementOrderComparer() { } public int Compare(object left, object right) { OrderedCodeStatementCollection cscLeft = left as OrderedCodeStatementCollection; OrderedCodeStatementCollection cscRight = right as OrderedCodeStatementCollection; if (left == null) { return 1; } else if (right == null) { return -1; } else if (right == left) { return 0; } return cscLeft.Order - cscRight.Order; } } private class ComponentComparer : IComparer { public static readonly ComponentComparer Default = new ComponentComparer(); private ComponentComparer() { } public int Compare(object left, object right) { int n = string.Compare(((IComponent)left).GetType().Name, ((IComponent)right).GetType().Name, false, CultureInfo.InvariantCulture); if (n == 0) { n = string.Compare(((IComponent)left).Site.Name, ((IComponent)right).Site.Name, true, CultureInfo.InvariantCulture); } return n; } } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- MenuItem.cs
- StandardToolWindows.cs
- IIS7WorkerRequest.cs
- WebPartCloseVerb.cs
- CommandBindingCollection.cs
- ExtentKey.cs
- RsaSecurityKey.cs
- FlagsAttribute.cs
- XmlWriter.cs
- DataGrid.cs
- HttpModulesSection.cs
- ClonableStack.cs
- CounterSet.cs
- DTCTransactionManager.cs
- Margins.cs
- Proxy.cs
- XmlSchemas.cs
- TriggerActionCollection.cs
- DrawingState.cs
- SoapExtension.cs
- DataTableNewRowEvent.cs
- Control.cs
- XmlQualifiedName.cs
- AccessedThroughPropertyAttribute.cs
- NumberFormatInfo.cs
- FlowPosition.cs
- AnnotationAuthorChangedEventArgs.cs
- FileVersionInfo.cs
- PointCollectionValueSerializer.cs
- ValidationErrorEventArgs.cs
- SafeArrayTypeMismatchException.cs
- Select.cs
- DrawingGroup.cs
- XPathSingletonIterator.cs
- GridViewRowCollection.cs
- CodeDOMUtility.cs
- ResponseStream.cs
- SqlDataReader.cs
- Oci.cs
- WebConfigurationHostFileChange.cs
- PenLineCapValidation.cs
- DataListItemCollection.cs
- TemplateBindingExtension.cs
- HttpCookieCollection.cs
- OperationInfo.cs
- ResXResourceWriter.cs
- SetState.cs
- Composition.cs
- TaskHelper.cs
- SelectionEditor.cs
- TemplateInstanceAttribute.cs
- StringComparer.cs
- AttributeCollection.cs
- GraphicsPathIterator.cs
- MappedMetaModel.cs
- __ComObject.cs
- Interlocked.cs
- XmlSchemaAppInfo.cs
- xsdvalidator.cs
- XmlSchemaComplexContentRestriction.cs
- PingOptions.cs
- DesignerOptionService.cs
- SymmetricAlgorithm.cs
- AddingNewEventArgs.cs
- WebBrowserSiteBase.cs
- DesignerVerbToolStripMenuItem.cs
- Baml2006KeyRecord.cs
- SQLDouble.cs
- AttachedAnnotation.cs
- localization.cs
- StorageSetMapping.cs
- XamlBrushSerializer.cs
- AssemblyCollection.cs
- OpenFileDialog.cs
- DragCompletedEventArgs.cs
- AutomationInteropProvider.cs
- FaultHandlingFilter.cs
- DetailsViewPagerRow.cs
- HyperlinkAutomationPeer.cs
- ValueTable.cs
- PipeStream.cs
- ConnectionModeReader.cs
- DecimalAnimationBase.cs
- ProxyAssemblyNotLoadedException.cs
- InstancePersistenceException.cs
- TextElementEnumerator.cs
- NativeMethods.cs
- PhysicalAddress.cs
- SectionInformation.cs
- DataObject.cs
- SynchronizingStream.cs
- RelationshipConverter.cs
- RelationshipEndMember.cs
- XmlSequenceWriter.cs
- ReplyChannelBinder.cs
- SqlDataSourceView.cs
- Icon.cs
- ColorTranslator.cs
- FilterQuery.cs
- SqlDataSourceParameterParser.cs