Skip to content

Commit 52bd4c6

Browse files
committed
Feat: IsNullableReferenceType
1 parent d5a4ff9 commit 52bd4c6

File tree

2 files changed

+100
-0
lines changed

2 files changed

+100
-0
lines changed
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// ---------------------------------------------------------------------------------------------------------------------
2+
// Imports
3+
// ---------------------------------------------------------------------------------------------------------------------
4+
using System.Reflection;
5+
6+
namespace CodeOfChaos.Extensions;
7+
8+
// ---------------------------------------------------------------------------------------------------------------------
9+
// Code
10+
// ---------------------------------------------------------------------------------------------------------------------
11+
public static class ReflectionHelper {
12+
public static bool IsNullableReferenceType(this ParameterInfo parameter) {
13+
// Value types can't be nullable reference types
14+
if (parameter.ParameterType.IsValueType)
15+
return false;
16+
17+
// Check if NullableAttribute exists on this parameter
18+
CustomAttributeData? nullableAttribute = parameter.GetCustomAttributesData()
19+
.FirstOrDefault(attr => attr.AttributeType.FullName == "System.Runtime.CompilerServices.NullableAttribute");
20+
21+
// If there is no NullableAttribute, treat it as non-nullable
22+
if (nullableAttribute == null || nullableAttribute.ConstructorArguments.Count == 0)
23+
return false;
24+
25+
// NullableAttribute encodes nullability flags; we need the first value for this parameter
26+
byte? nullabilityFlag = nullableAttribute.ConstructorArguments[0].Value as byte? ;
27+
28+
// "2" = Nullable; "0" = Non-nullable; "1" = Oblivious (treat as non-nullable in this context)
29+
return nullabilityFlag == 2;
30+
31+
}
32+
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
// ---------------------------------------------------------------------------------------------------------------------
2+
// Imports
3+
// ---------------------------------------------------------------------------------------------------------------------
4+
using CodeOfChaos.Extensions;
5+
using System.Reflection;
6+
7+
namespace Tests.CodeOfChaos.Extensions;
8+
9+
// ---------------------------------------------------------------------------------------------------------------------
10+
// Code
11+
// ---------------------------------------------------------------------------------------------------------------------
12+
public class ReflectionHelperTests {
13+
private class TestClass
14+
{
15+
// ReSharper disable UnusedParameter.Local
16+
public static void MethodWithNullability(
17+
string nonNullable,
18+
string? nullable,
19+
int valueType)
20+
{ }
21+
}
22+
23+
// -----------------------------------------------------------------------------------------------------------------
24+
// Methods
25+
// -----------------------------------------------------------------------------------------------------------------
26+
[Test]
27+
public async Task IsNullableReferenceType_ShouldReturnTrue_ForNullableReferenceType()
28+
{
29+
// Arrange
30+
MethodInfo method = typeof(TestClass).GetMethod(nameof(TestClass.MethodWithNullability))!;
31+
ParameterInfo nullableParameter = method.GetParameters().First(p => p.Name == "nullable");
32+
33+
// Act
34+
bool result = nullableParameter.IsNullableReferenceType();
35+
36+
// Assert
37+
await Assert.That(result).IsTrue().Because("Expected parameter 'nullable' to be recognized as a nullable reference type.");
38+
}
39+
40+
[Test]
41+
public async Task IsNullableReferenceType_ShouldReturnFalse_ForNonNullableReferenceType()
42+
{
43+
// Arrange
44+
MethodInfo method = typeof(TestClass).GetMethod(nameof(TestClass.MethodWithNullability))!;
45+
ParameterInfo nonNullableParameter = method.GetParameters().First(p => p.Name == "nonNullable");
46+
47+
// Act
48+
bool result = nonNullableParameter.IsNullableReferenceType();
49+
50+
// Assert
51+
await Assert.That(result).IsFalse().Because("Expected parameter 'nonNullable' to be recognized as a non-nullable reference type.");
52+
}
53+
54+
[Test]
55+
public async Task IsNullableReferenceType_ShouldReturnFalse_ForValueType()
56+
{
57+
// Arrange
58+
MethodInfo method = typeof(TestClass).GetMethod(nameof(TestClass.MethodWithNullability))!;
59+
ParameterInfo valueTypeParameter = method.GetParameters().First(p => p.Name == "valueType");
60+
61+
// Act
62+
bool result = valueTypeParameter.IsNullableReferenceType();
63+
64+
// Assert
65+
await Assert.That(result).IsFalse().Because("Expected parameter 'valueType' to be recognized as a non-nullable reference type.");
66+
}
67+
68+
}

0 commit comments

Comments
 (0)