louthy/language-ext · error · InvalidOperationException
InvalidOperationException
Error message
InvalidOperationException
What it means
Resolver.GetHashCodeMethodAlways searches HashableResolve/EqResolve/OrdResolve for a usable GetHashCode MethodInfo and, when none of the resolvers report Exists, falls back to HashableResolve<T>.GetMethod("GetHashCode") and throws InvalidOperationException if that is also absent. It means the requested type has no Hashable/Eq/Ord instance registered, so a hash-code method is guaranteed unavailable.
Solutions
- Implement a Hashable<T> instance (or Eq<T>/Ord<T>) for the type in the same or a referenced assembly.
- Name the conventional resolver class correctly so Resolver.Find can locate it (prefix 'Hashable' + type name).
- Verify the assembly containing the instance is referenced and loadable.
- Check the nullable Resolver.GetHashCodeMethod first if your code can fall back to BCL GetHashCode instead.
Example fix
// before
var set = HashSet.create<Money>(...); // InvalidOperationException: no hashable instance
// after
public class MoneyHashable : Hashable<Money>
{
public override int GetHashCode(Money x) => x.Amount.GetHashCode() ^ x.Currency.GetHashCode();
public override bool Equals(Money x, Money y) => x.Amount == y.Amount && x.Currency == y.Currency;
} Defensive patterns
Strategy: fallback
Validate before calling
// pre-check before hashing API that uses 'Always' resolution
if (!HashableResolve<Money>.Exists && !EqResolve<Money>.Exists && !OrdResolve<Money>.Exists)
throw new InvalidOperationException($"No Hashable/Eq/Ord instance for Money"); Type guard
static bool HasHashableInstance<T>() => HashableResolve<T>.Exists || EqResolve<T>.Exists || OrdResolve<T>.Exists;
Try / catch
MethodInfo hashMethod;
try { hashMethod = Resolver.GetHashCodeMethodAlways(typeof(T)); }
catch (InvalidOperationException)
{
hashMethod = null; // fall back to EqualityComparer<T>.Default.GetHashCode
} Prevention
- Write a Hashable<T> instance for every type used as a key or in a set
- Follow the trait-instance naming convention exactly so Resolver.Find can locate it
- Ensure assemblies containing instances are referenced and loadable
- Prefer the nullable Resolver.GetHashCodeMethod when a fallback is acceptable
When it happens
Trigger: Calling APIs that require hashing (dictionaries, hash sets, Hashablerelude helpers) for a type T where HashableResolve<T>, EqResolve<T> and OrdResolve<T>.Exists are all false — i.e. no static Hashable<T>/Eq<T>/Ord<T> instance exists for T and no 'Hashable<T>'-named convention class was found.
Common situations: Forgetting to write a Hashable<T>/Eq<T> instance for a custom struct/class before using it as a key; type-named convention classes misspelled (resolver searches for 'HashableT'-style names via Resolver.Find); instances defined in an assembly that failed to load.
Related errors
- Ord attribute should have a struct type that derives from…
- InvalidOperationException
- InvalidOperationException
- InvalidOperationException
- Hashable attribute should have a struct type that derives…
AI-assisted analysis of louthy/language-ext@2f0e362824 (2026-09-15).
Data as JSON: /api/errors/083cb4628acfa83a.
Report an issue: GitHub.
Appendix: source
Thrown at LanguageExt.Core/Traits/Resolve/Resolver.cs:114
return null;
}
public static MethodInfo GetHashCodeMethodAlways(Type type)
{
Type[] traits = [typeof(HashableResolve<>), typeof(EqResolve<>), typeof(OrdResolve<>)];
foreach (var trait in traits)
{
var impl = trait.MakeGenericType(type);
var exists = (bool?)impl.GetProperty("Exists")?.GetValue(null) ?? false;
if (exists)
{
var method = impl.GetMethod("GetHashCode", BindingFlags.Static | BindingFlags.Public, [type]);
if (method is not null) return method;
}
}
var impl2 = typeof(HashableResolve<>).MakeGenericType(type);
return impl2.GetMethod("GetHashCode", BindingFlags.Static | BindingFlags.Public, [type]) ?? throw new InvalidOperationException();
}
public static MethodInfo? GetEqualsMethod(Type type)
{
Type[] traits = [typeof(EqResolve<>), typeof(OrdResolve<>)];
foreach (var trait in traits)
{
var impl = trait.MakeGenericType(type);
var exists = (bool?)impl.GetProperty("Exists")?.GetValue(null) ?? false;
if (exists)
{
var method = impl.GetMethod("Equals", BindingFlags.Static | BindingFlags.Public, [type, type]);
if (method is not null) return method;
}
}
return null;
}
View on GitHub (pinned to 2f0e362824)