Finalizer<T> class Null safety

A finalizer which can be attached to Dart objects.

A finalizer can create attachments between the finalizer and any number of Dart values, by calling attach with the value, along with a finalization token and an optional attach key, which are part of the attachment.

When a Dart value becomes inaccessible to the program, any finalizer that currently has an attachment to the value may have its callback function called with the attachment's finalization token.

Example:

// Keep the finalizer itself reachable, otherwise might not do anything.
final Finalizer<DBConnection> _finalizer = Finalizer((connection) {
  connection.close();
});

/// Access the database.
Database connect() {
  // Wraps the connection in a nicer user-facing API,
  // *and* closes connection if the user forgets to.
  var connection = _connectToDatabase();
  var wrapper = Database._fromConnection(connection, _finalizer);
  // Get finalizer callback when `wrapper` is no longer reachable.
  _finalizer.attach(wrapper, connection, detach: wrapper);
  return wrapper;
}

class Database {
  final DBConnection _connection;
  final Finalizer<Connection> _finalizer;
  Database._fromConnection(this._connection, this._finalizer);

  // Some useful methods.

  void close() {
    // User requested close.
    _connection.close();
    // Detach from finalizer, no longer needed.
    _finalizer.detach(this);
  }
}

This example has an example of an external resource that needs clean-up. The finalizer is used to clean up an external connection when the user of the API no longer has access to that connection. The example uses the same object as attached object and detach key, which is a useful approach when each attached object can be detached individually. Being a detachment key doesn't keep an object alive.

No promises are made that the callback will ever be called. The only thing that is guaranteed is that if a finalizer's callback is called with a specific finalization token as argument, then at least one value with an attachment to to the finalizer that has that finalization token, is no longer accessible to the program.

If the finalzier itself becomes unreachable, it's allowed to be garbage collected and then it won't trigger any further callbacks. Always make sure to keep the finalizer itself reachable while it's needed.

If multiple finalizers are attached to a single object, or the same finalizer is attached multiple times to an object, and that object becomes inaccessible to the program, then any number (including zero) of those attachments may trigger their associated finalizer's callback. It will not necessarily be all or none of them.

Finalization callbacks will happen as events. They will not happen during execution of other code, and not as a microtask, but as high-level events similar to timer events.

Finalization callbacks must not throw.

Annotations
  • @Since("2.17")

Constructors

Finalizer(void callback(T))
Creates a finalizer with the given finalization callback. [...]
factory

Properties

hashCode int
The hash code for this object. [...]
read-only, inherited
runtimeType Type
A representation of the runtime type of the object.
read-only, inherited

Methods

attach(Object value, T finalizationToken, {Object? detach}) → void
Attaches this finalizer to value. [...]
detach(Object detach) → void
Detaches this finalizer from values attached with detach. [...]
noSuchMethod(Invocation invocation) → dynamic
Invoked when a non-existent method or property is accessed. [...]
inherited
toString() String
A string representation of this object. [...]
inherited

Operators

operator ==(Object other) bool
The equality operator. [...]
inherited