Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
90ed195
Add Type.GetNullableUnderlyingType() virtual API
AaronRobinsonMSFT Mar 10, 2026
2e7a9fb
Address review feedback for Type.GetNullableUnderlyingType()
AaronRobinsonMSFT Apr 14, 2026
656890c
Merge remote-tracking branch 'upstream/main' into fix/124216-nullable…
AaronRobinsonMSFT Apr 14, 2026
1aa46f5
Improve MLC tests: throwOnError and stronger assertions
AaronRobinsonMSFT Apr 14, 2026
e8a877d
Efficient GetNullableUnderlyingType() via MethodTable for CoreCLR/Nat…
AaronRobinsonMSFT Apr 15, 2026
325f699
Add GetNullableUnderlyingType() overrides for Emit/Modified types; mo…
AaronRobinsonMSFT Apr 15, 2026
5da1c09
Fix open-generic Nullable<> edge cases and preserve TypeBuilderInstan…
AaronRobinsonMSFT Apr 15, 2026
8a39a7a
Remove unnecessary using directive for System.Runtime.InteropServices…
AaronRobinsonMSFT Apr 15, 2026
9f9b085
Fix RoType.GetNullableUnderlyingType guard: use NET11_0_OR_GREATER no…
AaronRobinsonMSFT Apr 15, 2026
4e99b77
Fix SignatureConstructedGenericType.GetNullableUnderlyingType to retu…
AaronRobinsonMSFT Apr 15, 2026
6a03178
Apply suggestions from code review
AaronRobinsonMSFT Apr 15, 2026
2153bf1
Apply suggestion from @jkotas
jkotas Apr 16, 2026
d7228ab
Update src/libraries/System.Private.CoreLib/src/System/Nullable.cs
jkotas Apr 16, 2026
2a92fa3
Apply suggestion from @jkotas
jkotas Apr 16, 2026
8c08626
Fix GetNullableUnderlyingType crashes and wrong results
AaronRobinsonMSFT Apr 17, 2026
2de90fc
Apply jkotas review feedback: add GetNullableUnderlyingType overrides
AaronRobinsonMSFT Apr 24, 2026
92e3faf
Treat Nullable<> generic type definition as nullable in Type.GetNulla…
AaronRobinsonMSFT Apr 24, 2026
49353e3
Merge remote-tracking branch 'upstream/main' into fix/124216-nullable…
AaronRobinsonMSFT Apr 27, 2026
85e3ec5
Address review feedback: fix Nullable<> over foreign generic parameter
AaronRobinsonMSFT Apr 27, 2026
475eb35
Fix misleading comment on SignatureType.GetNullableUnderlyingType
AaronRobinsonMSFT Apr 27, 2026
0e694d9
Fix CoreCLR assert when Nullable<T> is instantiated over a generic va…
AaronRobinsonMSFT Apr 28, 2026
bc3b14d
Address PR feedback: refactor NativeAOT override and add tests
AaronRobinsonMSFT Apr 28, 2026
f631afa
Override GetNullableUnderlyingType on RoModifiedType
AaronRobinsonMSFT Apr 28, 2026
1c5764b
Override GetNullableUnderlyingType on SymbolType
AaronRobinsonMSFT Apr 28, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3591,6 +3591,31 @@ public override GenericParameterAttributes GenericParameterAttributes
#endregion

#region Generics

public override unsafe Type? GetNullableUnderlyingType()
{
TypeHandle th = GetNativeTypeHandle();
if (!th.IsTypeDesc)
{
MethodTable* pMT = th.AsMethodTable();
if (pMT->IsNullable)
{
// The open generic Nullable<> is also classified as Nullable, and a constructed
// Nullable<T> instantiated over a generic variable holds a TypeDesc (not a
// MethodTable*) in InstantiationArg0(). Fall back to managed reflection in
// those cases.
if (pMT->ContainsGenericVariables)
{
return GetGenericArguments()[0];
}
RuntimeType result = RuntimeTypeHandle.GetRuntimeTypeFromHandle((IntPtr)pMT->InstantiationArg0());
GC.KeepAlive(this);
return result;
}
Comment thread
jkotas marked this conversation as resolved.
}
return null;
Comment thread
AaronRobinsonMSFT marked this conversation as resolved.
}

internal RuntimeType[] GetGenericArgumentsInternal()
{
return GetRootElementType().TypeHandle.GetInstantiationInternal();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,11 @@ public sealed override string Name

protected sealed override IEnumerable<CustomAttributeData> TrueCustomAttributes => RuntimeCustomAttributeData.GetCustomAttributes(_reader, _typeDefinition.CustomAttributes);

public sealed override Type? GetNullableUnderlyingType()
{
return (this.ToType() == typeof(Nullable<>)) ? RuntimeGenericTypeParameters[0].ToType() : null;
}

internal sealed override RuntimeTypeInfo[] RuntimeGenericTypeParameters
{
get
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,11 @@ public sealed override Type GetGenericTypeDefinition()
return GenericTypeDefinitionTypeInfo.ToType();
}

public sealed override Type? GetNullableUnderlyingType() =>
GenericTypeDefinitionTypeInfo.ToType() == typeof(Nullable<>)
? _key.GenericTypeArguments[0].ToType()
: null;

public sealed override Guid GUID
{
get
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,8 @@ public virtual Type GetGenericTypeDefinition()
throw new InvalidOperationException(SR.InvalidOperation_NotGenericType);
}

public virtual Type? GetNullableUnderlyingType() => null;

public Type MakeArrayType()
{
// Do not implement this as a call to MakeArrayType(1) - they are not interchangeable. MakeArrayType() returns a
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,19 @@ public override Type GetEnumUnderlyingType()
return Enum.InternalGetUnderlyingType(this);
}

public override Type? GetNullableUnderlyingType()
{
MethodTable* pEEType = _pUnderlyingEEType;
if (pEEType != null)
{
Comment thread
AaronRobinsonMSFT marked this conversation as resolved.
if (!pEEType->IsNullable)
return null;
if (!pEEType->IsGenericTypeDefinition)
return GetTypeFromMethodTable(pEEType->NullableType);
}
return GetRuntimeTypeInfo().GetNullableUnderlyingType();
}

public override bool IsEnumDefined(object value)
{
ArgumentNullException.ThrowIfNull(value);
Expand Down
31 changes: 31 additions & 0 deletions src/libraries/Common/tests/System/ModifiedTypeTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -867,5 +867,36 @@ public static delegate*
delegate*<sbyte> // ret
> _fcnPtr_complex;
}
[Fact]
public static unsafe void GetNullableUnderlyingType_ModifiedType()
{
FieldInfo fi = typeof(NullableModifiedTypeHolder).Project().GetField(nameof(NullableModifiedTypeHolder._fcnPtr_NullableReturn), Bindings);

// The function pointer's return type is Nullable<int>. Pulling the modified return type
// produces a ModifiedType wrapping Nullable<int>, which exercises the override.
Type modifiedNullable = fi.GetModifiedFieldType().GetFunctionPointerReturnType();
Assert.True(IsModifiedType(modifiedNullable));
Assert.Equal(typeof(int?).Project(), modifiedNullable.UnderlyingSystemType);

Type modifiedUnderlying = modifiedNullable.GetNullableUnderlyingType();
Assert.NotNull(modifiedUnderlying);
Assert.True(IsModifiedType(modifiedUnderlying));
Assert.Equal(typeof(int).Project(), modifiedUnderlying.UnderlyingSystemType);
Assert.Same(modifiedNullable.GetGenericArguments()[0], modifiedUnderlying);
}

[Fact]
public static unsafe void GetNullableUnderlyingType_ModifiedType_NonNullable_ReturnsNull()
{
FieldInfo fi = typeof(ModifiedTypeHolder).Project().GetField(nameof(ModifiedTypeHolder._volatileInt), Bindings);
Type modifiedInt = fi.GetModifiedFieldType();
Assert.True(IsModifiedType(modifiedInt));
Assert.Null(modifiedInt.GetNullableUnderlyingType());
}

public unsafe class NullableModifiedTypeHolder
{
public static volatile delegate*<int?> _fcnPtr_NullableReturn;
}
}
}
15 changes: 5 additions & 10 deletions src/libraries/System.Private.CoreLib/src/System/Nullable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -104,16 +104,11 @@ public static bool Equals<T>(T? n1, T? n2) where T : struct
{
ArgumentNullException.ThrowIfNull(nullableType);

if (nullableType.IsGenericType && !nullableType.IsGenericTypeDefinition)
{
// Instantiated generic type only
Type genericType = nullableType.GetGenericTypeDefinition();
if (ReferenceEquals(genericType, typeof(Nullable<>)))
{
return nullableType.GetGenericArguments()[0];
}
}
return null;
// COMPAT: Returns null for generic type definition
if (nullableType.IsGenericTypeDefinition)
Comment thread
AaronRobinsonMSFT marked this conversation as resolved.
return null;

return nullableType.GetNullableUnderlyingType();
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ protected EnumBuilder()
{
}

// An EnumBuilder represents an enum being built; it cannot itself be a Nullable<T>.
public override Type? GetNullableUnderlyingType() => null;

public FieldBuilder UnderlyingField
=> UnderlyingFieldCore;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ protected GenericTypeParameterBuilder()
{
}

// A generic type parameter is not a Nullable<T> instantiation.
public override Type? GetNullableUnderlyingType() => null;

public void SetCustomAttribute(ConstructorInfo con, byte[] binaryAttribute) => SetCustomAttributeCore(con, binaryAttribute);

protected abstract void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan<byte> binaryAttribute);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,8 @@ internal void SetFormat(string format, int curIndex, int length)

public override bool IsSZArray => _rank <= 1 && _isSzArray;

public override Type? GetNullableUnderlyingType() => null;

public override Type MakePointerType()
{
return FormCompoundType(_format + "*", _baseType, 0)!;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ protected TypeBuilder()
{
}

public override Type? GetNullableUnderlyingType() => null;

public const int UnspecifiedTypeSize = 0;

public PackingSize PackingSize
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,7 @@ public override bool ContainsGenericParameters
}
public override MethodBase? DeclaringMethod => null;
public override Type GetGenericTypeDefinition() { return _genericType; }
public override Type? GetNullableUnderlyingType() => _genericType.GetNullableUnderlyingType() is not null ? _typeArguments[0] : null;
Comment thread
AaronRobinsonMSFT marked this conversation as resolved.

[RequiresUnreferencedCode("If some of the generic arguments are annotated (either with DynamicallyAccessedMembersAttribute, or generic constraints), trimming can't validate that the requirements of those annotations are met.")]
public override Type MakeGenericType(params Type[] inst) { throw new InvalidOperationException(SR.Format(SR.Arg_NotGenericTypeDefinition, this)); }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ public override Type[] GetOptionalCustomModifiers()
public override bool ContainsGenericParameters => _unmodifiedType.ContainsGenericParameters;
public override Type GetGenericTypeDefinition() => _unmodifiedType.GetGenericTypeDefinition();
public override bool IsGenericType => _unmodifiedType.IsGenericType;
public override Type? GetNullableUnderlyingType() => _unmodifiedType.GetNullableUnderlyingType() is not null ? GetGenericArguments()[0] : null;
Comment thread
AaronRobinsonMSFT marked this conversation as resolved.

[DynamicallyAccessedMembers(InvokeMemberMembers)]
public override object? InvokeMember(string name, BindingFlags invokeAttr, Binder? binder, object? target,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ public sealed override bool ContainsGenericParameters
internal sealed override SignatureType? ElementType => null;
public sealed override int GetArrayRank() => throw new ArgumentException(SR.Argument_HasToBeArrayClass);
public sealed override Type GetGenericTypeDefinition() => _genericTypeDefinition;
public sealed override Type? GetNullableUnderlyingType() => _genericTypeDefinition.GetNullableUnderlyingType() is not null ? _genericTypeArguments[0] : null;
public sealed override Type[] GetGenericArguments() => GenericTypeArguments;
public sealed override Type[] GenericTypeArguments => (Type[])(_genericTypeArguments.Clone());
public sealed override int GenericParameterPosition => throw new InvalidOperationException(SR.Arg_NotGenericParameter);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ internal SignatureModifiedType(Type baseType, Type[] requiredCustomModifiers, Ty
public override Type[] GenericTypeArguments => _unmodifiedType.GenericTypeArguments;
public override int GenericParameterPosition => _unmodifiedType.GenericParameterPosition;
internal override SignatureType? ElementType => HasElementType ? new SignatureModifiedType(_unmodifiedType.GetElementType()!, [], []) : null;
public override Type? GetNullableUnderlyingType() => _unmodifiedType.GetNullableUnderlyingType();
public override string Name => _unmodifiedType.Name;
public override string? Namespace => _unmodifiedType.Namespace;
public override bool IsEnum => _unmodifiedType.IsEnum;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ internal abstract class SignatureType : Type
{
public sealed override bool IsSignatureType => true;

// The base implementation does not expose Nullable<T> behavior; subclasses override when appropriate.
public override Type? GetNullableUnderlyingType() => null;

// Type flavor predicates
public abstract override bool IsTypeDefinition { get; }
protected abstract override bool HasElementTypeImpl();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ public TypeDelegator([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.
protected override bool IsValueTypeImpl() => typeImpl.IsValueType;
protected override bool IsCOMObjectImpl() => typeImpl.IsCOMObject;
public override bool IsByRefLike => typeImpl.IsByRefLike;
public override Type? GetNullableUnderlyingType() => typeImpl.GetNullableUnderlyingType();
Comment thread
AaronRobinsonMSFT marked this conversation as resolved.
Comment thread
AaronRobinsonMSFT marked this conversation as resolved.
public override bool IsConstructedGenericType => typeImpl.IsConstructedGenericType;

public override bool IsCollectible => typeImpl.IsCollectible;
Expand Down
12 changes: 12 additions & 0 deletions src/libraries/System.Private.CoreLib/src/System/Type.cs
Original file line number Diff line number Diff line change
Expand Up @@ -602,6 +602,18 @@ protected virtual TypeCode GetTypeCodeImpl()
public virtual bool IsInstanceOfType([NotNullWhen(true)] object? o) => o != null && IsAssignableFrom(o.GetType());
public virtual bool IsEquivalentTo([NotNullWhen(true)] Type? other) => this == other;

/// <summary>
/// Returns the underlying type argument of a <see cref="Nullable{T}"/> type.
/// </summary>
/// <returns>
/// The type argument of the <see cref="Nullable{T}"/> type if the current type represents
/// the <see cref="Nullable{T}"/> generic type definition or a constructed <see cref="Nullable{T}"/>;
/// otherwise, <see langword="null"/>. When the current type is the generic type definition
/// (for example, <c>typeof(Nullable&lt;&gt;)</c>), the returned type is the generic type
/// parameter <c>T</c>.
/// </returns>
public virtual Type? GetNullableUnderlyingType() => throw new NotSupportedException(SR.NotSupported_SubclassOverride);
Comment thread
AaronRobinsonMSFT marked this conversation as resolved.

[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2085:UnrecognizedReflectionPattern",
Justification = "The single instance field on enum types is never trimmed")]
[Intrinsic]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ protected EnumBuilder() { }
public override System.Type? GetNestedType(string name, System.Reflection.BindingFlags bindingAttr) { throw null; }
[System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.NonPublicNestedTypes | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicNestedTypes)]
public override System.Type[] GetNestedTypes(System.Reflection.BindingFlags bindingAttr) { throw null; }
public override System.Type? GetNullableUnderlyingType() { throw null; }
[System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.NonPublicProperties | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicProperties)]
public override System.Reflection.PropertyInfo[] GetProperties(System.Reflection.BindingFlags bindingAttr) { throw null; }
[System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.NonPublicProperties | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicProperties)]
Expand Down Expand Up @@ -293,6 +294,7 @@ protected GenericTypeParameterBuilder() { }
public override System.Type GetNestedType(string name, System.Reflection.BindingFlags bindingAttr) { throw null; }
[System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.NonPublicNestedTypes | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicNestedTypes)]
public override System.Type[] GetNestedTypes(System.Reflection.BindingFlags bindingAttr) { throw null; }
public override System.Type? GetNullableUnderlyingType() { throw null; }
[System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.NonPublicProperties | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicProperties)]
public override System.Reflection.PropertyInfo[] GetProperties(System.Reflection.BindingFlags bindingAttr) { throw null; }
[System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.NonPublicProperties | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicProperties)]
Expand Down Expand Up @@ -657,6 +659,7 @@ public void DefineMethodOverride(System.Reflection.MethodInfo methodInfoBody, Sy
public override System.Type? GetNestedType(string name, System.Reflection.BindingFlags bindingAttr) { throw null; }
[System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.NonPublicNestedTypes | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicNestedTypes)]
public override System.Type[] GetNestedTypes(System.Reflection.BindingFlags bindingAttr) { throw null; }
public override System.Type? GetNullableUnderlyingType() { throw null; }
[System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.NonPublicProperties | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicProperties)]
public override System.Reflection.PropertyInfo[] GetProperties(System.Reflection.BindingFlags bindingAttr) { throw null; }
[System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.NonPublicProperties | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicProperties)]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@
<Compile Include="TypeBuilder\TypeBuilderGetField.cs" />
<Compile Include="TypeBuilder\TypeBuilderGetGenericTypeDefinition.cs" />
<Compile Include="TypeBuilder\TypeBuilderGetMethod.cs" />
<Compile Include="TypeBuilder\TypeBuilderGetNullableUnderlyingType.cs" />
<Compile Include="TypeBuilder\TypeBuilderGUID.cs" />
<Compile Include="TypeBuilder\TypeBuilderIsByRefLike.cs" />
<Compile Include="TypeBuilder\TypeBuilderIsGenericParameter.cs" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Xunit;

namespace System.Reflection.Emit.Tests
{
public class TypeBuilderGetNullableUnderlyingType
{
[Fact]
public void TypeBuilder_ReturnsNull()
{
TypeBuilder tb = Helpers.DynamicType(TypeAttributes.Public);
Assert.Null(tb.GetNullableUnderlyingType());
}
Comment thread
AaronRobinsonMSFT marked this conversation as resolved.

[Fact]
public void EnumBuilder_ReturnsNull()
{
EnumBuilder eb = Helpers.DynamicEnum(TypeAttributes.Public, typeof(int));
Assert.Null(eb.GetNullableUnderlyingType());
}

[Fact]
public void GenericTypeParameterBuilder_ReturnsNull()
{
TypeBuilder tb = Helpers.DynamicType(TypeAttributes.Public);
GenericTypeParameterBuilder[] gps = tb.DefineGenericParameters("T");
Assert.Null(gps[0].GetNullableUnderlyingType());
}

[Fact]
public void TypeBuilderInstantiation_ReturnsNull()
{
// A TypeBuilderInstantiation is produced when MakeGenericType is called on a
// generic TypeBuilder. The open generic definition is a TypeBuilder (never
// typeof(Nullable<>)), so the override always returns null in practice.
TypeBuilder tb = Helpers.DynamicType(TypeAttributes.Public);
tb.DefineGenericParameters("T");
Type instantiation = tb.MakeGenericType(typeof(int));
Assert.Null(instantiation.GetNullableUnderlyingType());
}

[Fact]
public void SymbolType_Array_ReturnsNull()
{
TypeBuilder tb = Helpers.DynamicType(TypeAttributes.Public);
Type arrayType = tb.MakeArrayType();
Assert.Null(arrayType.GetNullableUnderlyingType());
Assert.Null(Nullable.GetUnderlyingType(arrayType));
}

[Fact]
public void SymbolType_MultiDimArray_ReturnsNull()
{
TypeBuilder tb = Helpers.DynamicType(TypeAttributes.Public);
Type arrayType = tb.MakeArrayType(2);
Assert.Null(arrayType.GetNullableUnderlyingType());
Assert.Null(Nullable.GetUnderlyingType(arrayType));
}

[Fact]
public void SymbolType_Pointer_ReturnsNull()
{
TypeBuilder tb = Helpers.DynamicType(TypeAttributes.Public);
Type pointerType = tb.MakePointerType();
Assert.Null(pointerType.GetNullableUnderlyingType());
Assert.Null(Nullable.GetUnderlyingType(pointerType));
}

[Fact]
public void SymbolType_ByRef_ReturnsNull()
{
TypeBuilder tb = Helpers.DynamicType(TypeAttributes.Public);
Type byRefType = tb.MakeByRefType();
Assert.Null(byRefType.GetNullableUnderlyingType());
Assert.Null(Nullable.GetUnderlyingType(byRefType));
}
}
}
Loading
Loading