Skip to content

Allow type formatters to match by interface, base class, and generic type definition (fixes #644) - #680

Open
NoTh0ughts wants to merge 1 commit into
allure-framework:mainfrom
NoTh0ughts:feature/hierarchical-type-formatters
Open

Allow type formatters to match by interface, base class, and generic type definition (fixes #644)#680
NoTh0ughts wants to merge 1 commit into
allure-framework:mainfrom
NoTh0ughts:feature/hierarchical-type-formatters

Conversation

@NoTh0ughts

Copy link
Copy Markdown

Context

Fixes #644.

AddTypeFormatter/TypeFormatter<T> only matched a value if its exact
runtime type was registered (value.GetType() == typeof(T)). That made it
impossible to reuse one formatter for an interface, a base class, or an
open generic type definition (e.g. List<>), and made it hard to format
3rd-party types that are inaccessible at compile time but implement a
public interface.

What changed

  • Formatter resolution now falls back, in order, to: the exact type → its
    generic type definition → the interfaces it implements → their generic
    definitions → its base classes → their generic definitions. Resolved
    lookups are cached per runtime type and invalidated on new registrations
    (HierarchicalTypeFormatterLookup).
  • Added AllureLifecycle.AddTypeFormatter(Type, ITypeFormatter) to register
    a formatter for an open generic type definition (typeof(List<>)), which
    can't be expressed as a type argument to AddTypeFormatter<T>.
  • AllureLifecycle.TypeFormatters keeps its IReadOnlyDictionary<Type, ITypeFormatter> shape, so no existing call sites needed to change.

Checklist

  • Sign Allure CLA
  • Provide unit tests

@CLAassistant

CLAassistant commented Jul 27, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@NoTh0ughts
NoTh0ughts force-pushed the feature/hierarchical-type-formatters branch from bd1b789 to ddff637 Compare July 27, 2026 15:04
…type definition

Previously, AddTypeFormatter/TypeFormatter<T> only matched a value if its
exact runtime type was registered, which made it impossible to reuse a
formatter for an interface, a base class, or an open generic type
definition (e.g. List<>). Resolution now falls back, in order, to the
generic type definition, the implemented interfaces (and their generic
definitions), and the base classes (and their generic definitions), with
resolved lookups cached per runtime type.

A new AddTypeFormatter(Type, ITypeFormatter) overload lets a formatter be
registered for an open generic type definition, which can't be expressed
as a type argument to AddTypeFormatter<T>.

Fixes allure-framework#644
@NoTh0ughts
NoTh0ughts force-pushed the feature/hierarchical-type-formatters branch from ddff637 to c3118ab Compare July 27, 2026 15:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Allow an argument to match a type formatter by its interface/base class/generic definition

2 participants