typo: Double word "a" (dotnet/corefx#36271)
[platform/upstream/coreclr.git] / src / System.Private.CoreLib / shared / System / Nullable.cs
1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4
5 using System.Collections.Generic;
6 using System.Runtime.Versioning;
7
8 namespace System
9 {
10     // Because we have special type system support that says a boxed Nullable<T>
11     // can be used where a boxed<T> is use, Nullable<T> can not implement any intefaces
12     // at all (since T may not).   Do NOT add any interfaces to Nullable!
13     //
14     [Serializable]
15     [NonVersionable] // This only applies to field layout
16     [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
17     public partial struct Nullable<T> where T : struct
18     {
19         private readonly bool hasValue; // Do not rename (binary serialization)
20         internal T value; // Do not rename (binary serialization) or make readonly (can be mutated in ToString, etc.)
21
22         [NonVersionable]
23         public Nullable(T value)
24         {
25             this.value = value;
26             hasValue = true;
27         }
28
29         public bool HasValue
30         {
31             [NonVersionable]
32             get
33             {
34                 return hasValue;
35             }
36         }
37
38         public T Value
39         {
40             get
41             {
42                 if (!hasValue)
43                 {
44                     ThrowHelper.ThrowInvalidOperationException_InvalidOperation_NoValue();
45                 }
46                 return value;
47             }
48         }
49
50         [NonVersionable]
51         public T GetValueOrDefault()
52         {
53             return value;
54         }
55
56         [NonVersionable]
57         public T GetValueOrDefault(T defaultValue)
58         {
59             return hasValue ? value : defaultValue;
60         }
61
62         public override bool Equals(object other)
63         {
64             if (!hasValue) return other == null;
65             if (other == null) return false;
66             return value.Equals(other);
67         }
68
69         public override int GetHashCode()
70         {
71             return hasValue ? value.GetHashCode() : 0;
72         }
73
74         public override string ToString()
75         {
76             return hasValue ? value.ToString() : "";
77         }
78
79         [NonVersionable]
80         public static implicit operator Nullable<T>(T value)
81         {
82             return new Nullable<T>(value);
83         }
84
85         [NonVersionable]
86         public static explicit operator T(Nullable<T> value)
87         {
88             return value.Value;
89         }
90     }
91
92     public static class Nullable
93     {
94         public static int Compare<T>(Nullable<T> n1, Nullable<T> n2) where T : struct
95         {
96             if (n1.HasValue)
97             {
98                 if (n2.HasValue) return Comparer<T>.Default.Compare(n1.value, n2.value);
99                 return 1;
100             }
101             if (n2.HasValue) return -1;
102             return 0;
103         }
104
105         public static bool Equals<T>(Nullable<T> n1, Nullable<T> n2) where T : struct
106         {
107             if (n1.HasValue)
108             {
109                 if (n2.HasValue) return EqualityComparer<T>.Default.Equals(n1.value, n2.value);
110                 return false;
111             }
112             if (n2.HasValue) return false;
113             return true;
114         }
115
116         // If the type provided is not a Nullable Type, return null.
117         // Otherwise, returns the underlying type of the Nullable type
118         public static Type GetUnderlyingType(Type nullableType)
119         {
120             if ((object)nullableType == null)
121             {
122                 throw new ArgumentNullException(nameof(nullableType));
123             }
124
125 #if CORERT
126             // This is necessary to handle types without reflection metadata
127             if (nullableType.TryGetEEType(out EETypePtr nullableEEType))
128             {
129                 if (nullableEEType.IsGeneric)
130                 {
131                     if (nullableEEType.IsNullable)
132                     {
133                         return Internal.Reflection.Core.NonPortable.RuntimeTypeUnifier.GetRuntimeTypeForEEType(nullableEEType.NullableType);
134                     }
135                 }
136                 return null;
137             }
138 #endif
139
140             if (nullableType.IsGenericType && !nullableType.IsGenericTypeDefinition)
141             {
142                 // instantiated generic type only                
143                 Type genericType = nullableType.GetGenericTypeDefinition();
144                 if (object.ReferenceEquals(genericType, typeof(Nullable<>)))
145                 {
146                     return nullableType.GetGenericArguments()[0];
147                 }
148             }
149             return null;
150         }
151     }
152 }