-
Notifications
You must be signed in to change notification settings - Fork 4.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
New API: MemberNotNullAttribute
and MemberNotNullWhenAttribute
#31877
Comments
Should there be a MemberNull attribute for methods that might reset members back to their null state? |
We know multiple scenarios (like constructor helpers) where |
namespace System.Diagnostics.CodeAnalysis
{
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, AllowMultiple = true, Inherited = false)]
public sealed class MemberNotNullAttribute : Attribute
{
public MemberNotNullAttribute(params string[] members) { }
}
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, AllowMultiple = true, Inherited = false)]
public sealed class MemberNotNullWhenAttribute : Attribute
{
public MemberNotNullWhenAttribute(bool when, params string[] members) { }
}
} |
@terrajobst I think that |
Opened PR for adding these attributes: #33567 |
The examples provide motivation for the new API ("before state") but do not provide the "after state" examples. Is it possible to provide examples with decorations? |
e.g. If you have: public class C
{
private string _s;
public C()
{
Init();
}
private void Init()
{
_s = "Hello";
}
} Today you might use public class C
{
private string _s = null!;
public C()
{
Init();
}
private void Init()
{
_s = "Hello";
}
} whereas with MemberNotNull you do: public class C
{
private string _s;
public C()
{
Init();
}
[MemberNotNull(nameof(_s))]
private void Init()
{
_s = "Hello";
}
} |
@jcouv @stephentoub Is it too late to ask for a revision around My use-case is that I have a tri-state public enum CurrentlyPlaying
{
None = 0,
ThisGame = 1,
DifferentGame = 2
}
public abstract partial class GameModuleBase<TGame>
{
// What I'd like to write here:
[MemberNotNullWhen(CurrentlyPlaying.ThisGame, nameof(Game))]
protected CurrentlyPlaying GameInProgress { get; }
protected TGame? Game { get; }
} So my users can write their checks like |
We discussed that for Maybe/NotNullWhen as well back when they were first introduced. The use case certainly comes up, but it was deemed not widespread enough to meet the bar for the compiler. @jcouv can comment on whether we can revisit it. If we were going to do this, I'd want to do that for all of the When attributes, not just MemberNotNullWhen. |
I would like this for all of the When attributes. I think I had a few enum-returning methods with nullable out parameters. |
I would like to support enums as well, but unfortunately, that would require some significant changes to dataflow/nullability analysis. If we want to analyze based on enum values, now we need to split the state multiple ways, ranging from 2 to (potentially large) N and need to known which states correspond to which enum values (it's no longer just true and false alternatives). This is technically feasible, but requires significant change that go deeper than nullability analysis (affect the common dataflow analysis infrastructure). That does not seem worthwhile when a simple pattern can solve the problem: add an instance or extension method that does the test, is annotated with the attribute and returns a boolean. |
As part of the nullability feature C# 8, we have shipped a number of attributes already (
NotNull
,MaybeNull
,NotNullWhen
,MaybeNullWhen
,DoesNotReturn
,DoesNotReturnIf
,NotNullWhenNotNull
, listed here with some details).As part of enhancements to nullability analysis for C# 9, some more attributes will be introduced. We're working documenting an explicit backlog, but we already know one of the top scenarios we're interested in addressing: dependent calls.
Let's start with two illustrations to motivate the problem:
The attribute definitions that were discussed in C# LDM are:
and
Note that unlike other nullability attributes, both of these new attributes allow multiple instances:
[MemberNotNull(nameof(field)), MemberNotNull(nameof(Property))]
is the same as[MemberNotNull(nameof(field), nameof(Property))]
.[MemberNotNullWhen(true, nameof(field1)), MemberNotNullWhen(false, nameof(field2))]
is also valid.LDM notes for 2/5/2020: https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-02-05.md#nullability
Note that some other scenarios were also discussed in that LDM (declaring that nested fields/properties of a parameter or return value are not-null after a method returns, possibly with a new overload of the
NotNullAttribute
andNotNullWhenAttribute
constructors), but we decided to reduce the scope.The text was updated successfully, but these errors were encountered: