diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/OutputTypes/CSharpType.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/OutputTypes/CSharpType.cs
index 9d251e6925..bab9c08fcb 100644
--- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/OutputTypes/CSharpType.cs
+++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/OutputTypes/CSharpType.cs
@@ -66,8 +66,8 @@ public class CSharpType
/// Optional flag to determine if the constructed type should be nullable. Defaults to false.
public CSharpType(Type type, bool isNullable = false) : this(
type,
- isNullable,
- type.IsGenericType ? type.GetGenericArguments().Select(p => new CSharpType(p)).ToArray() : Array.Empty())
+ type.IsGenericType ? type.GetGenericArguments().Select(p => new CSharpType(p)).ToArray() : Array.Empty(),
+ isNullable)
{ }
///
@@ -97,6 +97,16 @@ public CSharpType(Type type, IReadOnlyList arguments, bool isNullabl
{
Debug.Assert(type.Namespace != null, "type.Namespace != null");
+ // handle nullable value types explicitly because they are implemented using generic type `System.Nullable`
+ var underlyingValueType = Nullable.GetUnderlyingType(type);
+ if (underlyingValueType != null)
+ {
+ // in this block, we are converting input like `typeof(int?)` into the way as if they input: `typeof(int), isNullable: true`
+ type = underlyingValueType;
+ arguments = type.IsGenericType ? type.GetGenericArguments().Select(p => new CSharpType(p)).ToArray() : Array.Empty();
+ isNullable = true;
+ }
+
_type = type.IsGenericType ? type.GetGenericTypeDefinition() : type;
ValidateArguments(_type, arguments);
diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/test/CSharpTypeTests.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/test/CSharpTypeTests.cs
index 67d715c3bf..e5cf8aed3e 100644
--- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/test/CSharpTypeTests.cs
+++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/test/CSharpTypeTests.cs
@@ -1,14 +1,14 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
-using System.Collections.Generic;
using System;
-using NUnit.Framework;
-using System.Linq;
+using System.Collections.Generic;
using System.Collections.Immutable;
-using Moq;
using System.IO;
+using System.Linq;
using System.Text;
+using Moq;
+using NUnit.Framework;
namespace Microsoft.Generator.CSharp.Tests
{
@@ -394,5 +394,71 @@ public void TestToString(Type type, string expectedString)
Assert.AreEqual(expected, actual);
}
+
+ [TestCaseSource(nameof(ValidateNullableTypesData))]
+ public void ValidateNullableTypes(Type type, IReadOnlyList expectedArguments, bool expectedIsNullable)
+ {
+ var csharpType = new CSharpType(type);
+
+ CollectionAssert.AreEqual(expectedArguments, csharpType.Arguments);
+ Assert.AreEqual(expectedIsNullable, csharpType.IsNullable);
+ }
+
+ private static object[] ValidateNullableTypesData = [
+ new object[]
+ {
+ typeof(int), Array.Empty(), false
+ },
+ new object[]
+ {
+ typeof(int?), Array.Empty(), true
+ },
+ new object[]
+ {
+ typeof(Uri), Array.Empty(), false
+ },
+ new object[]
+ {
+ typeof(Guid), Array.Empty(), false
+ },
+ new object[]
+ {
+ typeof(Guid?), Array.Empty(), true
+ },
+ new object[]
+ {
+ typeof(TestStruct), new CSharpType[] { typeof(int) }, false
+ },
+ new object[]
+ {
+ typeof(TestStruct?), new CSharpType[] { typeof(int) }, true
+ },
+ new object[]
+ {
+ typeof(TestStruct), new CSharpType[] { typeof(int?) }, false
+ },
+ new object[]
+ {
+ typeof(TestStruct?), new CSharpType[] { typeof(int?) }, true
+ },
+ new object[]
+ {
+ typeof(TestStruct>), new CSharpType[] { typeof(TestStruct) }, false
+ },
+ new object[]
+ {
+ typeof(TestStruct>?), new CSharpType[] { typeof(TestStruct) }, true
+ },
+ new object[]
+ {
+ typeof(TestStruct?>), new CSharpType[] { typeof(TestStruct?) }, false
+ },
+ new object[]
+ {
+ typeof(TestStruct?>?), new CSharpType[] { typeof(TestStruct?) }, true
+ },
+ ];
+
+ internal struct TestStruct { }
}
}