Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Are there any public MemberNotNull/MemberNotNullWhen attributes in .net core

I have read the following article about nullable reference analysis in C# 8 not long ago: https://www.meziantou.net/csharp-8-nullable-reference-types.htm

The post-condition attributes are particularly interesting to me. Recently I have encountered a situation where it might be useful to apply MemberNotNull attribute. However, unexpectedly I can't find MemberNotNull and MemberNotNullWhen public attributes in the .Net core 3.1. However, I can see a number of internal attributes declared in .net core: https://source.dot.net/#q=MemberNotNull

Are there any substitutions in .net core for these attributes. Do I have to use .net 5 to use them?

like image 550
SENya Avatar asked Nov 23 '20 20:11

SENya


3 Answers

You can reference Nullable package. It will do basically the same as you did with copy-paste. Think that's the best way to backport these attributes to pre .net50 sdks.

like image 136
unsafePtr Avatar answered Oct 25 '22 15:10

unsafePtr


I tried to copy declarations of both attributes to my source code but it didn't help when I declared attributes in my custom namespace. However if I declare them in System.Diagnostics.CodeAnalysis namespace like this then it works:

namespace System.Diagnostics.CodeAnalysis
{
    [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)]
    public sealed class MemberNotNullWhenAttribute : Attribute
    {
        /// <summary>Initializes the attribute with the specified return value condition and a field or property member.</summary>
        /// <param name="returnValue">
        /// The return value condition. If the method returns this value, the associated parameter will not be null.
        /// </param>
        /// <param name="member">
        /// The field or property member that is promised to be not-null.
        /// </param>
        public MemberNotNullWhenAttribute(bool returnValue, string member)
        {
            ReturnValue = returnValue;
            Members = new[] { member };
        }

        /// <summary>Initializes the attribute with the specified return value condition and list of field and property members.</summary>
        /// <param name="returnValue">
        /// The return value condition. If the method returns this value, the associated parameter will not be null.
        /// </param>
        /// <param name="members">
        /// The list of field and property members that are promised to be not-null.
        /// </param>
        public MemberNotNullWhenAttribute(bool returnValue, params string[] members)
        {
            ReturnValue = returnValue;
            Members = members;
        }

        /// <summary>Gets the return value condition.</summary>
        public bool ReturnValue { get; }

        /// <summary>Gets field or property member names.</summary>
        public string[] Members { get; }
    }
}

And Roslyn removes the displayed warning for possible null dereference. However, instead I receive the following error:

Error CS8652: The feature 'MemberNotNull attribute' is currently in Preview and unsupported. To use Preview features, use the 'preview' language version.

So it seems I can at least switch to the preview language version with this approach. But I would like to avoid such hacks, so if there is a better solution please provide it and I will mark it as an accepted answer.

EDIT: To avoid some confusion expressed in the comments - this answer allows to use MemberNotNullWhen attribute without compile time error. Just add

  <LangVersion>preview</LangVersion>

to your project file.

like image 2
SENya Avatar answered Oct 25 '22 15:10

SENya


If you do not want to upgrade your framework version, or backport support for [MemberNotNull] from .NET 5, you can instead initialize the relevant fields using the null forgiving operator as a workaround.

For example, if you have a non-nullable field _myField that is initialized in the method Init(), you can add write the following in your constructor to remove the warning about a non-null value when exiting the constructor.

_myField = null!;
InitFields();
like image 2
mark.monteiro Avatar answered Oct 25 '22 16:10

mark.monteiro