1 //
2 // Copyright (c) ZeroC, Inc. All rights reserved.
3 //
4 
5 namespace Ice
6 {
7     using System;
8     using System.Collections.Generic;
9     using System.Runtime.Serialization;
10 
11     public struct NoneType
12     {
13     }
14 
15     /// <summary>
16     /// Encapsulates an optional value. Instances of this type are immutable.
17     /// </summary>
18     [Serializable]
19     public struct Optional<T> : ISerializable
20     {
21         /// <summary>
22         /// Creates an optional value whose state is unset.
23         /// </summary>
OptionalIce.Optional24         public Optional(NoneType none)
25         {
26             _value = default(T);
27             _isSet = false;
28         }
29 
30         /// <summary>
31         /// Creates an optional value and sets its value to the given argument.
32         /// </summary>
OptionalIce.Optional33         public Optional(T v)
34         {
35             _value = v;
36             _isSet = true;
37         }
38 
39         /// <summary>
40         /// Creates an optional value whose state is copied from the given argument.
41         /// </summary>
OptionalIce.Optional42         public Optional(Optional<T> v)
43         {
44             _value = v._value;
45             _isSet = v._isSet;
46         }
47 
48         /// <summary>
49         /// Initializes a new instance of the exception with serialized data.
50         /// </summary>
51         /// <param name="info">Holds the serialized object data about the exception being thrown.</param>
52         /// <param name="context">Contains contextual information about the source or destination.</param>
OptionalIce.Optional53         public Optional(SerializationInfo info, StreamingContext context)
54         {
55             _isSet = info.GetBoolean("isSet");
56             if(_isSet)
57             {
58                 _value = (T)info.GetValue("value", typeof(T));
59             }
60             else
61             {
62                 _value = default(T);
63             }
64         }
65 
66         /// <summary>
67         /// Conversion operator to the underlying type; a cast is required. An exception
68         /// is raised if no value is set.
69         /// </summary>
70         /// <returns>The encapsulated value.</returns>
71         /// <exception cref="System.InvalidOperationException">Thrown if no value is set.</exception>
operator TIce.Optional72         public static explicit operator T(Optional<T> v)
73         {
74             return v.Value;
75         }
76 
77         /// <summary>
78         /// Conversion operator from a value of the underlying type; no cast is required.
79         /// </summary>
operator Optional<T>Ice.Optional80         public static implicit operator Optional<T>(T v)
81         {
82             return new Optional<T>(v);
83         }
84 
85         /// <summary>
86         /// Conversion operator from a None value; no cast is required.
87         /// </summary>
operator Optional<T>Ice.Optional88         public static implicit operator Optional<T>(NoneType v)
89         {
90             return new Optional<T>();
91         }
92 
93         /// <summary>
94         /// Reads and writes the encapsulated value.
95         /// </summary>
96         /// <exception cref="System.InvalidOperationException">Thrown if the property is read and no value is
97         /// set.</exception>
98         public T Value
99         {
100             get
101             {
102                 if(!_isSet)
103                 {
104                     throw new InvalidOperationException();
105                 }
106                 return _value;
107             }
108         }
109 
110         /// <summary>
111         /// Determines whether a value is set.
112         /// </summary>
113         /// <returns>True if a value is set, false otherwise.</returns>
114         public bool HasValue
115         {
116             get
117             {
118                 return _isSet;
119             }
120         }
121 
EqualsIce.Optional122         public override bool Equals(object other)
123         {
124             if(ReferenceEquals(this, other))
125             {
126                 return true;
127             }
128             if(other == null)
129             {
130                 return false;
131             }
132 
133             try
134             {
135                 Optional<T> o2 = (Optional<T>)other;
136 
137                 if(_isSet != o2._isSet)
138                 {
139                     return false;
140                 }
141                 else if(_isSet)
142                 {
143                     EqualityComparer<T> comparer = EqualityComparer<T>.Default;
144                     return comparer.Equals(_value, o2._value);
145                 }
146 
147                 return true;
148             }
149             catch(System.Exception)
150             {
151                 return false;
152             }
153         }
154 
GetHashCodeIce.Optional155         public override int GetHashCode()
156         {
157             if(!_isSet)
158             {
159                 return base.GetHashCode();
160             }
161             else
162             {
163                 return _value.GetHashCode();
164             }
165         }
166 
167         /// <summary>
168         /// Serializes an optional value.
169         /// </summary>
170         /// <param name="info">Holds the serialized object data about the exception being thrown.</param>
171         /// <param name="context">Contains contextual information about the source or destination.</param>
GetObjectDataIce.Optional172         public void GetObjectData(SerializationInfo info, StreamingContext context)
173         {
174             info.AddValue("isSet", _isSet);
175             if(_isSet)
176             {
177                 info.AddValue("value", _value, typeof(T));
178             }
179         }
180 
181         private T _value;
182         private bool _isSet;
183     }
184 
185     /// <summary>
186     /// The optional format.
187     ///
188     /// An optional value is encoded with a specific optional format. This optional
189     /// format describes how the data is encoded and how it can be skipped by the
190     /// unmarshaling code if the optional is not known to the receiver.
191     /// </summary>
192     public enum OptionalFormat
193     {
194         F1 = 0,
195         F2 = 1,
196         F4 = 2,
197         F8 = 3,
198         Size = 4,
199         VSize = 5,
200         FSize = 6,
201         Class = 7
202     }
203 }
204