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