1 //------------------------------------------------------------------------------
2 // <copyright file="ContextStack.cs" company="Microsoft">
3 //     Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 //------------------------------------------------------------------------------
6 
7 namespace System.ComponentModel.Design.Serialization {
8 
9     using System;
10     using System.Collections;
11     using System.Security.Permissions;
12 
13     /// <devdoc>
14     ///     A context stack is an object that can be used by serializers
15     ///     to push various context objects.  Serialization is often
16     ///     a deeply nested operation, involving many different
17     ///     serialization classes.  These classes often need additional
18     ///     context information when performing serialization.  As
19     ///     an example, an object with a property named "Enabled" may have
20     ///     a data type of System.Boolean.  If a serializer is writing
21     ///     this value to a data stream it may want to know what property
22     ///     it is writing.  It won't have this information, however, because
23     ///     it is only instructed to write the boolean value.  In this
24     ///     case the parent serializer may push a PropertyDescriptor
25     ///     pointing to the "Enabled" property on the context stack.
26     ///     What objects get pushed on this stack are up to the
27     ///     individual serializer objects.
28     /// </devdoc>
29     [HostProtection(SharedState = true)]
30     [System.Security.Permissions.PermissionSetAttribute(System.Security.Permissions.SecurityAction.LinkDemand, Name = "FullTrust")]
31     public sealed class ContextStack {
32         private ArrayList contextStack;
33 
34         /// <devdoc>
35         ///     Retrieves the current object on the stack, or null
36         ///     if no objects have been pushed.
37         /// </devdoc>
38         public object Current {
39             get {
40                 if (contextStack != null && contextStack.Count > 0) {
41                     return contextStack[contextStack.Count - 1];
42                 }
43                 return null;
44             }
45         }
46 
47         /// <devdoc>
48         ///     Retrieves the object on the stack at the given
49         ///     level, or null if no object exists at that level.
50         /// </devdoc>
51         public object this[int level] {
52             get {
53                 if (level < 0) {
54                     throw new ArgumentOutOfRangeException("level");
55                 }
56                 if (contextStack != null && level < contextStack.Count) {
57                     return contextStack[contextStack.Count - 1 - level];
58                 }
59                 return null;
60             }
61         }
62 
63         /// <devdoc>
64         ///     Retrieves the first object on the stack that
65         ///     inherits from or implements the given type, or
66         ///     null if no object on the stack implements the type.
67         /// </devdoc>
68         public object this[Type type] {
69             get {
70                 if (type == null) {
71                     throw new ArgumentNullException("type");
72                 }
73 
74                 if (contextStack != null) {
75                     int level = contextStack.Count;
76                     while(level > 0) {
77                         object value = contextStack[--level];
78                         if (type.IsInstanceOfType(value)) {
79                             return value;
80                         }
81                     }
82                 }
83 
84                 return null;
85             }
86         }
87 
88         /// <devdoc>
89         ///     Appends an object to the end of the stack, rather than pushing it
90         ///     onto the top of the stack.  This method allows a serializer to communicate
91         ///     with other serializers by adding contextual data that does not have to
92         ///     be popped in order.  There is no way to remove an object that was
93         ///     appended to the end of the stack without popping all other objects.
94         /// </devdoc>
Append(object context)95         public void Append(object context) {
96             if (context == null) {
97                 throw new ArgumentNullException("context");
98             }
99 
100             if (contextStack == null) {
101                 contextStack = new ArrayList();
102             }
103             contextStack.Insert(0, context);
104         }
105 
106         /// <devdoc>
107         ///     Pops the current object off of the stack, returning
108         ///     its value.
109         /// </devdoc>
Pop()110         public object Pop() {
111             object context = null;
112 
113             if (contextStack != null && contextStack.Count > 0) {
114                 int idx = contextStack.Count - 1;
115                 context = contextStack[idx];
116                 contextStack.RemoveAt(idx);
117             }
118 
119             return context;
120         }
121 
122         /// <devdoc>
123         ///     Pushes the given object onto the stack.
124         /// </devdoc>
Push(object context)125         public void Push(object context) {
126             if (context == null) {
127                 throw new ArgumentNullException("context");
128             }
129 
130             if (contextStack == null) {
131                 contextStack = new ArrayList();
132             }
133             contextStack.Add(context);
134         }
135     }
136 }
137 
138