简体   繁体   中英

Properly implementing IComparable<T> on a Struct in C# 8 with Nullable set to enable

What is now the proper way to implement CompareTo in C# 8 when Nullable is enabled. The implement interface feature in Visual Studio suggested this signature:

public struct PackageVersionNumber : IComparable<PackageVersionNumber>
{
    public int Major { get; }

    public int Minor { get; }

    public int Patch { get; }

    public int CompareTo([AllowNull] PackageVersionNumber other)
    {
        // ...
    }
}

PackageVersionNumber is a struct in this case and really shouldn't be null. Can I safely delete the [AllowNull] attribute from the argument or do I need to leave it there and really check for null. Or is this a bug?

TL;DR
You can safely remove this attribute from the method signature.

Explanation

In your CompareTo method signature, the struct is passed by-value and is not marked as nullable. This is the correct interface implementation for your PackageVersionNumber struct.

That means, the other argument value cannot be null no matter what you do.

You cannot even write if (other == null) - that will produce a compiler error (unless you overload the == operator for PackageVersionNumber what you should really consider for a struct, by the way).

But even with an overloaded == operator, the if (other == null) comparison will always yield false - so there is no need in that check. The overloaded operator will allow the compiler to implicitly cast PackageVersionNumber to nullable PackageVersionNumber? in the comparison - and you'll get a CS0472 warning:

The result of the expression is always 'false' since a value of type 'PackageVersionNumber' is never equal to 'null' of type 'PackageVersionNumber?'

I suppose that the "Implement interface" feature in Visual Studio doesn't consider the type on which the interface is implemented and always uses the same snippet with that AllowNullAttribute .

That attribute is indeed useful for implementing the interface for non-nullable reference types. While they are "logically" non-nullable, there is still a way to get a null value at runtime - so a null check is required to avoid a NullReferenceException . Furthermore, you have to ensure the backwards compatibility with assemblies compiled with C#7.x and below - IComparable<T> perfectly allows null for T s that are reference types.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM