louthy/language-ext · error · InvalidOperationException

Don't use Equals - use either RecordType

Error message

Don't use Equals - use either RecordType<A>.Equality or RecordType<A>.EqualityTyped

What it means

RecordType<A>.Equals(object, object) is explicitly obsoleted and unconditionally throws InvalidOperationException. Record equality in LanguageExt is performed via the Equality/EqualityTyped delegates, so this shadowed Object.Equals overload exists only to fail loudly at runtime (and warn at compile time via [Obsolete]).

Solutions

  1. Replace the call with RecordType<A>.Equality(objA, objB) for object-based comparison.
  2. Use RecordType<A>.EqualityTyped((A, A)) when both operands are statically typed as A.
  3. If flagged by the compiler as obsolete-warning-turned-error, fix the call site rather than suppressing the warning.

Example fix

// before
bool same = RecordType<MyRecord>.Equals(a, b); // throws

// after
bool same = RecordType<MyRecord>.Equality(a, b);
Defensive patterns

Strategy: type-guard

Type guard

static bool RecordsEqual<A>(A a, A b) where A : Record<A> => RecordType<A>.EqualityTyped(a, b);

Prevention

When it happens

Trigger: Calling RecordType<A>.Equals(objA, objB) directly, e.g. translating object.Equals(a, b) code to RecordType.Equals without switching to RecordType<A>.Equality(a, b).

Common situations: Refactoring from record class helpers to RecordType-based value objects; generic comparison helpers that call static Equals; code written against the base System.Object pattern.

Understand the failure class

Background: "is deprecated and will be removed" — deprecation warnings for old API names, keywords, and options, and how to migrate before the removal release — this error's family across 29 libraries.

Related errors


AI-assisted analysis of louthy/language-ext@2f0e362824 (2026-09-15). Data as JSON: /api/errors/6b9d41a6102b346f. Report an issue: GitHub.

Appendix: source

Thrown at LanguageExt.Core/DataTypes/Record/RecordType.cs:50

    /// <summary>
    /// General ToString function
    /// </summary>
    public new static Func<A, string> ToString => RecordTypeToString<A>.ToString;

    /// <summary>
    /// De-serialise an A
    /// </summary>
    public static Action<A, SerializationInfo> SetObjectData => RecordTypeSetObjectData<A>.SetObjectData;

    /// <summary>
    /// Serialise an A
    /// </summary>
    public static Action<A, SerializationInfo> GetObjectData => RecordTypeGetObjectData<A>.GetObjectData;

    [Obsolete("Don't use Equals - use either RecordType<A>.Equality or RecordType<A>.EqualityTyped")]
    public new static bool Equals(object objA, object objB) => 
        throw new InvalidOperationException("Don't use Equals - use either RecordType<A>.Equality or RecordType<A>.EqualityTyped");
}

internal static class RecordTypeIncludeBase<A>
{
    internal static readonly bool IncludeBase;
    
    static RecordTypeIncludeBase() =>
        IncludeBase = !typeof(A).CustomAttributes
                                .AsIterable() 
                                .Exists(a => a.AttributeType.Name == nameof(IgnoreBaseAttribute));
}

internal static class RecordTypeHash<A>
{
    internal static readonly Func<A, int> Hash;
    
    static RecordTypeHash() => 
        Hash = IL.GetHashCode<A>(RecordTypeIncludeBase<A>.IncludeBase);

View on GitHub (pinned to 2f0e362824)