As slepic in his comment, I also wonder why you use and enumerator in the first and `foreach` in the second place?


----------
You can minimize the `null` checks in the versions that call other overrides:

>     public static int DistinctCount<TSource>(this IEnumerable<TSource> source) =>
>             source?.DistinctCount((IEqualityComparer<TSource>)null) ?? throw new ArgumentNullException(nameof(source));

can be reduced to:

    public static int DistinctCount<TSource>(this IEnumerable<TSource> source) => DistinctCount(source, (IEqualityComparer<TSource>)null);

And the other to:

    public static int DistinctCount<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate) => DistinctCount(source, predicate, null);


----------
You could create a common counter method as:


    private static int Count<TSource>(IEnumerable<TSource> source, Func<TSource, ISet<TSource>, bool> predicate, IEqualityComparer<TSource> comparer)
    {
      ISet<TSource> set = new HashSet<TSource>(comparer);
      int num = 0;

      using (IEnumerator<TSource> enumerator = source.GetEnumerator())
      {
        while (enumerator.MoveNext())
        {
          if (predicate(enumerator.Current, set))
          {
            checked
            {
              ++num;
            }
          }
        }
      }

      return num;
    }

Called in the first as:


    public static int DistinctCount<TSource>(this IEnumerable<TSource> source, IEqualityComparer<TSource> comparer)
    {
      if (source is null)
      {
        throw new ArgumentNullException(nameof(source));
      }

      return Count(source, (o, set) => set.Add(o), comparer);
    }

and in the latter as:

    public static int DistinctCount<TSource>(
        this IEnumerable<TSource> source,
        Func<TSource, bool> predicate,
        IEqualityComparer<TSource> comparer)
    {
      if (source is null)
      {
        throw new ArgumentNullException(nameof(source));
      }

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

      return Count(source, (o, set) => predicate(o) && set.Add(o), comparer);
    }