Home > front end >  How can I write my IEqualityComparer without checking for nulls?
How can I write my IEqualityComparer without checking for nulls?

Time:11-17

I'm running my project in a nullable enabled context and I wish to simplify my code because it's internal and I KNOW that the references passed in are non-null. The IEqualityComparer interface gives warnings if I make the parameters not nullable.

class FileInfoComparer : IEqualityComparer<FileInfo>
{
    // Round up timestamp to the next 2 seconds
    const long interval = 20_000_000;
    DateTime RoundUp(DateTime time) => time.AddTicks(interval - (time.Ticks - 1) % interval - 1);

    public bool Equals(FileInfo? fi1, FileInfo? fi2)
    {
        return fi1.Name == fi2.Name &&
            RoundUp(fi1.LastWriteTime) == RoundUp(fi2.LastWriteTime) && fi1.Length == fi2.Length;
    }

    public int GetHashCode(FileInfo fi)
    {
        return HashCode.Combine(fi.Name, RoundUp(fi.LastWriteTime), fi.Length);
    }
}

As it stands I'm getting squigglies under various fi1 and fi2 references whenever I try to make them not nullable. I've tried adding various attributes like [NotNull] in places but nothing works. I've also tried writing like this:

return fi1?.Name == fi2?.Name &&
    RoundUp(fi1.LastWriteTime) == RoundUp(fi2.LastWriteTime) && i1.Length == fi2.Length;

but the squigglies just move somewhere else. Are there any Null attributes like [DisallowNull] etc. that I can add in the right places to remove the warnings?

CodePudding user response:

/// <remarks>
/// <see cref="Equals"/> rejects <see langword="null"/> values.
/// </remarks>
class FileInfoComparer : IEqualityComparer<FileInfo>
{
    // Other parts as before

    public bool Equals(FileInfo? fi1, FileInfo? fi2)
    {
        if (fi1 is null)
        {
            throw new ArgumentNullException(nameof(fi1));
        }

        if (fi2 is null)
        {
            throw new ArgumentNullException(nameof(fi2));
        }

        return fi1.Name == fi2.Name &&
            RoundUp(fi1.LastWriteTime) == RoundUp(fi2.LastWriteTime) && fi1.Length == fi2.Length;
    }

    // GetHashCode as before
}

It is possible to make the argument validation a single line if desired by turning it into a method that takes a parameter and throws if it is null.

Alternative using the null forgiving operator:

/// <remarks>
/// <see cref="Equals"/> rejects <see langword="null"/> values.
/// </remarks>
class FileInfoComparer : IEqualityComparer<FileInfo>
{
    // Other parts as before

    public bool Equals(FileInfo? fi1, FileInfo? fi2)
    {
        return fi1!.Name == fi2!.Name &&
            RoundUp(fi1.LastWriteTime) == RoundUp(fi2.LastWriteTime) && fi1.Length == fi2.Length;
    }

    // GetHashCode as before
}
  • Related