Exposes top-level nullability information from reflection.
This feature is included in net6. This project exposes the APIs to lower runtime. It supports netstandard2.0
and up.
This project ships two packages:
https://nuget.org/packages/Nullability.Source/
A source-only nuget designed to be compatible for libraries that are targeting multiple frameworks including net6
. In net5
and below the source files shipped in this nuget are used. In net6
and up the types from System.Runtime.dll
are used.
https://nuget.org/packages/Nullability/
A traditional nuget that ships a single assembly Nullability.dll
. Since this project syncs with the current master from https://github.com/dotnet/runtime, it contains fixes that may not be included in the currently System.Runtime.dll
. Use the Nullability package to get those fixes.
To prevent name conflicts the following has been changed:
System.Reflection.NullabilityState
=>Nullability.NullabilityStateEx
System.Reflection.NullabilityInfoContext
=>Nullability.NullabilityInfoContextEx
The csproj and nuget config that builds the package is under MIT.
The content of the nugets are also MIT but are Copyright (c) .NET Foundation and Contributors
Given the following class
class Target
{
public string? StringField;
public string?[] ArrayField;
public Dictionary<string, object?> GenericField;
}
From the Nullability.Source package
[Fact]
public void Test()
{
var type = typeof(Target);
var arrayField = type.GetField("ArrayField");
var genericField = type.GetField("GenericField");
var context = new NullabilityInfoContext();
var arrayInfo = context.Create(arrayField);
Assert.Equal(NullabilityState.NotNull, arrayInfo.ReadState);
Assert.Equal(NullabilityState.Nullable, arrayInfo.ElementType.ReadState);
var genericInfo = context.Create(genericField);
Assert.Equal(NullabilityState.NotNull, genericInfo.ReadState);
Assert.Equal(NullabilityState.NotNull, genericInfo.GenericTypeArguments[0].ReadState);
Assert.Equal(NullabilityState.Nullable, genericInfo.GenericTypeArguments[1].ReadState);
}
From the Nullability package
[Fact]
public void Test()
{
var type = typeof(Target);
var arrayField = type.GetField("ArrayField");
var genericField = type.GetField("GenericField");
var context = new NullabilityInfoContextEx();
var arrayInfo = context.Create(arrayField);
Assert.Equal(NullabilityStateEx.NotNull, arrayInfo.ReadState);
Assert.Equal(NullabilityStateEx.Nullable, arrayInfo.ElementType.ReadState);
var genericInfo = context.Create(genericField);
Assert.Equal(NullabilityStateEx.NotNull, genericInfo.ReadState);
Assert.Equal(NullabilityStateEx.NotNull, genericInfo.GenericTypeArguments[0].ReadState);
Assert.Equal(NullabilityStateEx.Nullable, genericInfo.GenericTypeArguments[1].ReadState);
}
NullabilityInfoExtensions
provides static and thread safe wrapper around . It adds three extension methods to each of ParameterInfo, PropertyInfo, EventInfo, and FieldInfo.
GetNullabilityInfo
: returns theNullabilityInfo
for the target info.GetNullability
: returns theNullabilityState
for the state (NullabilityInfo.ReadState
orNullabilityInfo.WriteState
depending on which has more info) of target info.IsNullable
: given the state (NullabilityInfo.ReadState
orNullabilityInfo.WriteState
depending on which has more info) of the info:- Returns true if state is
NullabilityState.Nullable
. - Returns false if state is
NullabilityState.NotNull
. - Throws an exception if state is
NullabilityState.Unknown
.
- Returns true if state is
namespace System.Reflection
{
public sealed class NullabilityInfoContext
{
public NullabilityInfo Create(ParameterInfo parameterInfo);
public NullabilityInfo Create(PropertyInfo propertyInfo);
public NullabilityInfo Create(EventInfo eventInfo);
public NullabilityInfo Create(FieldInfo parameterInfo);
}
}
#nullable enable
using System.Linq;
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Collections.ObjectModel;
namespace System.Reflection
{
/// <summary>
/// A class that represents nullability info
/// </summary>
sealed class NullabilityInfo
{
internal NullabilityInfo(Type type, NullabilityState readState, NullabilityState writeState,
NullabilityInfo? elementType, NullabilityInfo[] typeArguments)
{
Type = type;
ReadState = readState;
WriteState = writeState;
ElementType = elementType;
GenericTypeArguments = typeArguments;
}
/// <summary>
/// The <see cref="System.Type" /> of the member or generic parameter
/// to which this NullabilityInfo belongs
/// </summary>
public Type Type { get; }
/// <summary>
/// The nullability read state of the member
/// </summary>
public NullabilityState ReadState { get; internal set; }
/// <summary>
/// The nullability write state of the member
/// </summary>
public NullabilityState WriteState { get; internal set; }
/// <summary>
/// If the member type is an array, gives the <see cref="NullabilityInfo" /> of the elements of the array, null otherwise
/// </summary>
public NullabilityInfo? ElementType { get; }
/// <summary>
/// If the member type is a generic type, gives the array of <see cref="NullabilityInfo" /> for each type parameter
/// </summary>
public NullabilityInfo[] GenericTypeArguments { get; }
}
/// <summary>
/// An enum that represents nullability state
/// </summary>
enum NullabilityState
{
/// <summary>
/// Nullability context not enabled (oblivious)
/// </summary>
Unknown,
/// <summary>
/// Non nullable value or reference type
/// </summary>
NotNull,
/// <summary>
/// Nullable value or reference type
/// </summary>
Nullable
}
}
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Collections.ObjectModel;
using NullabilityInfoContext= Nullability.NullabilityInfoContextEx;
using NullabilityInfo = Nullability.NullabilityInfoEx;
using NullabilityState = Nullability.NullabilityStateEx;
namespace Nullability
{
/// <summary>
/// A class that represents nullability info
/// </summary>
public sealed class NullabilityInfoEx
{
internal NullabilityInfoEx(Type type, NullabilityState readState, NullabilityState writeState,
NullabilityInfo? elementType, NullabilityInfo[] typeArguments)
{
Type = type;
ReadState = readState;
WriteState = writeState;
ElementType = elementType;
GenericTypeArguments = typeArguments;
}
/// <summary>
/// The <see cref="System.Type" /> of the member or generic parameter
/// to which this NullabilityInfo belongs
/// </summary>
public Type Type { get; }
/// <summary>
/// The nullability read state of the member
/// </summary>
public NullabilityState ReadState { get; internal set; }
/// <summary>
/// The nullability write state of the member
/// </summary>
public NullabilityState WriteState { get; internal set; }
/// <summary>
/// If the member type is an array, gives the <see cref="NullabilityInfo" /> of the elements of the array, null otherwise
/// </summary>
public NullabilityInfo? ElementType { get; }
/// <summary>
/// If the member type is a generic type, gives the array of <see cref="NullabilityInfo" /> for each type parameter
/// </summary>
public NullabilityInfo[] GenericTypeArguments { get; }
}
/// <summary>
/// An enum that represents nullability state
/// </summary>
public enum NullabilityStateEx
{
/// <summary>
/// Nullability context not enabled (oblivious)
/// </summary>
Unknown,
/// <summary>
/// Non nullable value or reference type
/// </summary>
NotNull,
/// <summary>
/// Nullable value or reference type
/// </summary>
Nullable
}
}
On every build the NullabilityInfo.csproj
downloads NullabilityInfo.cs
and NullabilityInfoContext.cs
. This ensures that the bundled files are always up to date on each release.
Reflection designed by Yogi Aprelliyanto from The Noun Project.