in sdk/core/Azure.Core.Experimental/src/Variant/Variant.cs [1132:1324]
private readonly bool TryGetValueSlow<T>(out T value)
{
// Single return has a significant performance benefit.
bool result = false;
if (_object is null)
{
// A null is stored, it can only be assigned to a reference type or nullable.
value = default!;
result = Nullable.GetUnderlyingType(typeof(T)) is not null;
}
else if (typeof(T).IsEnum && _object is TypeFlag<T> typeFlag)
{
value = typeFlag.To(in this);
result = true;
}
else if (_object is T t)
{
value = t;
result = true;
}
else if (typeof(T) == typeof(ArraySegment<byte>))
{
ulong bits = _union.UInt64;
if (bits != 0 && _object is byte[] byteArray)
{
ArraySegment<byte> segment = bits != ulong.MaxValue
? new(byteArray, _union.Segment.Offset, _union.Segment.Count)
: new(byteArray, 0, 0);
value = Unsafe.As<ArraySegment<byte>, T>(ref segment);
result = true;
}
else
{
value = default!;
}
}
else if (typeof(T) == typeof(ArraySegment<char>))
{
ulong bits = _union.UInt64;
if (bits != 0 && _object is char[] charArray)
{
ArraySegment<char> segment = bits != ulong.MaxValue
? new(charArray, _union.Segment.Offset, _union.Segment.Count)
: new(charArray, 0, 0);
value = Unsafe.As<ArraySegment<char>, T>(ref segment);
result = true;
}
else
{
value = default!;
}
}
else if (typeof(T) == typeof(int?) && _object == TypeFlags.Int32)
{
int? asInt = (int?)_union.Int32;
value = Unsafe.As<int?, T>(ref Unsafe.AsRef(in asInt));
result = true;
}
else if (typeof(T) == typeof(long?) && _object == TypeFlags.Int64)
{
long? asLong = (long?)_union.Int64;
value = Unsafe.As<long?, T>(ref Unsafe.AsRef(in asLong));
result = true;
}
else if (typeof(T) == typeof(bool?) && _object == TypeFlags.Boolean)
{
bool? asBool = (bool?)_union.Boolean;
value = Unsafe.As<bool?, T>(ref Unsafe.AsRef(in asBool));
result = true;
}
else if (typeof(T) == typeof(float?) && _object == TypeFlags.Single)
{
float? asFloat = (float?)_union.Single;
value = Unsafe.As<float?, T>(ref Unsafe.AsRef(in asFloat));
result = true;
}
else if (typeof(T) == typeof(double?) && _object == TypeFlags.Double)
{
double? asDouble = (double?)_union.Double;
value = Unsafe.As<double?, T>(ref Unsafe.AsRef(in asDouble));
result = true;
}
else if (typeof(T) == typeof(uint?) && _object == TypeFlags.UInt32)
{
uint? asUInt = (uint?)_union.UInt32;
value = Unsafe.As<uint?, T>(ref Unsafe.AsRef(in asUInt));
result = true;
}
else if (typeof(T) == typeof(ulong?) && _object == TypeFlags.UInt64)
{
ulong? asULong = (ulong?)_union.UInt64;
value = Unsafe.As<ulong?, T>(ref Unsafe.AsRef(in asULong));
result = true;
}
else if (typeof(T) == typeof(char?) && _object == TypeFlags.Char)
{
char? asChar = (char?)_union.Char;
value = Unsafe.As<char?, T>(ref Unsafe.AsRef(in asChar));
result = true;
}
else if (typeof(T) == typeof(short?) && _object == TypeFlags.Int16)
{
short? asShort = (short?)_union.Int16;
value = Unsafe.As<short?, T>(ref Unsafe.AsRef(in asShort));
result = true;
}
else if (typeof(T) == typeof(ushort?) && _object == TypeFlags.UInt16)
{
ushort? asUShort = (ushort?)_union.UInt16;
value = Unsafe.As<ushort?, T>(ref Unsafe.AsRef(in asUShort));
result = true;
}
else if (typeof(T) == typeof(byte?) && _object == TypeFlags.Byte)
{
byte? asByte = (byte?)_union.Byte;
value = Unsafe.As<byte?, T>(ref Unsafe.AsRef(in asByte));
result = true;
}
else if (typeof(T) == typeof(sbyte?) && _object == TypeFlags.SByte)
{
sbyte? asSByte = (sbyte?)_union.SByte;
value = Unsafe.As<sbyte?, T>(ref Unsafe.AsRef(in asSByte));
result = true;
}
else if (typeof(T) == typeof(DateTime?) && _object == TypeFlags.DateTime)
{
DateTime? asDateTime = (DateTime?)_union.DateTime;
value = Unsafe.As<DateTime?, T>(ref Unsafe.AsRef(in asDateTime));
result = true;
}
else if (typeof(T) == typeof(DateTimeOffset?) && _object == TypeFlags.DateTimeOffset)
{
DateTimeOffset? asDateTimeOffset = (DateTimeOffset?)new DateTimeOffset(_union.Ticks, TimeSpan.Zero);
value = Unsafe.As<DateTimeOffset?, T>(ref Unsafe.AsRef(in asDateTimeOffset));
result = true;
}
else if (typeof(T) == typeof(DateTimeOffset?) && _object == TypeFlags.PackedDateTimeOffset)
{
DateTimeOffset? asDateTimeOffset = (DateTimeOffset?)_union.PackedDateTimeOffset.Extract();
value = Unsafe.As<DateTimeOffset?, T>(ref Unsafe.AsRef(in asDateTimeOffset));
result = true;
}
else if (Nullable.GetUnderlyingType(typeof(T)) is Type underlyingType
&& underlyingType.IsEnum
&& _object is TypeFlag underlyingTypeFlag
&& underlyingTypeFlag.Type == underlyingType)
{
// Asked for a nullable enum and we've got that type.
// We've got multiple layouts, depending on the size of the enum backing field. We can't use the
// nullable itself (e.g. default(T)) as a template as it gets treated specially by the runtime.
int size = Unsafe.SizeOf<T>();
switch (size)
{
case (2):
NullableTemplate<byte> byteTemplate = new(_union.Byte);
value = Unsafe.As<NullableTemplate<byte>, T>(ref Unsafe.AsRef(in byteTemplate));
result = true;
break;
case (4):
NullableTemplate<ushort> shortTemplate = new(_union.UInt16);
value = Unsafe.As<NullableTemplate<ushort>, T>(ref Unsafe.AsRef(in shortTemplate));
result = true;
break;
case (8):
NullableTemplate<uint> intTemplate = new(_union.UInt32);
value = Unsafe.As<NullableTemplate<uint>, T>(ref Unsafe.AsRef(in intTemplate));
result = true;
break;
case (16):
NullableTemplate<ulong> longTemplate = new(_union.UInt64);
value = Unsafe.As<NullableTemplate<ulong>, T>(ref Unsafe.AsRef(in longTemplate));
result = true;
break;
default:
ThrowInvalidOperation();
value = default!;
result = false;
break;
}
}
else
{
value = default!;
result = false;
}
return result;
}