From 8a37c316fda4588473bc0bad4305017be3fb7b58 Mon Sep 17 00:00:00 2001 From: Anne Thompson Date: Mon, 11 Sep 2023 15:31:07 -0700 Subject: [PATCH] Allow As to return null for reference types (#38611) * Allow As to return null for reference types * Improve cast exception message --- .../src/Variant/Variant.cs | 19 +++++++--- .../tests/Variant/VariantUsage.cs | 36 +++++++++++++++++++ 2 files changed, 51 insertions(+), 4 deletions(-) diff --git a/sdk/core/Azure.Core.Experimental/src/Variant/Variant.cs b/sdk/core/Azure.Core.Experimental/src/Variant/Variant.cs index ec3264b5edd22..12cb8bd9efd08 100644 --- a/sdk/core/Azure.Core.Experimental/src/Variant/Variant.cs +++ b/sdk/core/Azure.Core.Experimental/src/Variant/Variant.cs @@ -77,7 +77,17 @@ public Variant(object? value) } [DoesNotReturn] - private static void ThrowInvalidCast() => throw new InvalidCastException(); + private static void ThrowInvalidCast(Type? source, Type target) + { + if (source is null) + { + throw new InvalidCastException($"Unable to cast null Variant to type '{target}'."); + } + else + { + throw new InvalidCastException($"Unable to cast Variant of type '{source}' to type '{target}'."); + } + } [DoesNotReturn] private static void ThrowArgumentNull(string paramName) => throw new ArgumentNullException(paramName); @@ -1296,11 +1306,12 @@ private Variant(object o, ulong u) { // Single return has a significant performance benefit. - bool result = false; + bool result; if (_object is null) { value = default!; + result = true; } else if (typeof(T) == typeof(char[])) { @@ -1380,9 +1391,9 @@ private Variant(object o, ulong u) [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly T As() { - if (!TryGetValue(out T value)) + if (!TryGetValue(out T value)) { - ThrowInvalidCast(); + ThrowInvalidCast(Type, typeof(T)); } return value; diff --git a/sdk/core/Azure.Core.Experimental/tests/Variant/VariantUsage.cs b/sdk/core/Azure.Core.Experimental/tests/Variant/VariantUsage.cs index 3c115b0ae7b66..23c8b43815fb0 100644 --- a/sdk/core/Azure.Core.Experimental/tests/Variant/VariantUsage.cs +++ b/sdk/core/Azure.Core.Experimental/tests/Variant/VariantUsage.cs @@ -91,6 +91,42 @@ public void VariantAssignmentHasReferenceSemantics() Assert.AreEqual("3", b.As>()[0]); } + [Test] + public void ReferenceTypesCanBeNull() + { + string s = null; + Variant stringVariant = new(s); + + Assert.AreEqual(Variant.Null, stringVariant); + Assert.IsNull(stringVariant.As()); + + List list = null; + Variant listVariant = new(list); + + Assert.AreEqual(Variant.Null, listVariant); + Assert.IsNull(listVariant.As()); + } + + [Test] + public void NonNullableValueTypesCannotBeNull() + { + int? i = null; + Variant intVariant = new(i); + + Assert.AreEqual(Variant.Null, intVariant); + Assert.Throws(() => intVariant.As()); + } + + [Test] + public void NullableValueTypesCanBeNull() + { + int? i = null; + Variant intVariant = new(i); + + Assert.AreEqual(Variant.Null, intVariant); + Assert.IsNull(intVariant.As()); + } + #region Helpers public static IEnumerable VariantValues() {