Home > Mobile >  Why does MemberNotNull not work for override of properties?
Why does MemberNotNull not work for override of properties?

Time:04-17

The message warning CS8604: Possible null reference argument is issued on the call to Process(). A way to fix is to mark it with MemberNotNull.

If there is no override in the Derived class then MemberNotNull works as expected.

Why does the compiler still warn if an override exists?

What would be a better way to suppress this warning?

using System;
using System.Diagnostics.CodeAnalysis;

namespace Tests
{
    class Base
    {
        public virtual string? Member { get; set; }

        [MemberNotNull(nameof(Member))]
        public void Validate()
        {
            if (Member is null)
            {
                throw new Exception("Prop is null");
            }
        }
    }

    class Derived : Base
    {
        public override string? Member { get; set; } // warning CS8604: Possible null reference argument
    }

    [TestClass]
    public class MemberNotNullTests
    {
        static void Process(string s)
        {
            Console.WriteLine(s);
        }

        [TestMethod]
        public void TestMemberNotNull()
        {
            Derived instance = new();
            instance.Validate();
            Process(instance.Member);
        }
    }
}```

CodePudding user response:

(This answer is non-authoritative)

From what I can tell, this behaviour is likely by-design for now, apparently.

Here's some relevant sources:

This is indirectly mentioned in the LDM notes, but they don't explain why or how they came to that decision, but I assume because it would save time and result in predictable behaviour (or in this case... unexpected behaviour):

We propose that the lookup rules for resolving the names in these instances would be similar to the rules for the DefaultMemberAttribute.

Curiously, in the PR code-review notes the reverse scenario is discussed where MemberNotNull is used in a subclass to assert that non-overridden inherited members are not-null - but I can't find a mention of the obvious reversal of that, which is what we're concerned:

@jcouv 2022-02-25: Note that a type can only mark its own members as not-null, but not its base's.

CodePudding user response:

  1. Why you are using string?

  2. Why do you write validation inside the class that is going to be validated?

  3. Are you sure that the derived class should override property?

I could recommend having:

class Base
    {
      public virtual string Property {get;set;}
    }
    class Derived: Base
    {
      public override string Property {get;set;}
    }
    // can be as service
    public interface IValidator<T> where T: Base
    {
      public bool IsValid(T item);
    }
    
    class Validator : IValidator<T>
    {
      public bool IsValid(T obj) => string.IsNullOrEmpty(obj.Property);
    }

In tests:

        Derived instance = new();
        Validator validator = new();
        validator.Validate(instance);
        Process(instance.Member);
  • Related