Code:
/ DotNET / DotNET / 8.0 / untmp / whidbey / REDBITS / ndp / fx / src / Designer / CompMod / System / ComponentModel / Design / Serialization / TypeCodeDomSerializer.cs / 1 / TypeCodeDomSerializer.cs
//------------------------------------------------------------------------------ //// Copyright (c) Microsoft Corporation. All rights reserved. // //----------------------------------------------------------------------------- namespace System.ComponentModel.Design.Serialization { using System; using System.CodeDom; using System.CodeDom.Compiler; using System.Collections; using System.Collections.Generic; using System.Collections.Specialized; using System.Design; using System.Diagnostics; ////// /// This class performs the same tasks as a CodeDomSerializer only serializing an object through this class defines a new type. /// [DefaultSerializationProvider(typeof(CodeDomSerializationProvider))] public class TypeCodeDomSerializer : CodeDomSerializerBase { // Used only during deserialization to provide name to object mapping. private IDictionary _nameTable; private Dictionary_statementTable; private static readonly Attribute[] _designTimeFilter = new Attribute[] { DesignOnlyAttribute.Yes }; private static readonly Attribute[] _runTimeFilter = new Attribute[] { DesignOnlyAttribute.No }; private static object _initMethodKey = new object(); private static TypeCodeDomSerializer _default; internal static TypeCodeDomSerializer Default { get { if (_default == null) { _default = new TypeCodeDomSerializer(); } return _default; } } /// /// /// This method deserializes a previously serialized code type declaration. The default /// implementation performs the following tasks: /// /// � Case Sensitivity Checks: It looks for a CodeDomProvider service to decide if it should treat /// members as case sensitive or case insensitive. /// � Statement Sorting: All member variables and local variables from init methods are stored in /// a table. Then each statement in an init method is added to a statement collection grouped according /// to its left hand side. So all statements assigning or operating on a particular variable are grouped /// under that variable. Variables that have no statements are discarded. /// � Deserialization: Finally, the statement collections for each variable are deserialized /// according to the variable. /// /// Deserialize returns an instance of the root object. /// public virtual object Deserialize(IDesignerSerializationManager manager, CodeTypeDeclaration declaration) { if (manager == null) { throw new ArgumentNullException("manager"); } if (declaration == null) { throw new ArgumentNullException("declaration"); } object rootObject = null; using (TraceScope("TypeCodeDomSerializer::Deserialize")) { // Determine case-sensitivity bool caseInsensitive = false; CodeDomProvider provider = manager.GetService(typeof(CodeDomProvider)) as CodeDomProvider; TraceWarningIf(provider == null, "Unable to determine case sensitivity. Make sure CodeDomProvider is a service of the manager."); if (provider != null) { caseInsensitive = ((provider.LanguageOptions & LanguageOptions.CaseInsensitive) != 0); } // Get and initialize the document type. Type baseType = null; string baseTypeName = declaration.Name; foreach (CodeTypeReference typeRef in declaration.BaseTypes) { Type t = manager.GetType(GetTypeNameFromCodeTypeReference(manager, typeRef)); baseTypeName = typeRef.BaseType; if (t != null && !(t.IsInterface)) { baseType = t; break; } } if (baseType == null) { TraceError("Base type for type declaration {0} could not be loaded. Closest base type name: {1}", declaration.Name, baseTypeName); Error(manager, SR.GetString(SR.SerializerTypeNotFound, baseTypeName), SR.SerializerTypeNotFound); } if (TypeDescriptor.GetReflectionType(baseType).IsAbstract) { TraceError("Base type {0} is abstract, which isn't allowed", baseType.FullName); Error(manager, SR.GetString(SR.SerializerTypeAbstract, baseType.FullName), SR.SerializerTypeAbstract); } ResolveNameEventHandler onResolveName = new ResolveNameEventHandler(OnResolveName); manager.ResolveName += onResolveName; rootObject = manager.CreateInstance(baseType, null, declaration.Name, true); // Now that we have the root object, we create a nametable and fill it with member declarations. _nameTable = new HybridDictionary(declaration.Members.Count, caseInsensitive); _statementTable = new Dictionary(declaration.Members.Count); Dictionary names = new Dictionary (); RootContext rootCxt = new RootContext(new CodeThisReferenceExpression(), rootObject); manager.Context.Push(rootCxt); try { StringComparison compare = caseInsensitive ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal; foreach (CodeTypeMember typeMember in declaration.Members) { CodeMemberField member = typeMember as CodeMemberField; if (member != null) { if (!string.Equals(member.Name, declaration.Name, compare)) { // 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; if (member.Type != null && !string.IsNullOrEmpty(member.Type.BaseType)) { names[member.Name] = GetTypeNameFromCodeTypeReference(manager, member.Type); } } } } CodeMemberMethod[] methods = GetInitializeMethods(manager, declaration); if (methods == null) { throw new InvalidOperationException(); } Trace("Members to deserialize: {0}", _nameTable.Keys.Count); Trace("Methods to deserialize: {0}", methods.Length); TraceWarningIf(methods.Length == 0, "Serializer did not find any methods to deserialize."); // Walk through all of our methods and search for local variables. These guys get added to our // nametable too. foreach(CodeMemberMethod method in methods) { foreach (CodeStatement statement in method.Statements) { CodeVariableDeclarationStatement local = statement as CodeVariableDeclarationStatement; if (local != null) { _nameTable[local.Name] = statement; } } } // The name table should come pre-populated with our root expression. _nameTable[declaration.Name] = rootCxt.Expression; // We fill a "statement table" for everything in our init methods. 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 supportGenerate is true, FillStatementTable will skip methods // that are marked with the tag "GeneratedStatement". foreach (CodeMemberMethod method in methods) { FillStatementTable(manager, _statementTable, names, method.Statements, declaration.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 look out for // these statements while filling the statement collections. 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) { if (_statementTable.ContainsKey(name)) { CodeStatementCollection statements = _statementTable[name]; 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)", declaration.Name); Trace("--------------------------------------------------------------------"); // Deserialize design time properties for the root component. DeserializePropertiesFromResources(manager, rootObject, _designTimeFilter); // sort by the order so we deserialize in the same order the objects // were decleared in. OrderedCodeStatementCollection[] statementArray = new OrderedCodeStatementCollection[_statementTable.Count]; _statementTable.Values.CopyTo(statementArray, 0); Array.Sort(statementArray, StatementOrderComparer.Default); // make sure we have fully deserialized everything that is referenced in the statement table. // Skip the root object for last OrderedCodeStatementCollection rootStatements = null; foreach (OrderedCodeStatementCollection statements in statementArray) { if (statements.Name.Equals(declaration.Name)) { rootStatements = statements; } else { DeserializeName(manager, statements.Name, statements); } } if (rootStatements != null) { DeserializeName(manager, rootStatements.Name, rootStatements); } } finally { _nameTable = null; _statementTable = null; Debug.Assert(manager.Context.Current == rootCxt, "Context stack corrupted"); manager.ResolveName -= onResolveName; manager.Context.Pop(); } } return rootObject; } /// /// 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, CodeStatementCollection statements) { object value = null; using (TraceScope("RootCodeDomSerializer::DeserializeName")) { // 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. // value = _nameTable[name]; CodeObject codeObject = value as CodeObject; string typeName = null; CodeMemberField field = null; TraceIf(codeObject == null, "Name already deserialized. Type: {0}", (value == null ? "(null)" : value.GetType().Name)); if (codeObject != null) { // If we fail, don't return a CodeDom element to the caller! Also // clear out our nametable entry here -- A badly written serializer may cause a recursion here, and // we want to stop it. // value = null; _nameTable[name] = null; // What kind of code object is this? // Trace("CodeDom type: {0}", codeObject.GetType().Name); CodeVariableDeclarationStatement declaration = codeObject as CodeVariableDeclarationStatement; if (declaration != null) { typeName = GetTypeNameFromCodeTypeReference(manager, declaration.Type); } else { field = codeObject as CodeMemberField; if (field != null) { typeName = GetTypeNameFromCodeTypeReference(manager, field.Type); } else { CodeExpression exp = codeObject as CodeExpression; RootContext rootCxt = manager.Context[typeof(RootContext)] as RootContext; if (rootCxt != null && exp != null && rootCxt.Expression == exp) { value = rootCxt.Value; typeName = TypeDescriptor.GetClassName(value); } else { Debug.Fail("Unrecognized code object in nametable."); } } } } else if (value == null) { // See if the container has this object. This may be necessary for // visual inheritance. 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; } } } if (typeName != null) { // Default case -- something that needs to be deserialized // Type type = manager.GetType(typeName); if (type == null) { TraceError("Type does not exist: {0}", typeName); manager.ReportError(new CodeDomSerializerException(SR.GetString(SR.SerializerTypeNotFound, typeName), manager)); } else { if (statements == null && _statementTable.ContainsKey(name)) { statements = _statementTable[name]; } if (statements != null && statements.Count > 0) { CodeDomSerializer serializer = GetSerializer(manager, type); 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(new CodeDomSerializerException(SR.GetString(SR.SerializerNoSerializerForComponent, type.FullName), manager)); } 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); } } _nameTable[name] = value; } catch (Exception ex) { manager.ReportError(ex); } } } } } } return value; } ////// /// This method returns the method to emit all of the initialization code to for the given member. /// The default implementation returns an empty constructor. /// protected virtual CodeMemberMethod GetInitializeMethod(IDesignerSerializationManager manager, CodeTypeDeclaration declaration, object value) { if (manager == null) { throw new ArgumentNullException("manager"); } if (declaration == null) { throw new ArgumentNullException("declaration"); } if (value == null) { throw new ArgumentNullException("value"); } CodeConstructor ctor = declaration.UserData[_initMethodKey] as CodeConstructor; if (ctor == null) { ctor = new CodeConstructor(); declaration.UserData[_initMethodKey] = ctor; } return ctor; } ////// /// This method returns an array of methods that need to be interpreted during deserialization. /// The default implementation returns a single element array with the constructor in it. /// protected virtual CodeMemberMethod[] GetInitializeMethods(IDesignerSerializationManager manager, CodeTypeDeclaration declaration) { if (manager == null) { throw new ArgumentNullException("manager"); } if (declaration == null) { throw new ArgumentNullException("declaration"); } foreach (CodeTypeMember member in declaration.Members) { CodeConstructor ctor = member as CodeConstructor; if (ctor != null && ctor.Parameters.Count == 0) { return new CodeMemberMethod[] { ctor }; } } return new CodeMemberMethod[0]; } ////// 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; e.Value = DeserializeName(manager, e.Name, null); } } } ////// /// This method serializes the given root object and optional collection of members to create a /// new type definition. The members collection can be null or empty. If it contains values, /// these values will be serialized. Values themselves may decide to serialize as either member /// variables or local variables. This determination is done by looking for an extender property /// on the object called GenerateMember. If true, a member is generated. Otherwise, a local /// variable is generated. For convenience, the members collection can contain the root object. /// In this case the root object will not also be added as a member or local variable. The return /// value is a CodeTypeDeclaration that defines the root object. The name of the type will be taken /// from the root object�s name, if it was a named object. If not, a name will be fabricated from the /// simple type name of the root class. /// /// The default implementation of Serialize performs the following tasks: /// /// � Context Seeding. The serialization context will be �seeded� with data including the RootContext, /// and CodeTypeDeclaration. /// � Member Serialization. Next Serialize will walk all of the members and call SerializeToExpression. /// Because serialization is done opportunistically in SerializeToExpression, this ensures that we do /// not serialize twice. /// � Root Seralization. Finally, the root object is serialized and its statements are added to the statement /// collection. /// � Statement Integration. After all objects have been serialized the Serialize method orders the statements /// and adds them to a method returned from GetInitializeMethod. Finally, a constructor is fabricated that calls /// all of the methods returned from GetInitializeMethod (this step is skipped for cases when GetInitializeMethod /// returns a constructor. /// public virtual CodeTypeDeclaration Serialize(IDesignerSerializationManager manager, object root, ICollection members) { if (manager == null) { throw new ArgumentNullException("manager"); } if (root == null) { throw new ArgumentNullException("root"); } Trace("TypeCodeDomSerializer::Serialize"); // As a type serializer we are responsible for creating the type declaration. Other // serializers may access this type declaration and add members to it, so we need // to place it on the context stack. The serialization process also looks at the // root context to see if there is a root component. The root context is also used // by the serializers to add statement collections for serialized components. CodeTypeDeclaration docType = new CodeTypeDeclaration(manager.GetName(root)); CodeThisReferenceExpression thisRef = new CodeThisReferenceExpression(); RootContext rootCxt = new RootContext(thisRef, root); StatementContext statementCxt = new StatementContext(); // Populate the statement context with a list of members we'd like to see // statements for statementCxt.StatementCollection.Populate(root); if (members != null) { statementCxt.StatementCollection.Populate(members); } docType.BaseTypes.Add(root.GetType()); manager.Context.Push(docType); manager.Context.Push(rootCxt); manager.Context.Push(statementCxt); try { // Do each component, skipping us, since we handle our own serialization. // 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; if (members != null) { foreach (object member in members) { if (member != root) { #if DEBUG string memberName = manager.GetName(member); if (memberName == null) memberName = member.ToString(); Trace("--------------------------------------------------------------------"); Trace(" Beginning serialization of {0}", memberName); Trace("--------------------------------------------------------------------"); #endif // This returns an expression for the object, if possible. We ignore that. Besides returning // an expression, it fills the statement table in the statement context and we're very interested // in that. After serializing everything we will walk over the statement context's statement table. // We will validate that each and every member we've serialized has a presence in the // statement table. If it doesn't, that's an error in the member's serializer. SerializeToExpression(manager, member); } } } // Now do the root object last. #if DEBUG string rootName = manager.GetName(root); if (rootName == null) rootName = root.ToString(); Trace("--------------------------------------------------------------------"); Trace(" Bedginning serialization of root object {0}", rootName); Trace("--------------------------------------------------------------------"); #endif // Now, do the root object last. SerializeToExpression(manager, root); // After serializing everything we will walk over the statement context's statement table. // We will validate that each and every member we've serialized has a presence in the // statement table. If it doesn't, that's an error in the member's serializer. IntegrateStatements(manager, root, members, statementCxt, docType); } finally { Debug.Assert(manager.Context.Current == statementCxt, "Somebody messed up our context stack"); manager.Context.Pop(); manager.Context.Pop(); manager.Context.Pop(); } Trace("--------------------------------------------------------------------"); Trace(" Generated code for ", manager.GetName(root)); Trace("--------------------------------------------------------------------"); Trace(docType); return docType; } ////// Takes the statement context and integrates all the statements into the correct methods. Then, those methods are added to the code type declaration. /// private void IntegrateStatements(IDesignerSerializationManager manager, object root, ICollection members, StatementContext statementCxt, CodeTypeDeclaration typeDecl) { DictionarymethodMapIndex = new Dictionary (); List methodMap = new List (); // Go through all of our members and root object and fish out matching statement context // info for each object. The statement context will probably contain more objects than // our members, because each object that returned a statement collection was placed in the // context. That's fine, because for each major component we serialized it pushed its // statement collection on the context stack and statements were added there as well, forming // a comlete graph. if (members != null) { foreach(object member in members) { if (member != root) { // always skip the root and do it last CodeStatementCollection statements = statementCxt.StatementCollection[member]; if (statements != null) { CodeMemberMethod method = GetInitializeMethod(manager, typeDecl, member); if (method == null) { throw new InvalidOperationException(); } CodeMethodMap map; int mapIndex; if (methodMapIndex.TryGetValue(method.Name, out mapIndex)) { map = methodMap[mapIndex]; } else { map = new CodeMethodMap(method); methodMap.Add(map); methodMapIndex[method.Name] = methodMap.Count - 1; } if (statements.Count > 0) { map.Add(statements); } } } } } // Finally, do the same thing for the root object. CodeStatementCollection rootStatements = statementCxt.StatementCollection[root]; if (rootStatements != null) { CodeMemberMethod rootMethod = GetInitializeMethod(manager, typeDecl, root); if (rootMethod == null) { throw new InvalidOperationException(); } CodeMethodMap rootMap; int rootMapIndex; if (methodMapIndex.TryGetValue(rootMethod.Name, out rootMapIndex)) { rootMap = methodMap[rootMapIndex]; } else { rootMap = new CodeMethodMap(rootMethod); methodMap.Add(rootMap); methodMapIndex[rootMethod.Name] = methodMap.Count - 1; } if (rootStatements.Count > 0) { rootMap.Add(rootStatements); } } // Final step -- walk through all of the sections and emit them to the type declaration. foreach (CodeMethodMap map in methodMap) { map.Combine(); typeDecl.Members.Add(map.Method); Trace("...generated {0} statements into method {1}", map.Method.Statements.Count, map.Method.Name); } } #region OrderedStatementsCollection Class 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; } } #endregion } } // 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
- BamlCollectionHolder.cs
- HtmlPageAdapter.cs
- counter.cs
- COSERVERINFO.cs
- WizardForm.cs
- ListBoxChrome.cs
- Array.cs
- XmlUnspecifiedAttribute.cs
- TypedTableBaseExtensions.cs
- FormViewActionList.cs
- WebScriptMetadataFormatter.cs
- Label.cs
- DependsOnAttribute.cs
- Encoding.cs
- BitArray.cs
- UIElementHelper.cs
- HitTestWithGeometryDrawingContextWalker.cs
- Rotation3DAnimationUsingKeyFrames.cs
- PropertyValueUIItem.cs
- CroppedBitmap.cs
- ConfigsHelper.cs
- SingleAnimationBase.cs
- Empty.cs
- PrimaryKeyTypeConverter.cs
- Vector3DCollection.cs
- GenericsInstances.cs
- AppDomainEvidenceFactory.cs
- VariableAction.cs
- RegexWorker.cs
- ProxyAttribute.cs
- ConfigErrorGlyph.cs
- SmiContextFactory.cs
- CookielessHelper.cs
- LineServicesCallbacks.cs
- AmbientValueAttribute.cs
- _LocalDataStoreMgr.cs
- WebPartVerbsEventArgs.cs
- DataGridViewLinkColumn.cs
- FileDialog.cs
- PasswordTextNavigator.cs
- Privilege.cs
- CanExecuteRoutedEventArgs.cs
- BaseHashHelper.cs
- RootBrowserWindowProxy.cs
- ObjectView.cs
- WinInet.cs
- ResourcesBuildProvider.cs
- XPathNodeInfoAtom.cs
- EntityDataSourceWizardForm.cs
- LogConverter.cs
- SqlFactory.cs
- ClientScriptManager.cs
- StreamInfo.cs
- FilterElement.cs
- HMACSHA512.cs
- ImmutableDispatchRuntime.cs
- DataGridViewCellStyleBuilderDialog.cs
- DesignerLoader.cs
- MarginsConverter.cs
- DocumentEventArgs.cs
- XmlExtensionFunction.cs
- EmbeddedObject.cs
- TextBoxRenderer.cs
- WebPartExportVerb.cs
- ListParaClient.cs
- TerminatorSinks.cs
- WindowPattern.cs
- MessageEnumerator.cs
- DataGridPagerStyle.cs
- FloaterParaClient.cs
- BaseResourcesBuildProvider.cs
- MarshalDirectiveException.cs
- MemberPathMap.cs
- AutomationPeer.cs
- IgnoreDeviceFilterElementCollection.cs
- ReadOnlyDataSource.cs
- ChannelParameterCollection.cs
- OrderByExpression.cs
- D3DImage.cs
- WebBrowserSiteBase.cs
- TransportReplyChannelAcceptor.cs
- UrlPropertyAttribute.cs
- EnumValidator.cs
- StyleSelector.cs
- CollaborationHelperFunctions.cs
- ComEventsMethod.cs
- DataServiceProcessingPipeline.cs
- DataGridViewCellConverter.cs
- ClientUtils.cs
- BamlWriter.cs
- HtmlImage.cs
- ProxyHelper.cs
- ConfigurationManagerInternalFactory.cs
- SqlBinder.cs
- TemplateEditingFrame.cs
- DrawingAttributesDefaultValueFactory.cs
- ObjectStateEntry.cs
- WebRequest.cs
- XmlDataSourceView.cs
- PersonalizationProviderCollection.cs